summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPierre Joye <pajoye@php.net>2009-06-16 00:13:56 +0000
committerPierre Joye <pajoye@php.net>2009-06-16 00:13:56 +0000
commita5302d870dea471bda1e2d39e2d4fa084e432d94 (patch)
tree7d7b33a65c0b0d11a138b08c6e186ba127e5af56
parent18d5751a9e8da170ca02ddbe06120c3993c9bf1e (diff)
downloadphp-git-a5302d870dea471bda1e2d39e2d4fa084e432d94.tar.gz
- #47767, include_once does not resolve windows symlinks or junctions
-rw-r--r--TSRM/tsrm_virtual_cwd.c143
-rw-r--r--ext/standard/tests/file/bug41874.phpt17
-rw-r--r--ext/standard/tests/file/bug47767.phpt45
-rw-r--r--ext/standard/tests/file/link_win32.phpt8
4 files changed, 188 insertions, 25 deletions
diff --git a/TSRM/tsrm_virtual_cwd.c b/TSRM/tsrm_virtual_cwd.c
index 41cd1ff754..060da8ec4a 100644
--- a/TSRM/tsrm_virtual_cwd.c
+++ b/TSRM/tsrm_virtual_cwd.c
@@ -137,6 +137,42 @@ static int php_check_dots(const char *element, int n)
#ifdef TSRM_WIN32
+#ifdef CTL_CODE
+#undef CTL_CODE
+#endif
+#define CTL_CODE(DeviceType,Function,Method,Access) (((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
+#define FILE_DEVICE_FILE_SYSTEM 0x00000009
+#define METHOD_BUFFERED 0
+#define FILE_ANY_ACCESS 0
+#define FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE ( 16 * 1024 )
+
+typedef struct {
+ unsigned long ReparseTag;
+ unsigned short ReparseDataLength;
+ unsigned short Reserved;
+ union {
+ struct {
+ unsigned short SubstituteNameOffset;
+ unsigned short SubstituteNameLength;
+ unsigned short PrintNameOffset;
+ unsigned short PrintNameLength;
+ unsigned long Flags;
+ wchar_t ReparseTarget[1];
+ } SymbolicLinkReparseBuffer;
+ struct {
+ unsigned short SubstituteNameOffset;
+ unsigned short SubstituteNameLength;
+ unsigned short PrintNameOffset;
+ unsigned short PrintNameLength;
+ wchar_t ReparseTarget[1];
+ } MountPointReparseBuffer;
+ struct {
+ unsigned char ReparseTarget[1];
+ } GenericReparseBuffer;
+ };
+} REPARSE_DATA_BUFFER;
+
#define SECS_BETWEEN_EPOCHS (__int64)11644473600
#define SECS_TO_100NS (__int64)10000000
static inline time_t FileTimeToUnixTime(const FILETIME FileTime)
@@ -530,7 +566,8 @@ static int tsrm_realpath_r(char *path, int start, int len, int *ll, time_t *t, i
#endif
realpath_cache_bucket *bucket;
char *tmp;
- TSRM_ALLOCA_FLAG(use_heap);
+ TSRM_ALLOCA_FLAG(use_heap)
+ TSRM_ALLOCA_FLAG(use_heap_large)
while (1) {
if (len <= start) {
@@ -606,7 +643,7 @@ static int tsrm_realpath_r(char *path, int start, int len, int *ll, time_t *t, i
memcpy(path, bucket->realpath, bucket->realpath_len + 1);
return bucket->realpath_len;
}
- }
+ }
}
#ifdef TSRM_WIN32
@@ -618,16 +655,103 @@ static int tsrm_realpath_r(char *path, int start, int len, int *ll, time_t *t, i
/* continue resolution anyway but don't save result in the cache */
save = 0;
}
+
if (save) {
- directory = (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
- if (is_dir && !directory) {
- /* not a directory */
- FindClose(hFind);
- return -1;
- }
+ FindClose(hFind);
}
+
tmp = tsrm_do_alloca(len+1, use_heap);
memcpy(tmp, path, len+1);
+
+ if(save && (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
+ /* File is a reparse point. Get the target */
+ HANDLE hLink = NULL;
+ REPARSE_DATA_BUFFER * pbuffer;
+ unsigned int retlength = 0, rname_off = 0;
+ int bufindex = 0, rname_len = 0, isabsolute = 0;
+ wchar_t * reparsetarget;
+
+ if(++(*ll) > LINK_MAX) {
+ return -1;
+ }
+
+ hLink = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ if(hLink == INVALID_HANDLE_VALUE) {
+ return -1;
+ }
+
+ pbuffer = (REPARSE_DATA_BUFFER *)tsrm_do_alloca(MAXIMUM_REPARSE_DATA_BUFFER_SIZE, use_heap_large);
+ if(!DeviceIoControl(hLink, FSCTL_GET_REPARSE_POINT, NULL, 0, pbuffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &retlength, NULL)) {
+ tsrm_free_alloca(pbuffer, use_heap_large);
+ CloseHandle(hLink);
+ return -1;
+ }
+
+ CloseHandle(hLink);
+
+ if(pbuffer->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
+ rname_len = pbuffer->SymbolicLinkReparseBuffer.PrintNameLength/2;
+ rname_off = pbuffer->SymbolicLinkReparseBuffer.PrintNameOffset/2;
+ reparsetarget = pbuffer->SymbolicLinkReparseBuffer.ReparseTarget;
+ isabsolute = (pbuffer->SymbolicLinkReparseBuffer.Flags == 0) ? 1 : 0;
+ }
+ else if(pbuffer->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
+ rname_len = pbuffer->MountPointReparseBuffer.PrintNameLength/2;
+ rname_off = pbuffer->MountPointReparseBuffer.PrintNameOffset/2;
+ reparsetarget = pbuffer->MountPointReparseBuffer.ReparseTarget;
+ isabsolute = 1;
+ }
+ else {
+ tsrm_free_alloca(pbuffer, use_heap_large);
+ return -1;
+ }
+
+ /* Convert wide string to narrow string */
+ for(bufindex = 0; bufindex < rname_len; bufindex++) {
+ *(path + bufindex) = (char)(reparsetarget[rname_off + bufindex]);
+ }
+
+ *(path + bufindex) = 0;
+ tsrm_free_alloca(pbuffer, use_heap_large);
+ j = bufindex;
+
+ if(isabsolute == 1) {
+ /* use_realpath is 0 in the call below coz path is absolute*/
+ j = tsrm_realpath_r(path, 0, j, ll, t, 0, is_dir, &directory TSRMLS_CC);
+ if(j < 0) {
+ tsrm_free_alloca(tmp, use_heap);
+ return -1;
+ }
+ }
+ else {
+ if(i + j >= MAXPATHLEN - 1) {
+ tsrm_free_alloca(tmp, use_heap);
+ return -1;
+ }
+
+ memmove(path+i, path, j+1);
+ memcpy(path, tmp, i-1);
+ path[i-1] = DEFAULT_SLASH;
+ j = tsrm_realpath_r(path, start, i + j, ll, t, use_realpath, is_dir, &directory TSRMLS_CC);
+ if(j < 0) {
+ tsrm_free_alloca(tmp, use_heap);
+ return -1;
+ }
+ }
+
+ if(link_is_dir) {
+ *link_is_dir = directory;
+ }
+ }
+ else {
+ if (save) {
+ directory = (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
+ if (is_dir && !directory) {
+ /* not a directory */
+ return -1;
+ }
+ }
+
#elif defined(NETWARE)
save = 0;
tmp = tsrm_do_alloca(len+1, use_heap);
@@ -699,19 +823,18 @@ static int tsrm_realpath_r(char *path, int start, int len, int *ll, time_t *t, i
#ifdef TSRM_WIN32
if (j < 0 || j + len - i >= MAXPATHLEN-1) {
tsrm_free_alloca(tmp, use_heap);
- if (save) FindClose(hFind);
return -1;
}
if (save) {
i = strlen(data.cFileName);
memcpy(path+j, data.cFileName, i+1);
j += i;
- FindClose(hFind);
} else {
/* use the original file or directory name as it wasn't found */
memcpy(path+j, tmp+i, len-i+1);
j += (len-i);
}
+ }
#else
if (j < 0 || j + len - i >= MAXPATHLEN-1) {
tsrm_free_alloca(tmp, use_heap);
diff --git a/ext/standard/tests/file/bug41874.phpt b/ext/standard/tests/file/bug41874.phpt
index c6f9fed675..c6badef5c0 100644
--- a/ext/standard/tests/file/bug41874.phpt
+++ b/ext/standard/tests/file/bug41874.phpt
@@ -1,22 +1,15 @@
--TEST--
-bug #41874 (Separate STDOUT and STDERR in exec functions)
---CREDITS--
-Venkat Raman Don
---SKIPIF--
+bug #42143 (The constant NAN is reported as 0 on Windows build)
<?php
if(substr(PHP_OS, 0, 3) != 'WIN' ) {
- die('skip windows only test');
-}
+ die('skip windows only test');
?>
--FILE--
<?php
-$result = exec('cd 1:\\non_existant; dir nonexistant');
+$result = exec('cd 1:\non_existant; dir nonexistant');
echo "$result";
-system('cd 1:\\non_existant; dir nonexistant');
-$result = shell_exec('cd 1:\\non_existant; dir nonexistant');
-echo $result;
+system('cd 1:\non_existant; dir nonexistant');
?>
--EXPECT--
The system cannot find the drive specified.
-The system cannot find the drive specified.
-The system cannot find the drive specified.
+The system cannot find the drive specified. \ No newline at end of file
diff --git a/ext/standard/tests/file/bug47767.phpt b/ext/standard/tests/file/bug47767.phpt
new file mode 100644
index 0000000000..62388c28cb
--- /dev/null
+++ b/ext/standard/tests/file/bug47767.phpt
@@ -0,0 +1,45 @@
+--TEST--
+bug #47767 (include_once does not resolve windows symlinks or junctions)
+--CREDITS--
+Venkat Raman Don
+--SKIPIF--
+<?php
+if(substr(PHP_OS, 0, 3) != 'WIN' ) {
+ die('skip windows only test');
+}
+if(PHP_WINDOWS_VERSION_MAJOR < 6) {
+ die('skip windows version 6.0+ only test');
+}
+?>
+--FILE--
+<?php
+echo "Testing include_once using file symbolic link\n";
+$filename = __DIR__ . '\\a.php';
+$content = '<?php echo "I am included\n" ?>';
+file_put_contents($filename, $content);
+$softlinkname = __DIR__ . '\\a_slink.php';
+symlink($filename, $softlinkname);
+include_once("$filename");
+include_once("$softlinkname");
+include_once("$softlinkname");
+
+echo "Testing include_once using directory symbolic link\n";
+$softdirlinkname = __DIR__ . "\\a_dir";
+symlink(__DIR__, $softdirlinkname);
+include_once("$softdirlinkname" . '\\a.php');
+
+echo "Testing include_once using junction points\n";
+$junctionname = __DIR__ . '\\a_jdir';
+exec("mklink /J $junctionname " . __DIR__);
+include_once("$junctionname" . '\\a.php');
+
+unlink($filename);
+unlink($softlinkname);
+rmdir($softdirlinkname);
+rmdir($junctionname);
+?>
+--EXPECT--
+Testing include_once using file symbolic link
+I am included
+Testing include_once using directory symbolic link
+Testing include_once using junction points \ No newline at end of file
diff --git a/ext/standard/tests/file/link_win32.phpt b/ext/standard/tests/file/link_win32.phpt
index 2bba5469c7..f038f46484 100644
--- a/ext/standard/tests/file/link_win32.phpt
+++ b/ext/standard/tests/file/link_win32.phpt
@@ -10,11 +10,12 @@ if(substr(PHP_OS, 0, 3) != 'WIN' ) {
?>
--FILE--
<?php
-$filename = __DIR__ . '\\a.php';
+$filename = __DIR__ . '/a.php';
$content = '<?php echo "Dummy Content.\n" ?>';
file_put_contents($filename, $content);
-$linkname = __DIR__ . '\\a_link.php';
-link("$filename", "$linkname");
+
+$linkname = __DIR__ . '/a_link.php';
+var_dump(link("$filename", "$linkname"));
var_dump(file_exists("$linkname"));
$linkcontent = file_get_contents($linkname);
var_dump($content == $linkcontent);
@@ -24,3 +25,4 @@ unlink($linkname);
--EXPECT--
bool(true)
bool(true)
+bool(true)