Skip to content

Commit 81f5215

Browse files
committed
Fix #78220: Can't access OneDrive folder
As of Windows 1903, when the OneDrive on-demand feature is enabled, the OneDrive folder is reported as reparse point by `FindFirstFile()`, but trying to get information about the reparse point using `DeviceIoControl()` fails with `ERROR_NOT_A_REPARSE_POINT`. We work around this problem by falling back to `GetFileInformationByHandle()` if that happens, but only if the reparse point is reported as cloud reparse point, and only if PHP is running on Windows 1903 or later. The patch has been developed in collaboration with ab@php.net. We should keep an eye on the somewhat quirky OneDrive behavior, since it might change again in a future Windows release.
1 parent 725f439 commit 81f5215

File tree

3 files changed

+35
-2
lines changed

3 files changed

+35
-2
lines changed

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ PHP NEWS
33
?? ??? 2019, PHP 7.2.23
44

55
- Core:
6+
. Fixed bug #78220 (Can't access OneDrive folder). (cmb, ab)
67
. Fixed bug #78412 (Generator incorrectly reports non-releasable $this as GC
78
child). (Nikita)
89

Zend/zend_virtual_cwd.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ cwd_state main_cwd_state; /* True global */
9191
#include <unistd.h>
9292
#else
9393
#include <direct.h>
94+
#include "zend_globals.h"
95+
#include "zend_globals_macros.h"
9496
#endif
9597

9698
#define CWD_STATE_COPY(d, s) \
@@ -855,6 +857,7 @@ static int tsrm_realpath_r(char *path, int start, int len, int *ll, time_t *t, i
855857
tmp = do_alloca(len+1, use_heap);
856858
memcpy(tmp, path, len+1);
857859

860+
retry:
858861
if(save &&
859862
!(IS_UNC_PATH(path, len) && len >= 3 && path[2] != '?') &&
860863
(dataw.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
@@ -895,7 +898,21 @@ static int tsrm_realpath_r(char *path, int start, int len, int *ll, time_t *t, i
895898
return -1;
896899
}
897900
if(!DeviceIoControl(hLink, FSCTL_GET_REPARSE_POINT, NULL, 0, pbuffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &retlength, NULL)) {
901+
BY_HANDLE_FILE_INFORMATION fileInformation;
902+
898903
free_alloca(pbuffer, use_heap_large);
904+
if ((dataw.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
905+
(dataw.dwReserved0 & ~IO_REPARSE_TAG_CLOUD_MASK) == IO_REPARSE_TAG_CLOUD &&
906+
EG(windows_version_info).dwMajorVersion >= 10 &&
907+
EG(windows_version_info).dwMinorVersion == 0 &&
908+
EG(windows_version_info).dwBuildNumber >= 18362 &&
909+
GetFileInformationByHandle(hLink, &fileInformation) &&
910+
!(fileInformation.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
911+
dataw.dwFileAttributes = fileInformation.dwFileAttributes;
912+
CloseHandle(hLink);
913+
(*ll)--;
914+
goto retry;
915+
}
899916
free_alloca(tmp, use_heap);
900917
CloseHandle(hLink);
901918
FREE_PATHW()
@@ -975,8 +992,7 @@ static int tsrm_realpath_r(char *path, int start, int len, int *ll, time_t *t, i
975992
}
976993
else if (pbuffer->ReparseTag == IO_REPARSE_TAG_DEDUP ||
977994
/* Starting with 1709. */
978-
(pbuffer->ReparseTag & IO_REPARSE_TAG_CLOUD_MASK) != 0 && 0x90001018L != pbuffer->ReparseTag ||
979-
IO_REPARSE_TAG_CLOUD == pbuffer->ReparseTag ||
995+
(pbuffer->ReparseTag & ~IO_REPARSE_TAG_CLOUD_MASK) == IO_REPARSE_TAG_CLOUD ||
980996
IO_REPARSE_TAG_ONEDRIVE == pbuffer->ReparseTag) {
981997
isabsolute = 1;
982998
substitutename = malloc((len + 1) * sizeof(char));

ext/standard/tests/dir/bug78220.phpt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
--TEST--
2+
Bug #78220 (Can't access OneDrive folder)
3+
--SKIPIF--
4+
<?php
5+
if (substr(PHP_OS, 0, 3) != 'WIN') die("skip this test is for Windows platforms only");
6+
?>
7+
--FILE--
8+
<?php
9+
$onedrive_dirs = array_unique([getenv('OneDrive'), getenv('OneDriveCommercial')]);
10+
foreach ($onedrive_dirs as $dir) {
11+
if ($dir && scandir($dir) === FALSE) {
12+
echo "can't scan $dir\n";
13+
}
14+
}
15+
?>
16+
--EXPECT--

0 commit comments

Comments
 (0)