xref: /PHP-7.4/Zend/zend_virtual_cwd.c (revision 99a20856)
1daf926cfSAndi Gutmans /*
2daf926cfSAndi Gutmans    +----------------------------------------------------------------------+
3d0cb7153SJohannes Schlüter    | PHP Version 7                                                        |
4daf926cfSAndi Gutmans    +----------------------------------------------------------------------+
50cf7de1cSZeev Suraski    | Copyright (c) The PHP Group                                          |
6daf926cfSAndi Gutmans    +----------------------------------------------------------------------+
75bd93221Sfoobar    | This source file is subject to version 3.01 of the PHP license,      |
8daf926cfSAndi Gutmans    | that is bundled with this package in the file LICENSE, and is        |
960ffd0eaSSebastian Bergmann    | available through the world-wide-web at the following url:           |
105bd93221Sfoobar    | http://www.php.net/license/3_01.txt                                  |
11daf926cfSAndi Gutmans    | If you did not receive a copy of the PHP license and are unable to   |
12daf926cfSAndi Gutmans    | obtain it through the world-wide-web, please send a note to          |
13daf926cfSAndi Gutmans    | license@php.net so we can mail you a copy immediately.               |
14daf926cfSAndi Gutmans    +----------------------------------------------------------------------+
1554dc07f3SZeev Suraski    | Authors: Andi Gutmans <andi@php.net>                                 |
16daf926cfSAndi Gutmans    |          Sascha Schumann <sascha@schumann.cx>                        |
17dec8593fSPierre Joye    |          Pierre Joye <pierre@php.net>                                |
18daf926cfSAndi Gutmans    +----------------------------------------------------------------------+
19daf926cfSAndi Gutmans */
20daf926cfSAndi Gutmans 
21daf926cfSAndi Gutmans #include <sys/types.h>
22daf926cfSAndi Gutmans #include <sys/stat.h>
23daf926cfSAndi Gutmans #include <string.h>
24daf926cfSAndi Gutmans #include <stdio.h>
25daf926cfSAndi Gutmans #include <limits.h>
26daf926cfSAndi Gutmans #include <errno.h>
27daf926cfSAndi Gutmans #include <stdlib.h>
28daf926cfSAndi Gutmans #include <fcntl.h>
291594170fSIlia Alshanetsky #include <time.h>
30daf926cfSAndi Gutmans 
31cf6ab0e9SAnatol Belski #include "zend.h"
32e30b2aaeSAnatol Belski #include "zend_virtual_cwd.h"
3303432bf6SAndi Gutmans 
34ce2cd892SKalle Sommer Nielsen #ifdef ZEND_WIN32
3503432bf6SAndi Gutmans #include <io.h>
361b279d34SDaniel Beulshausen #include "tsrm_win32.h"
372e08b57eSPierre Joye # ifndef IO_REPARSE_TAG_SYMLINK
382e08b57eSPierre Joye #  define IO_REPARSE_TAG_SYMLINK 0xA000000C
392e08b57eSPierre Joye # endif
40c4334c7cSPierre Joye 
41a2e4404bSAnatoliy Belsky # ifndef IO_REPARSE_TAG_DEDUP
42a2e4404bSAnatoliy Belsky #  define IO_REPARSE_TAG_DEDUP   0x80000013
43a2e4404bSAnatoliy Belsky # endif
44a2e4404bSAnatoliy Belsky 
45c6720e2fSAnatol Belski # ifndef IO_REPARSE_TAG_CLOUD
46c6720e2fSAnatol Belski #  define IO_REPARSE_TAG_CLOUD    (0x9000001AL)
47c6720e2fSAnatol Belski # endif
48c6720e2fSAnatol Belski /* IO_REPARSE_TAG_CLOUD_1 through IO_REPARSE_TAG_CLOUD_F have values of 0x9000101AL
49c6720e2fSAnatol Belski    to 0x9000F01AL, they can be checked against the mask. */
50c6720e2fSAnatol Belski #ifndef IO_REPARSE_TAG_CLOUD_MASK
51c6720e2fSAnatol Belski #define IO_REPARSE_TAG_CLOUD_MASK (0x0000F000L)
52c6720e2fSAnatol Belski #endif
53c6720e2fSAnatol Belski 
54c6720e2fSAnatol Belski #ifndef IO_REPARSE_TAG_ONEDRIVE
55c6720e2fSAnatol Belski #define IO_REPARSE_TAG_ONEDRIVE   (0x80000021L)
56c6720e2fSAnatol Belski #endif
57c6720e2fSAnatol Belski 
5829968d8fSChristoph M. Becker # ifndef IO_REPARSE_TAG_ACTIVISION_HSM
5929968d8fSChristoph M. Becker #  define IO_REPARSE_TAG_ACTIVISION_HSM (0x00000047L)
6029968d8fSChristoph M. Becker # endif
6129968d8fSChristoph M. Becker 
6229968d8fSChristoph M. Becker # ifndef IO_REPARSE_TAG_PROJFS
6329968d8fSChristoph M. Becker #  define IO_REPARSE_TAG_PROJFS (0x9000001CL)
6429968d8fSChristoph M. Becker # endif
6529968d8fSChristoph M. Becker 
66c4334c7cSPierre Joye # ifndef VOLUME_NAME_NT
67c4334c7cSPierre Joye #  define VOLUME_NAME_NT 0x2
68c4334c7cSPierre Joye # endif
69c4334c7cSPierre Joye 
70c4334c7cSPierre Joye # ifndef VOLUME_NAME_DOS
71c4334c7cSPierre Joye #  define VOLUME_NAME_DOS 0x0
72c4334c7cSPierre Joye # endif
73e42e8b10SAnatol Belski 
74e42e8b10SAnatol Belski # include <winioctl.h>
75e42e8b10SAnatol Belski # include <winnt.h>
76daf926cfSAndi Gutmans #endif
77daf926cfSAndi Gutmans 
7878e2e69bSIlia Alshanetsky #ifndef HAVE_REALPATH
792a0fbdedSDavid Reid #define realpath(x,y) strcpy(y,x)
802a0fbdedSDavid Reid #endif
812a0fbdedSDavid Reid 
82daf926cfSAndi Gutmans #define VIRTUAL_CWD_DEBUG 0
83daf926cfSAndi Gutmans 
84daf926cfSAndi Gutmans #include "TSRM.h"
85daf926cfSAndi Gutmans 
862104bea5SKalle Sommer Nielsen /* Only need mutex for popen() in Windows because it doesn't chdir() on UNIX */
872104bea5SKalle Sommer Nielsen #if defined(ZEND_WIN32) && defined(ZTS)
88daf926cfSAndi Gutmans MUTEX_T cwd_mutex;
89daf926cfSAndi Gutmans #endif
90daf926cfSAndi Gutmans 
91daf926cfSAndi Gutmans #ifdef ZTS
92216853c0SAndi Gutmans ts_rsrc_id cwd_globals_id;
939499484eSDmitry Stogov size_t     cwd_globals_offset;
94daf926cfSAndi Gutmans #else
95216853c0SAndi Gutmans virtual_cwd_globals cwd_globals;
96daf926cfSAndi Gutmans #endif
97daf926cfSAndi Gutmans 
98397d40cdSAnatol Belski static cwd_state main_cwd_state; /* True global */
99daf926cfSAndi Gutmans 
100ce2cd892SKalle Sommer Nielsen #ifndef ZEND_WIN32
101daf926cfSAndi Gutmans #include <unistd.h>
102daf926cfSAndi Gutmans #else
103daf926cfSAndi Gutmans #include <direct.h>
10481f52158SChristoph M. Becker #include "zend_globals.h"
10581f52158SChristoph M. Becker #include "zend_globals_macros.h"
106daf926cfSAndi Gutmans #endif
107daf926cfSAndi Gutmans 
108daf926cfSAndi Gutmans #define CWD_STATE_COPY(d, s)				\
109daf926cfSAndi Gutmans 	(d)->cwd_length = (s)->cwd_length;		\
110cf6ab0e9SAnatol Belski 	(d)->cwd = (char *) emalloc((s)->cwd_length+1);	\
111daf926cfSAndi Gutmans 	memcpy((d)->cwd, (s)->cwd, (s)->cwd_length+1);
112daf926cfSAndi Gutmans 
113daf926cfSAndi Gutmans #define CWD_STATE_FREE(s)			\
1146679df14SAnatol Belski 	efree((s)->cwd); \
1156679df14SAnatol Belski 	(s)->cwd_length = 0;
116ae504412SPierre Joye 
117ce2cd892SKalle Sommer Nielsen #ifdef ZEND_WIN32
118abb962d5SAnatol Belski # define CWD_STATE_FREE_ERR(state) do { \
119abb962d5SAnatol Belski 		DWORD last_error = GetLastError(); \
120abb962d5SAnatol Belski 		CWD_STATE_FREE(state); \
121abb962d5SAnatol Belski 		SetLastError(last_error); \
122abb962d5SAnatol Belski 	} while (0)
123abb962d5SAnatol Belski #else
124abb962d5SAnatol Belski # define CWD_STATE_FREE_ERR(state) CWD_STATE_FREE(state)
125abb962d5SAnatol Belski #endif
126abb962d5SAnatol Belski 
php_is_dir_ok(const cwd_state * state)12738b7d577SAntony Dovgal static int php_is_dir_ok(const cwd_state *state)  /* {{{ */
128daf926cfSAndi Gutmans {
1298ee2a4a9SAnatol Belski 	zend_stat_t buf;
130daf926cfSAndi Gutmans 
131ce958edeSDmitry Stogov 	if (php_sys_stat(state->cwd, &buf) == 0 && S_ISDIR(buf.st_mode))
132daf926cfSAndi Gutmans 		return (0);
133daf926cfSAndi Gutmans 
134daf926cfSAndi Gutmans 	return (1);
135daf926cfSAndi Gutmans }
13638b7d577SAntony Dovgal /* }}} */
137daf926cfSAndi Gutmans 
php_is_file_ok(const cwd_state * state)13838b7d577SAntony Dovgal static int php_is_file_ok(const cwd_state *state)  /* {{{ */
139daf926cfSAndi Gutmans {
1408ee2a4a9SAnatol Belski 	zend_stat_t buf;
141daf926cfSAndi Gutmans 
142ce958edeSDmitry Stogov 	if (php_sys_stat(state->cwd, &buf) == 0 && S_ISREG(buf.st_mode))
143daf926cfSAndi Gutmans 		return (0);
144daf926cfSAndi Gutmans 
145daf926cfSAndi Gutmans 	return (1);
146daf926cfSAndi Gutmans }
14738b7d577SAntony Dovgal /* }}} */
148daf926cfSAndi Gutmans 
cwd_globals_ctor(virtual_cwd_globals * cwd_g)149bdeb220fSAnatol Belski static void cwd_globals_ctor(virtual_cwd_globals *cwd_g) /* {{{ */
150daf926cfSAndi Gutmans {
151dd73c48dSAntony Dovgal 	CWD_STATE_COPY(&cwd_g->cwd, &main_cwd_state);
152dd73c48dSAntony Dovgal 	cwd_g->realpath_cache_size = 0;
153dd73c48dSAntony Dovgal 	cwd_g->realpath_cache_size_limit = REALPATH_CACHE_SIZE;
154dd73c48dSAntony Dovgal 	cwd_g->realpath_cache_ttl = REALPATH_CACHE_TTL;
155dd73c48dSAntony Dovgal 	memset(cwd_g->realpath_cache, 0, sizeof(cwd_g->realpath_cache));
156daf926cfSAndi Gutmans }
15738b7d577SAntony Dovgal /* }}} */
158daf926cfSAndi Gutmans 
realpath_cache_clean_helper(uint32_t max_entries,realpath_cache_bucket ** cache,zend_long * cache_size)159*99a20856SDimitry Andric static void realpath_cache_clean_helper(uint32_t max_entries, realpath_cache_bucket **cache, zend_long *cache_size)
160*99a20856SDimitry Andric {
161*99a20856SDimitry Andric 	uint32_t i;
162*99a20856SDimitry Andric 
163*99a20856SDimitry Andric 	for (i = 0; i < max_entries; i++) {
164*99a20856SDimitry Andric 		realpath_cache_bucket *p = cache[i];
165*99a20856SDimitry Andric 		while (p != NULL) {
166*99a20856SDimitry Andric 			realpath_cache_bucket *r = p;
167*99a20856SDimitry Andric 			p = p->next;
168*99a20856SDimitry Andric 			free(r);
169*99a20856SDimitry Andric 		}
170*99a20856SDimitry Andric 		cache[i] = NULL;
171*99a20856SDimitry Andric 	}
172*99a20856SDimitry Andric 	*cache_size = 0;
173*99a20856SDimitry Andric }
174*99a20856SDimitry Andric 
cwd_globals_dtor(virtual_cwd_globals * cwd_g)175bdeb220fSAnatol Belski static void cwd_globals_dtor(virtual_cwd_globals *cwd_g) /* {{{ */
176daf926cfSAndi Gutmans {
177*99a20856SDimitry Andric 	realpath_cache_clean_helper(sizeof(cwd_g->realpath_cache)/sizeof(cwd_g->realpath_cache[0]), cwd_g->realpath_cache, &cwd_g->realpath_cache_size);
178daf926cfSAndi Gutmans }
17938b7d577SAntony Dovgal /* }}} */
180daf926cfSAndi Gutmans 
virtual_cwd_main_cwd_init(uint8_t reinit)1813069ad8dSAnatol Belski void virtual_cwd_main_cwd_init(uint8_t reinit) /* {{{ */
182daf926cfSAndi Gutmans {
183daf926cfSAndi Gutmans 	char cwd[MAXPATHLEN];
184daf926cfSAndi Gutmans 	char *result;
185daf926cfSAndi Gutmans 
1863069ad8dSAnatol Belski 	if (reinit) {
1873069ad8dSAnatol Belski 		free(main_cwd_state.cwd);
1883069ad8dSAnatol Belski 	}
1892104bea5SKalle Sommer Nielsen 
190dea14fc7SAnatol Belski #ifdef ZEND_WIN32
191dea14fc7SAnatol Belski 	ZeroMemory(&cwd, sizeof(cwd));
1923069ad8dSAnatol Belski 	result = php_win32_ioutil_getcwd(cwd, sizeof(cwd));
1933069ad8dSAnatol Belski #else
194ae504412SPierre Joye 	result = getcwd(cwd, sizeof(cwd));
19595880365SAnantha Kesari H Y #endif
1962104bea5SKalle Sommer Nielsen 
197daf926cfSAndi Gutmans 	if (!result) {
198daf926cfSAndi Gutmans 		cwd[0] = '\0';
199daf926cfSAndi Gutmans 	}
2004ccb9037SDmitry Stogov 
20149d9b301SAnatol Belski 	main_cwd_state.cwd_length = strlen(cwd);
202ce2cd892SKalle Sommer Nielsen #ifdef ZEND_WIN32
2034ccb9037SDmitry Stogov 	if (main_cwd_state.cwd_length >= 2 && cwd[1] == ':') {
2044ccb9037SDmitry Stogov 		cwd[0] = toupper(cwd[0]);
2054ccb9037SDmitry Stogov 	}
2064ccb9037SDmitry Stogov #endif
2074ccb9037SDmitry Stogov 	main_cwd_state.cwd = strdup(cwd);
2083069ad8dSAnatol Belski }
2093069ad8dSAnatol Belski /* }}} */
210daf926cfSAndi Gutmans 
virtual_cwd_startup(void)2113069ad8dSAnatol Belski CWD_API void virtual_cwd_startup(void) /* {{{ */
2123069ad8dSAnatol Belski {
2133069ad8dSAnatol Belski 	virtual_cwd_main_cwd_init(0);
214daf926cfSAndi Gutmans #ifdef ZTS
2159499484eSDmitry Stogov 	ts_allocate_fast_id(&cwd_globals_id, &cwd_globals_offset, sizeof(virtual_cwd_globals), (ts_allocate_ctor) cwd_globals_ctor, (ts_allocate_dtor) cwd_globals_dtor);
216daf926cfSAndi Gutmans #else
217bdeb220fSAnatol Belski 	cwd_globals_ctor(&cwd_globals);
218daf926cfSAndi Gutmans #endif
219daf926cfSAndi Gutmans 
2202104bea5SKalle Sommer Nielsen #if (defined(ZEND_WIN32)) && defined(ZTS)
221daf926cfSAndi Gutmans 	cwd_mutex = tsrm_mutex_alloc();
222daf926cfSAndi Gutmans #endif
223daf926cfSAndi Gutmans }
22438b7d577SAntony Dovgal /* }}} */
225daf926cfSAndi Gutmans 
virtual_cwd_shutdown(void)22638b7d577SAntony Dovgal CWD_API void virtual_cwd_shutdown(void) /* {{{ */
227daf926cfSAndi Gutmans {
228daf926cfSAndi Gutmans #ifndef ZTS
229bdeb220fSAnatol Belski 	cwd_globals_dtor(&cwd_globals);
230daf926cfSAndi Gutmans #endif
2312104bea5SKalle Sommer Nielsen #if (defined(ZEND_WIN32)) && defined(ZTS)
232daf926cfSAndi Gutmans 	tsrm_mutex_free(cwd_mutex);
233daf926cfSAndi Gutmans #endif
234daf926cfSAndi Gutmans 
235daf926cfSAndi Gutmans 	free(main_cwd_state.cwd); /* Don't use CWD_STATE_FREE because the non global states will probably use emalloc()/efree() */
236daf926cfSAndi Gutmans }
23738b7d577SAntony Dovgal /* }}} */
238daf926cfSAndi Gutmans 
virtual_cwd_activate(void)239bdeb220fSAnatol Belski CWD_API int virtual_cwd_activate(void) /* {{{ */
240cf6ab0e9SAnatol Belski {
241cf6ab0e9SAnatol Belski 	if (CWDG(cwd).cwd == NULL) {
242cf6ab0e9SAnatol Belski 		CWD_STATE_COPY(&CWDG(cwd), &main_cwd_state);
243cf6ab0e9SAnatol Belski 	}
244cf6ab0e9SAnatol Belski 	return 0;
245cf6ab0e9SAnatol Belski }
246cf6ab0e9SAnatol Belski /* }}} */
247cf6ab0e9SAnatol Belski 
virtual_cwd_deactivate(void)248bdeb220fSAnatol Belski CWD_API int virtual_cwd_deactivate(void) /* {{{ */
249cf6ab0e9SAnatol Belski {
250cf6ab0e9SAnatol Belski 	if (CWDG(cwd).cwd != NULL) {
251cf6ab0e9SAnatol Belski 		CWD_STATE_FREE(&CWDG(cwd));
2524d430ecbSAnatol Belski 		CWDG(cwd).cwd = NULL;
253cf6ab0e9SAnatol Belski 	}
254cf6ab0e9SAnatol Belski 	return 0;
255cf6ab0e9SAnatol Belski }
256cf6ab0e9SAnatol Belski /* }}} */
257cf6ab0e9SAnatol Belski 
virtual_getcwd_ex(size_t * length)258bdeb220fSAnatol Belski CWD_API char *virtual_getcwd_ex(size_t *length) /* {{{ */
259daf926cfSAndi Gutmans {
260daf926cfSAndi Gutmans 	cwd_state *state;
261daf926cfSAndi Gutmans 
262daf926cfSAndi Gutmans 	state = &CWDG(cwd);
263daf926cfSAndi Gutmans 
264daf926cfSAndi Gutmans 	if (state->cwd_length == 0) {
265daf926cfSAndi Gutmans 		char *retval;
266daf926cfSAndi Gutmans 
267daf926cfSAndi Gutmans 		*length = 1;
268cf6ab0e9SAnatol Belski 		retval = (char *) emalloc(2);
269daf926cfSAndi Gutmans 		retval[0] = DEFAULT_SLASH;
270ae504412SPierre Joye 		retval[1] = '\0';
271daf926cfSAndi Gutmans 		return retval;
272daf926cfSAndi Gutmans 	}
273daf926cfSAndi Gutmans 
274ce2cd892SKalle Sommer Nielsen #ifdef ZEND_WIN32
275daf926cfSAndi Gutmans 	/* If we have something like C: */
276daf926cfSAndi Gutmans 	if (state->cwd_length == 2 && state->cwd[state->cwd_length-1] == ':') {
277daf926cfSAndi Gutmans 		char *retval;
278daf926cfSAndi Gutmans 
279daf926cfSAndi Gutmans 		*length = state->cwd_length+1;
280cf6ab0e9SAnatol Belski 		retval = (char *) emalloc(*length+1);
281daf926cfSAndi Gutmans 		memcpy(retval, state->cwd, *length);
2824ccb9037SDmitry Stogov 		retval[0] = toupper(retval[0]);
283daf926cfSAndi Gutmans 		retval[*length-1] = DEFAULT_SLASH;
284daf926cfSAndi Gutmans 		retval[*length] = '\0';
285daf926cfSAndi Gutmans 		return retval;
286daf926cfSAndi Gutmans 	}
287daf926cfSAndi Gutmans #endif
2886084844fSAnatol Belski 	if (!state->cwd) {
2896084844fSAnatol Belski 		*length = 0;
2906084844fSAnatol Belski 		return NULL;
2916084844fSAnatol Belski 	}
2926084844fSAnatol Belski 
293daf926cfSAndi Gutmans 	*length = state->cwd_length;
294cf6ab0e9SAnatol Belski 	return estrdup(state->cwd);
295daf926cfSAndi Gutmans }
29638b7d577SAntony Dovgal /* }}} */
297daf926cfSAndi Gutmans 
298daf926cfSAndi Gutmans /* Same semantics as UNIX getcwd() */
virtual_getcwd(char * buf,size_t size)299bdeb220fSAnatol Belski CWD_API char *virtual_getcwd(char *buf, size_t size) /* {{{ */
300daf926cfSAndi Gutmans {
301daf926cfSAndi Gutmans 	size_t length;
302daf926cfSAndi Gutmans 	char *cwd;
303daf926cfSAndi Gutmans 
304bdeb220fSAnatol Belski 	cwd = virtual_getcwd_ex(&length);
305daf926cfSAndi Gutmans 
306daf926cfSAndi Gutmans 	if (buf == NULL) {
307daf926cfSAndi Gutmans 		return cwd;
308daf926cfSAndi Gutmans 	}
309daf926cfSAndi Gutmans 	if (length > size-1) {
310cf6ab0e9SAnatol Belski 		efree(cwd);
311daf926cfSAndi Gutmans 		errno = ERANGE; /* Is this OK? */
312daf926cfSAndi Gutmans 		return NULL;
313daf926cfSAndi Gutmans 	}
3146084844fSAnatol Belski 	if (!cwd) {
3156084844fSAnatol Belski 		return NULL;
3166084844fSAnatol Belski 	}
317daf926cfSAndi Gutmans 	memcpy(buf, cwd, length+1);
318cf6ab0e9SAnatol Belski 	efree(cwd);
319daf926cfSAndi Gutmans 	return buf;
320daf926cfSAndi Gutmans }
32138b7d577SAntony Dovgal /* }}} */
322daf926cfSAndi Gutmans 
323ce2cd892SKalle Sommer Nielsen #ifdef ZEND_WIN32
realpath_cache_key(const char * path,size_t path_len)324758af77eSAnatol Belski static inline zend_ulong realpath_cache_key(const char *path, size_t path_len) /* {{{ */
3250304ec79SPierre Joye {
326c3e3c98eSAnatol Belski 	register zend_ulong h;
32724ae8810SAnatol Belski 	size_t bucket_key_len;
32824ae8810SAnatol Belski 	char *bucket_key_start = tsrm_win32_get_path_sid_key(path, path_len, &bucket_key_len);
329b37f2257SPierre Joye 	char *bucket_key = (char *)bucket_key_start;
3307d5f71b0SXinchen Hui 	const char *e;
3310304ec79SPierre Joye 
3320304ec79SPierre Joye 	if (!bucket_key) {
3330304ec79SPierre Joye 		return 0;
3340304ec79SPierre Joye 	}
3350304ec79SPierre Joye 
33624ae8810SAnatol Belski 	e = bucket_key + bucket_key_len;
337455741fcSAnatol Belski 	for (h = Z_UL(2166136261); bucket_key < e;) {
338455741fcSAnatol Belski 		h *= Z_UL(16777619);
3390304ec79SPierre Joye 		h ^= *bucket_key++;
3400304ec79SPierre Joye 	}
3416a010ad4SAnatol Belski 	if (bucket_key_start != path) {
3426a010ad4SAnatol Belski 		HeapFree(GetProcessHeap(), 0, (LPVOID)bucket_key_start);
3436a010ad4SAnatol Belski 	}
3440304ec79SPierre Joye 	return h;
3450304ec79SPierre Joye }
3460304ec79SPierre Joye /* }}} */
3470304ec79SPierre Joye #else
realpath_cache_key(const char * path,size_t path_len)348758af77eSAnatol Belski static inline zend_ulong realpath_cache_key(const char *path, size_t path_len) /* {{{ */
349216853c0SAndi Gutmans {
350c3e3c98eSAnatol Belski 	register zend_ulong h;
351a719e16fSIlia Alshanetsky 	const char *e = path + path_len;
352a719e16fSIlia Alshanetsky 
353455741fcSAnatol Belski 	for (h = Z_UL(2166136261); path < e;) {
354455741fcSAnatol Belski 		h *= Z_UL(16777619);
355a719e16fSIlia Alshanetsky 		h ^= *path++;
356a719e16fSIlia Alshanetsky 	}
357a719e16fSIlia Alshanetsky 
358a719e16fSIlia Alshanetsky 	return h;
359216853c0SAndi Gutmans }
36038b7d577SAntony Dovgal /* }}} */
361ce2cd892SKalle Sommer Nielsen #endif /* defined(ZEND_WIN32) */
362216853c0SAndi Gutmans 
realpath_cache_clean(void)363bdeb220fSAnatol Belski CWD_API void realpath_cache_clean(void) /* {{{ */
364933c26deSDmitry Stogov {
365*99a20856SDimitry Andric 	realpath_cache_clean_helper(sizeof(CWDG(realpath_cache))/sizeof(CWDG(realpath_cache)[0]), CWDG(realpath_cache), &CWDG(realpath_cache_size));
366933c26deSDmitry Stogov }
36738b7d577SAntony Dovgal /* }}} */
368933c26deSDmitry Stogov 
realpath_cache_del(const char * path,size_t path_len)369758af77eSAnatol Belski CWD_API void realpath_cache_del(const char *path, size_t path_len) /* {{{ */
370933c26deSDmitry Stogov {
371bdeb220fSAnatol Belski 	zend_ulong key = realpath_cache_key(path, path_len);
372c3e3c98eSAnatol Belski 	zend_ulong n = key % (sizeof(CWDG(realpath_cache)) / sizeof(CWDG(realpath_cache)[0]));
373933c26deSDmitry Stogov 	realpath_cache_bucket **bucket = &CWDG(realpath_cache)[n];
374933c26deSDmitry Stogov 
375933c26deSDmitry Stogov 	while (*bucket != NULL) {
376933c26deSDmitry Stogov 		if (key == (*bucket)->key && path_len == (*bucket)->path_len &&
377cde75960SPierre Joye 					memcmp(path, (*bucket)->path, path_len) == 0) {
378933c26deSDmitry Stogov 			realpath_cache_bucket *r = *bucket;
379933c26deSDmitry Stogov 			*bucket = (*bucket)->next;
380b7a7b1a6SStanislav Malyshev 
38101a6840bSRasmus Lerdorf 			/* if the pointers match then only subtract the length of the path */
3824ad9f197SRasmus Lerdorf 		   	if(r->path == r->realpath) {
3834ad9f197SRasmus Lerdorf 				CWDG(realpath_cache_size) -= sizeof(realpath_cache_bucket) + r->path_len + 1;
3844ad9f197SRasmus Lerdorf 			} else {
3854ad9f197SRasmus Lerdorf 				CWDG(realpath_cache_size) -= sizeof(realpath_cache_bucket) + r->path_len + 1 + r->realpath_len + 1;
3864ad9f197SRasmus Lerdorf 			}
387b7a7b1a6SStanislav Malyshev 
388933c26deSDmitry Stogov 			free(r);
389933c26deSDmitry Stogov 			return;
390933c26deSDmitry Stogov 		} else {
391933c26deSDmitry Stogov 			bucket = &(*bucket)->next;
392933c26deSDmitry Stogov 		}
393933c26deSDmitry Stogov 	}
394933c26deSDmitry Stogov }
39538b7d577SAntony Dovgal /* }}} */
396933c26deSDmitry Stogov 
realpath_cache_add(const char * path,size_t path_len,const char * realpath,size_t realpath_len,int is_dir,time_t t)39753169dc4SAnatol Belski static inline void realpath_cache_add(const char *path, size_t path_len, const char *realpath, size_t realpath_len, int is_dir, time_t t) /* {{{ */
398216853c0SAndi Gutmans {
399c3e3c98eSAnatol Belski 	zend_long size = sizeof(realpath_cache_bucket) + path_len + 1;
4003fadad31SDmitry Stogov 	int same = 1;
401ae504412SPierre Joye 
4023fadad31SDmitry Stogov 	if (realpath_len != path_len ||
403cde75960SPierre Joye 		memcmp(path, realpath, path_len) != 0) {
4043fadad31SDmitry Stogov 		size += realpath_len + 1;
4053fadad31SDmitry Stogov 		same = 0;
4063fadad31SDmitry Stogov 	}
4073fadad31SDmitry Stogov 
408216853c0SAndi Gutmans 	if (CWDG(realpath_cache_size) + size <= CWDG(realpath_cache_size_limit)) {
409216853c0SAndi Gutmans 		realpath_cache_bucket *bucket = malloc(size);
410c3e3c98eSAnatol Belski 		zend_ulong n;
4110304ec79SPierre Joye 
4129a0771d8SPierre Joye 		if (bucket == NULL) {
4139a0771d8SPierre Joye 			return;
4149a0771d8SPierre Joye 		}
4159a0771d8SPierre Joye 
416216853c0SAndi Gutmans 		bucket->key = realpath_cache_key(path, path_len);
417216853c0SAndi Gutmans 		bucket->path = (char*)bucket + sizeof(realpath_cache_bucket);
418216853c0SAndi Gutmans 		memcpy(bucket->path, path, path_len+1);
419216853c0SAndi Gutmans 		bucket->path_len = path_len;
4203fadad31SDmitry Stogov 		if (same) {
4213fadad31SDmitry Stogov 			bucket->realpath = bucket->path;
4223fadad31SDmitry Stogov 		} else {
4233fadad31SDmitry Stogov 			bucket->realpath = bucket->path + (path_len + 1);
4243fadad31SDmitry Stogov 			memcpy(bucket->realpath, realpath, realpath_len+1);
4253fadad31SDmitry Stogov 		}
426216853c0SAndi Gutmans 		bucket->realpath_len = realpath_len;
4274d790486SAnatol Belski 		bucket->is_dir = is_dir > 0;
428ce2cd892SKalle Sommer Nielsen #ifdef ZEND_WIN32
42918d5751aSPierre Joye 		bucket->is_rvalid   = 0;
43018d5751aSPierre Joye 		bucket->is_readable = 0;
43118d5751aSPierre Joye 		bucket->is_wvalid   = 0;
43218d5751aSPierre Joye 		bucket->is_writable = 0;
43318d5751aSPierre Joye #endif
434216853c0SAndi Gutmans 		bucket->expires = t + CWDG(realpath_cache_ttl);
435216853c0SAndi Gutmans 		n = bucket->key % (sizeof(CWDG(realpath_cache)) / sizeof(CWDG(realpath_cache)[0]));
436216853c0SAndi Gutmans 		bucket->next = CWDG(realpath_cache)[n];
437216853c0SAndi Gutmans 		CWDG(realpath_cache)[n] = bucket;
438a719e16fSIlia Alshanetsky 		CWDG(realpath_cache_size) += size;
439216853c0SAndi Gutmans 	}
440216853c0SAndi Gutmans }
44138b7d577SAntony Dovgal /* }}} */
442216853c0SAndi Gutmans 
realpath_cache_find(const char * path,size_t path_len,time_t t)443758af77eSAnatol Belski static inline realpath_cache_bucket* realpath_cache_find(const char *path, size_t path_len, time_t t) /* {{{ */
444216853c0SAndi Gutmans {
445c3e3c98eSAnatol Belski 	zend_ulong key = realpath_cache_key(path, path_len);
446c3e3c98eSAnatol Belski 	zend_ulong n = key % (sizeof(CWDG(realpath_cache)) / sizeof(CWDG(realpath_cache)[0]));
447216853c0SAndi Gutmans 	realpath_cache_bucket **bucket = &CWDG(realpath_cache)[n];
448216853c0SAndi Gutmans 
449216853c0SAndi Gutmans 	while (*bucket != NULL) {
450216853c0SAndi Gutmans 		if (CWDG(realpath_cache_ttl) && (*bucket)->expires < t) {
451216853c0SAndi Gutmans 			realpath_cache_bucket *r = *bucket;
45271d4d4a9SDmitry Stogov 			*bucket = (*bucket)->next;
45301a6840bSRasmus Lerdorf 
454b7a7b1a6SStanislav Malyshev 			/* if the pointers match then only subtract the length of the path */
4554ad9f197SRasmus Lerdorf 		   	if(r->path == r->realpath) {
4564ad9f197SRasmus Lerdorf 				CWDG(realpath_cache_size) -= sizeof(realpath_cache_bucket) + r->path_len + 1;
4574ad9f197SRasmus Lerdorf 			} else {
4584ad9f197SRasmus Lerdorf 				CWDG(realpath_cache_size) -= sizeof(realpath_cache_bucket) + r->path_len + 1 + r->realpath_len + 1;
4594ad9f197SRasmus Lerdorf 			}
46071d4d4a9SDmitry Stogov 			free(r);
461216853c0SAndi Gutmans 		} else if (key == (*bucket)->key && path_len == (*bucket)->path_len &&
462cde75960SPierre Joye 					memcmp(path, (*bucket)->path, path_len) == 0) {
463216853c0SAndi Gutmans 			return *bucket;
464216853c0SAndi Gutmans 		} else {
46571d4d4a9SDmitry Stogov 			bucket = &(*bucket)->next;
466216853c0SAndi Gutmans 		}
467216853c0SAndi Gutmans 	}
468216853c0SAndi Gutmans 	return NULL;
469216853c0SAndi Gutmans }
47038b7d577SAntony Dovgal /* }}} */
471216853c0SAndi Gutmans 
realpath_cache_lookup(const char * path,size_t path_len,time_t t)472758af77eSAnatol Belski CWD_API realpath_cache_bucket* realpath_cache_lookup(const char *path, size_t path_len, time_t t) /* {{{ */
47318d5751aSPierre Joye {
474bdeb220fSAnatol Belski 	return realpath_cache_find(path, path_len, t);
47518d5751aSPierre Joye }
47618d5751aSPierre Joye /* }}} */
47718d5751aSPierre Joye 
realpath_cache_size(void)478bdeb220fSAnatol Belski CWD_API zend_long realpath_cache_size(void)
4797beb1af8SStanislav Malyshev {
4807beb1af8SStanislav Malyshev 	return CWDG(realpath_cache_size);
4817beb1af8SStanislav Malyshev }
4827beb1af8SStanislav Malyshev 
realpath_cache_max_buckets(void)483bdeb220fSAnatol Belski CWD_API zend_long realpath_cache_max_buckets(void)
4847beb1af8SStanislav Malyshev {
4857beb1af8SStanislav Malyshev 	return (sizeof(CWDG(realpath_cache)) / sizeof(CWDG(realpath_cache)[0]));
4867beb1af8SStanislav Malyshev }
4877beb1af8SStanislav Malyshev 
realpath_cache_get_buckets(void)488bdeb220fSAnatol Belski CWD_API realpath_cache_bucket** realpath_cache_get_buckets(void)
4897beb1af8SStanislav Malyshev {
4907beb1af8SStanislav Malyshev 	return CWDG(realpath_cache);
4917beb1af8SStanislav Malyshev }
4927beb1af8SStanislav Malyshev 
4937beb1af8SStanislav Malyshev 
494cd5d8585SFelipe Pena #undef LINK_MAX
4953fadad31SDmitry Stogov #define LINK_MAX 32
4963fadad31SDmitry Stogov 
tsrm_realpath_r(char * path,size_t start,size_t len,int * ll,time_t * t,int use_realpath,int is_dir,int * link_is_dir)49749d9b301SAnatol Belski static size_t tsrm_realpath_r(char *path, size_t start, size_t len, int *ll, time_t *t, int use_realpath, int is_dir, int *link_is_dir) /* {{{ */
498daf926cfSAndi Gutmans {
49949d9b301SAnatol Belski 	size_t i, j;
500824cbc27SNikita Popov 	int directory = 0, save;
501ce2cd892SKalle Sommer Nielsen #ifdef ZEND_WIN32
5023d3f11edSAnatol Belski 	WIN32_FIND_DATAW dataw;
5033d3f11edSAnatol Belski 	HANDLE hFind = INVALID_HANDLE_VALUE;
50408f6a76bSAnatol Belski 	ALLOCA_FLAG(use_heap_large)
5053d3f11edSAnatol Belski 	wchar_t *pathw = NULL;
506824cbc27SNikita Popov 	int may_retry_reparse_point;
5073d3f11edSAnatol Belski #define FREE_PATHW() \
5083d3f11edSAnatol Belski 	do { free(pathw); } while(0);
5093d3f11edSAnatol Belski 
5103fadad31SDmitry Stogov #else
5118ee2a4a9SAnatol Belski 	zend_stat_t st;
5128e0f5bbfSDmitry Stogov #endif
5133fadad31SDmitry Stogov 	realpath_cache_bucket *bucket;
5143fadad31SDmitry Stogov 	char *tmp;
51508f6a76bSAnatol Belski 	ALLOCA_FLAG(use_heap)
516daf926cfSAndi Gutmans 
5173fadad31SDmitry Stogov 	while (1) {
5183fadad31SDmitry Stogov 		if (len <= start) {
5192c90b8a0SDmitry Stogov 			if (link_is_dir) {
5202c90b8a0SDmitry Stogov 				*link_is_dir = 1;
5212c90b8a0SDmitry Stogov 			}
5223fadad31SDmitry Stogov 			return start;
5233fadad31SDmitry Stogov 		}
524811634bdSDmitry Stogov 
5253fadad31SDmitry Stogov 		i = len;
5263fadad31SDmitry Stogov 		while (i > start && !IS_SLASH(path[i-1])) {
5273fadad31SDmitry Stogov 			i--;
5283fadad31SDmitry Stogov 		}
529827284ecSAnatol Belski 		assert(i < MAXPATHLEN);
530811634bdSDmitry Stogov 
5313fadad31SDmitry Stogov 		if (i == len ||
53249d9b301SAnatol Belski 			(i + 1 == len && path[i] == '.')) {
5333fadad31SDmitry Stogov 			/* remove double slashes and '.' */
5348b20e7b6SAnatol Belski 			len = EXPECTED(i > 0) ? i - 1 : 0;
5353fadad31SDmitry Stogov 			is_dir = 1;
5363fadad31SDmitry Stogov 			continue;
537827284ecSAnatol Belski 		} else if (i + 2 == len && path[i] == '.' && path[i+1] == '.') {
5383fadad31SDmitry Stogov 			/* remove '..' and previous directory */
5392c90b8a0SDmitry Stogov 			is_dir = 1;
5402c90b8a0SDmitry Stogov 			if (link_is_dir) {
5412c90b8a0SDmitry Stogov 				*link_is_dir = 1;
5422c90b8a0SDmitry Stogov 			}
54349d9b301SAnatol Belski 			if (i <= start + 1) {
5443fadad31SDmitry Stogov 				return start ? start : len;
545eb25e822SAntony Dovgal 			}
546bdeb220fSAnatol Belski 			j = tsrm_realpath_r(path, start, i-1, ll, t, use_realpath, 1, NULL);
547827284ecSAnatol Belski 			if (j > start && j != (size_t)-1) {
5483fadad31SDmitry Stogov 				j--;
549827284ecSAnatol Belski 				assert(i < MAXPATHLEN);
5503fadad31SDmitry Stogov 				while (j > start && !IS_SLASH(path[j])) {
5513fadad31SDmitry Stogov 					j--;
5523fadad31SDmitry Stogov 				}
553827284ecSAnatol Belski 				assert(i < MAXPATHLEN);
5543fadad31SDmitry Stogov 				if (!start) {
5553fadad31SDmitry Stogov 					/* leading '..' must not be removed in case of relative path */
5563fadad31SDmitry Stogov 					if (j == 0 && path[0] == '.' && path[1] == '.' &&
557cde75960SPierre Joye 							IS_SLASH(path[2])) {
5583fadad31SDmitry Stogov 						path[3] = '.';
5593fadad31SDmitry Stogov 						path[4] = '.';
5603fadad31SDmitry Stogov 						path[5] = DEFAULT_SLASH;
5613fadad31SDmitry Stogov 						j = 5;
562ae504412SPierre Joye 					} else if (j > 0 &&
563cde75960SPierre Joye 							path[j+1] == '.' && path[j+2] == '.' &&
564cde75960SPierre Joye 							IS_SLASH(path[j+3])) {
5653fadad31SDmitry Stogov 						j += 4;
5663fadad31SDmitry Stogov 						path[j++] = '.';
5673fadad31SDmitry Stogov 						path[j++] = '.';
5683fadad31SDmitry Stogov 						path[j] = DEFAULT_SLASH;
5693fadad31SDmitry Stogov 					}
5703fadad31SDmitry Stogov 				}
5713fadad31SDmitry Stogov 			} else if (!start && !j) {
5723fadad31SDmitry Stogov 				/* leading '..' must not be removed in case of relative path */
5733fadad31SDmitry Stogov 				path[0] = '.';
5743fadad31SDmitry Stogov 				path[1] = '.';
5753fadad31SDmitry Stogov 				path[2] = DEFAULT_SLASH;
5763fadad31SDmitry Stogov 				j = 2;
577eb25e822SAntony Dovgal 			}
5783fadad31SDmitry Stogov 			return j;
579216853c0SAndi Gutmans 		}
580ae504412SPierre Joye 
5813fadad31SDmitry Stogov 		path[len] = 0;
582811634bdSDmitry Stogov 
5833fadad31SDmitry Stogov 		save = (use_realpath != CWD_EXPAND);
5843fadad31SDmitry Stogov 
5853fadad31SDmitry Stogov 		if (start && save && CWDG(realpath_cache_size_limit)) {
5863fadad31SDmitry Stogov 			/* cache lookup for absolute path */
5873fadad31SDmitry Stogov 			if (!*t) {
5883fadad31SDmitry Stogov 				*t = time(0);
589216853c0SAndi Gutmans 			}
590bdeb220fSAnatol Belski 			if ((bucket = realpath_cache_find(path, len, *t)) != NULL) {
591cde75960SPierre Joye 				if (is_dir && !bucket->is_dir) {
5923fadad31SDmitry Stogov 					/* not a directory */
59349d9b301SAnatol Belski 					return (size_t)-1;
594cde75960SPierre Joye 				} else {
595cde75960SPierre Joye 					if (link_is_dir) {
596cde75960SPierre Joye 						*link_is_dir = bucket->is_dir;
597cde75960SPierre Joye 					}
5983fadad31SDmitry Stogov 					memcpy(path, bucket->realpath, bucket->realpath_len + 1);
599cde75960SPierre Joye 					return bucket->realpath_len;
6003fadad31SDmitry Stogov 				}
601cde75960SPierre Joye 			}
602216853c0SAndi Gutmans 		}
603daf926cfSAndi Gutmans 
604ce2cd892SKalle Sommer Nielsen #ifdef ZEND_WIN32
605c756f82cSChristoph M. Becker retry_reparse_point:
606848e24f2SChristoph M. Becker 		may_retry_reparse_point = 0;
6073d3f11edSAnatol Belski 		if (save) {
6083d3f11edSAnatol Belski 			pathw = php_win32_ioutil_any_to_w(path);
6093d3f11edSAnatol Belski 			if (!pathw) {
61049d9b301SAnatol Belski 				return (size_t)-1;
6113011278aSDmitry Stogov 			}
612ad4ef13cSAnatol Belski 			hFind = FindFirstFileExW(pathw, FindExInfoBasic, &dataw, FindExSearchNameMatch, NULL, 0);
6133d3f11edSAnatol Belski 			if (INVALID_HANDLE_VALUE == hFind) {
6143d3f11edSAnatol Belski 				if (use_realpath == CWD_REALPATH) {
6153d3f11edSAnatol Belski 					/* file not found */
6163d3f11edSAnatol Belski 					FREE_PATHW()
61749d9b301SAnatol Belski 					return (size_t)-1;
6183d3f11edSAnatol Belski 				}
6193d3f11edSAnatol Belski 				/* continue resolution anyway but don't save result in the cache */
6203d3f11edSAnatol Belski 				save = 0;
6213d3f11edSAnatol Belski 			} else {
6223d3f11edSAnatol Belski 				FindClose(hFind);
6233d3f11edSAnatol Belski 			}
6243fadad31SDmitry Stogov 		}
625a5302d87SPierre Joye 
62608f6a76bSAnatol Belski 		tmp = do_alloca(len+1, use_heap);
6273fadad31SDmitry Stogov 		memcpy(tmp, path, len+1);
628a5302d87SPierre Joye 
629c756f82cSChristoph M. Becker retry_reparse_tag_cloud:
630ae504412SPierre Joye 		if(save &&
631366e7170SPierre Joye 				!(IS_UNC_PATH(path, len) && len >= 3 && path[2] != '?') &&
6323d3f11edSAnatol Belski                                (dataw.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
6333d3f11edSAnatol Belski 				) {
634a5302d87SPierre Joye 			/* File is a reparse point. Get the target */
635a5302d87SPierre Joye 			HANDLE hLink = NULL;
636e42e8b10SAnatol Belski 			PHP_WIN32_IOUTIL_REPARSE_DATA_BUFFER * pbuffer;
637fb6c3d3cSAnatol Belski 			DWORD retlength = 0;
63849d9b301SAnatol Belski 			size_t bufindex = 0;
63949d9b301SAnatol Belski 			uint8_t isabsolute = 0;
640a5302d87SPierre Joye 			wchar_t * reparsetarget;
641b6882eddSPierre Joye 			BOOL isVolume = FALSE;
64251e1da6eSAnatol Belski #if VIRTUAL_CWD_DEBUG
64351e1da6eSAnatol Belski 			char *printname = NULL;
64451e1da6eSAnatol Belski #endif
64551e1da6eSAnatol Belski 			char *substitutename = NULL;
64695406c87SAnatol Belski 			size_t substitutename_len;
64749d9b301SAnatol Belski 			size_t substitutename_off = 0;
6486b6122a9SAnatol Belski 			wchar_t tmpsubstname[MAXPATHLEN];
649a5302d87SPierre Joye 
650a5302d87SPierre Joye 			if(++(*ll) > LINK_MAX) {
6513d3f11edSAnatol Belski 				free_alloca(tmp, use_heap);
6523d3f11edSAnatol Belski 				FREE_PATHW()
65349d9b301SAnatol Belski 				return (size_t)-1;
654a5302d87SPierre Joye 			}
655a5302d87SPierre Joye 
65617d621e7SAnatol Belski 			hLink = CreateFileW(pathw,
65717d621e7SAnatol Belski 					0,
65817d621e7SAnatol Belski 					PHP_WIN32_IOUTIL_DEFAULT_SHARE_MODE,
65917d621e7SAnatol Belski 					NULL,
66017d621e7SAnatol Belski 					OPEN_EXISTING,
66117d621e7SAnatol Belski 					FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS,
66217d621e7SAnatol Belski 					NULL);
663a5302d87SPierre Joye 			if(hLink == INVALID_HANDLE_VALUE) {
6643d3f11edSAnatol Belski 				free_alloca(tmp, use_heap);
6653d3f11edSAnatol Belski 				FREE_PATHW()
66649d9b301SAnatol Belski 				return (size_t)-1;
667a5302d87SPierre Joye 			}
668a5302d87SPierre Joye 
669e42e8b10SAnatol Belski 			pbuffer = (PHP_WIN32_IOUTIL_REPARSE_DATA_BUFFER *)do_alloca(MAXIMUM_REPARSE_DATA_BUFFER_SIZE, use_heap_large);
6709a0771d8SPierre Joye 			if (pbuffer == NULL) {
6716b63d80aSAnatol Belski 				CloseHandle(hLink);
6723d3f11edSAnatol Belski 				free_alloca(tmp, use_heap);
6733d3f11edSAnatol Belski 				FREE_PATHW()
67449d9b301SAnatol Belski 				return (size_t)-1;
6759a0771d8SPierre Joye 			}
676a5302d87SPierre Joye 			if(!DeviceIoControl(hLink, FSCTL_GET_REPARSE_POINT, NULL, 0, pbuffer,  MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &retlength, NULL)) {
67781f52158SChristoph M. Becker 				BY_HANDLE_FILE_INFORMATION fileInformation;
67881f52158SChristoph M. Becker 
67908f6a76bSAnatol Belski 				free_alloca(pbuffer, use_heap_large);
68081f52158SChristoph M. Becker 				if ((dataw.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
68181f52158SChristoph M. Becker 						(dataw.dwReserved0 & ~IO_REPARSE_TAG_CLOUD_MASK) == IO_REPARSE_TAG_CLOUD &&
68281f52158SChristoph M. Becker 						EG(windows_version_info).dwMajorVersion >= 10 &&
68381f52158SChristoph M. Becker 						EG(windows_version_info).dwMinorVersion == 0 &&
68481f52158SChristoph M. Becker 						EG(windows_version_info).dwBuildNumber >= 18362 &&
68581f52158SChristoph M. Becker 						GetFileInformationByHandle(hLink, &fileInformation) &&
68681f52158SChristoph M. Becker 						!(fileInformation.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
68781f52158SChristoph M. Becker 					dataw.dwFileAttributes = fileInformation.dwFileAttributes;
68881f52158SChristoph M. Becker 					CloseHandle(hLink);
68981f52158SChristoph M. Becker 					(*ll)--;
690c756f82cSChristoph M. Becker 					goto retry_reparse_tag_cloud;
69181f52158SChristoph M. Becker 				}
6923d3f11edSAnatol Belski 				free_alloca(tmp, use_heap);
693a5302d87SPierre Joye 				CloseHandle(hLink);
6943d3f11edSAnatol Belski 				FREE_PATHW()
69549d9b301SAnatol Belski 				return (size_t)-1;
696a5302d87SPierre Joye 			}
697a5302d87SPierre Joye 
698a5302d87SPierre Joye 			CloseHandle(hLink);
699a5302d87SPierre Joye 
700a5302d87SPierre Joye 			if(pbuffer->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
701848e24f2SChristoph M. Becker 				may_retry_reparse_point = 1;
702a5302d87SPierre Joye 				reparsetarget = pbuffer->SymbolicLinkReparseBuffer.ReparseTarget;
703cdd8368dSGabriel Caruso 				isabsolute = pbuffer->SymbolicLinkReparseBuffer.Flags == 0;
70451e1da6eSAnatol Belski #if VIRTUAL_CWD_DEBUG
705