From be40b135f062cdfb6a6abee5c50ba713d646799e Mon Sep 17 00:00:00 2001 From: Rafe Kettler Date: Tue, 25 Mar 2014 23:43:33 -0700 Subject: [PATCH] Make statSyscall in ext_file.cpp support relative paths by default. This fixes a number of php5 incompatibilities -- specifically this fixes #1733, and gives relative path support that should exist to is_readable, is_writable, is_executable, fileperms, fileowner, etc. (all the file* functions for extracting stat fields). Closes #1983 Reviewed By: @fredemmott Differential Revision: D1240987 --- hphp/runtime/base/stream-wrapper-registry.cpp | 3 ++- hphp/runtime/base/stream-wrapper-registry.h | 2 +- hphp/runtime/ext/ext_file.cpp | 27 ++++++++++++++++++++++---- hphp/test/slow/ext_file/predicates.php | 28 +++++++++++++++++++++++++++ hphp/test/slow/ext_file/predicates.php.expect | 16 +++++++++++++++ 5 files changed, 70 insertions(+), 6 deletions(-) diff --git a/hphp/runtime/base/stream-wrapper-registry.cpp b/hphp/runtime/base/stream-wrapper-registry.cpp index a3e0fd48506..3190e0eff72 100644 --- a/hphp/runtime/base/stream-wrapper-registry.cpp +++ b/hphp/runtime/base/stream-wrapper-registry.cpp @@ -185,7 +185,7 @@ Wrapper* getWrapper(const String& scheme) { return nullptr; } -Wrapper* getWrapperFromURI(const String& uri) { +Wrapper* getWrapperFromURI(const String& uri, int* pathIndex /* = NULL */) { const char *uri_string = uri.data(); /* Special case for PHP4 Backward Compatability */ @@ -204,6 +204,7 @@ Wrapper* getWrapperFromURI(const String& uri) { } int len = colon - uri_string; + if (pathIndex != nullptr) *pathIndex = len + sizeof("://") - 1; if (Wrapper *w = getWrapper(String(uri_string, len, CopyString))) { return w; } diff --git a/hphp/runtime/base/stream-wrapper-registry.h b/hphp/runtime/base/stream-wrapper-registry.h index 9a56eb52158..adda556a2e7 100644 --- a/hphp/runtime/base/stream-wrapper-registry.h +++ b/hphp/runtime/base/stream-wrapper-registry.h @@ -34,7 +34,7 @@ bool restoreWrapper(const String& scheme); bool registerRequestWrapper(const String& scheme, std::unique_ptr wrapper); Array enumWrappers(); Wrapper* getWrapper(const String& scheme); -Wrapper* getWrapperFromURI(const String& uri); +Wrapper* getWrapperFromURI(const String& uri, int* pathIndex = nullptr); /* Called during process init to register core wrappers */ void RegisterCoreWrappers(); diff --git a/hphp/runtime/ext/ext_file.cpp b/hphp/runtime/ext/ext_file.cpp index d7c0463f6f9..4928bad367e 100644 --- a/hphp/runtime/ext/ext_file.cpp +++ b/hphp/runtime/ext/ext_file.cpp @@ -34,6 +34,7 @@ #include "hphp/runtime/base/file-stream-wrapper.h" #include "hphp/runtime/base/directory.h" #include "hphp/runtime/base/thread-info.h" +#include "hphp/runtime/base/stat-cache.h" #include "hphp/system/systemlib.h" #include "hphp/util/logger.h" #include "hphp/util/process.h" @@ -122,11 +123,29 @@ static int statSyscall( const String& path, struct stat* buf, bool useFileCache = false) { - Stream::Wrapper* w = Stream::getWrapperFromURI(path); - if (useFileCache && dynamic_cast(w)) { - return ::stat(File::TranslatePathWithFileCache(path).data(), buf); + bool isRelative = path.charAt(0) != '/'; + int pathIndex = 0; + Stream::Wrapper* w = Stream::getWrapperFromURI(path, &pathIndex); + bool isFileStream = dynamic_cast(w); + auto canUseFileCache = useFileCache && isFileStream; + if (isRelative && !pathIndex) { + auto fullpath = g_context->getCwd() + String::FromChar('/') + path; + std::string realpath = StatCache::realpath(fullpath.data()); + // realpath will return an empty string for nonexistent files + if (realpath.empty()) { + return ENOENT; + } + auto translatedPath = canUseFileCache ? + File::TranslatePathWithFileCache(realpath) : + File::TranslatePath(realpath); + return ::stat(translatedPath.data(), buf); + } + + auto properPath = isFileStream ? path.substr(pathIndex) : path; + if (canUseFileCache) { + return ::stat(File::TranslatePathWithFileCache(properPath).data(), buf); } - return w->stat(path, buf); + return w->stat(properPath, buf); } static int lstatSyscall( diff --git a/hphp/test/slow/ext_file/predicates.php b/hphp/test/slow/ext_file/predicates.php index 0ff95aa022b..ba3e02e90b9 100644 --- a/hphp/test/slow/ext_file/predicates.php +++ b/hphp/test/slow/ext_file/predicates.php @@ -14,6 +14,10 @@ var_dump(is_readable($tempfile)); var_dump(is_uploaded_file($tempfile)); var_dump(filetype($tempfile)); +$streamfile = 'file://' . $tempfile; +var_dump(is_file($streamfile)); +var_dump(is_dir($streamfile)); + unlink($tempfile); mkdir($tempfile); @@ -21,3 +25,27 @@ var_dump(is_dir($tempfile)); rmdir($tempfile); clearstatcache(); var_dump(is_dir($tempfile)); +var_dump(is_writable($tempfile)); +var_dump(is_readable($tempfile)); +var_dump(is_executable($tempfile)); + +$tempfile = tempnam(getcwd(), 'vmextfiletest'); +$relativetempfile = './' . basename($tempfile); +var_dump(is_file($relativetempfile)); +var_dump(is_dir($relativetempfile)); +var_dump(is_link($relativetempfile)); +var_dump(is_executable($relativetempfile)); +chmod($tempfile, 0777); +clearstatcache(); +var_dump(is_executable($relativetempfile)); +var_dump(is_writable($relativetempfile)); +var_dump(is_readable($relativetempfile)); +var_dump(is_uploaded_file($relativetempfile)); +var_dump(filetype($relativetempfile)); + +unlink($tempfile); + +mkdir($tempfile); +var_dump(is_dir($relativetempfile)); +rmdir($tempfile); +var_dump(is_dir($relativetempfile)); diff --git a/hphp/test/slow/ext_file/predicates.php.expect b/hphp/test/slow/ext_file/predicates.php.expect index f0f648bf2ed..ff757d4cf33 100644 --- a/hphp/test/slow/ext_file/predicates.php.expect +++ b/hphp/test/slow/ext_file/predicates.php.expect @@ -10,3 +10,19 @@ bool(false) string(4) "file" bool(true) bool(false) +bool(true) +bool(false) +bool(false) +bool(false) +bool(false) +bool(true) +bool(false) +bool(false) +bool(false) +bool(true) +bool(true) +bool(true) +bool(false) +string(4) "file" +bool(true) +bool(false) -- 2.11.4.GIT