delegate some syscalls to the stream wrappers
Needed for phars. People are doing
file_exists('phar://a.phar/b.php');
I didn't do all syscalls like `chmod` or `symlink`. Think I should bite the bullet, or do it piecemeal when needed?
Esse commit está contido em:
@@ -123,7 +123,8 @@ bool File::IsPlainFilePath(CStrRef filename) {
|
||||
Variant File::Open(CStrRef filename, CStrRef mode,
|
||||
int options /* = 0 */,
|
||||
CVarRef context /* = null */) {
|
||||
File *file = Stream::open(filename, mode, options, context);
|
||||
Stream::Wrapper *wrapper = Stream::getWrapperFromURI(filename);
|
||||
File *file = wrapper->open(filename, mode, options, context);
|
||||
if (file != nullptr) {
|
||||
file->m_name = filename.data();
|
||||
file->m_mode = mode.data();
|
||||
|
||||
@@ -31,6 +31,15 @@ class FileStreamWrapper : public Stream::Wrapper {
|
||||
static MemFile* openFromCache(CStrRef filename, CStrRef mode);
|
||||
virtual File* open(CStrRef filename, CStrRef mode,
|
||||
int options, CVarRef context);
|
||||
virtual int access(CStrRef path, int mode) {
|
||||
return ::access(File::TranslatePath(path).data(), mode);
|
||||
}
|
||||
virtual int stat(CStrRef path, struct stat* buf) {
|
||||
return ::stat(File::TranslatePath(path).data(), buf);
|
||||
}
|
||||
virtual int lstat(CStrRef path, struct stat* buf) {
|
||||
return ::lstat(File::TranslatePath(path).data(), buf);
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -33,6 +33,15 @@ class Wrapper : boost::noncopyable {
|
||||
|
||||
virtual File* open(CStrRef filename, CStrRef mode,
|
||||
int options, CVarRef context) = 0;
|
||||
virtual int access(CStrRef path, int mode) {
|
||||
return -1;
|
||||
}
|
||||
virtual int lstat(CStrRef path, struct stat* buf) {
|
||||
return -1;
|
||||
}
|
||||
virtual int stat(CStrRef path, struct stat* buf) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
virtual ~Wrapper() {}
|
||||
};
|
||||
|
||||
@@ -176,26 +176,28 @@ Wrapper* getWrapper(CStrRef scheme) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
File* open(CStrRef uri, CStrRef mode, int options, CVarRef context) {
|
||||
StaticString
|
||||
s_compress_zlib("compress.zlib"),
|
||||
s_file("file");
|
||||
|
||||
Wrapper* getWrapperFromURI(CStrRef uri) {
|
||||
const char *uri_string = uri.data();
|
||||
Wrapper *wrapper = nullptr;
|
||||
|
||||
/* Special case for PHP4 Backward Compatability */
|
||||
if (!strncasecmp(uri_string, "zlib:", sizeof("zlib:") - 1)) {
|
||||
wrapper = getWrapper("compress.zlib");
|
||||
} else {
|
||||
const char *colon = strstr(uri_string, "://");
|
||||
if (colon) {
|
||||
wrapper = getWrapper(String(uri_string, colon - uri_string, CopyString));
|
||||
}
|
||||
return getWrapper(s_compress_zlib);
|
||||
}
|
||||
|
||||
if (wrapper == nullptr) {
|
||||
wrapper = getWrapper("file");
|
||||
const char *colon = strstr(uri_string, "://");
|
||||
if (!colon) {
|
||||
return getWrapper(s_file);
|
||||
}
|
||||
assert(wrapper);
|
||||
|
||||
return wrapper->open(uri, mode, options, context);
|
||||
int len = colon - uri_string;
|
||||
if (Wrapper *w = getWrapper(String(uri_string, len, CopyString))) {
|
||||
return w;
|
||||
}
|
||||
return getWrapper(s_file);
|
||||
}
|
||||
|
||||
static FileStreamWrapper s_file_stream_wrapper;
|
||||
|
||||
@@ -35,7 +35,7 @@ bool restoreWrapper(CStrRef scheme);
|
||||
bool registerRequestWrapper(CStrRef scheme, std::unique_ptr<Wrapper> wrapper);
|
||||
Array enumWrappers();
|
||||
Wrapper* getWrapper(CStrRef scheme);
|
||||
File* open(CStrRef uri, CStrRef mode, int options, CVarRef context);
|
||||
Wrapper* getWrapperFromURI(CStrRef uri);
|
||||
|
||||
/* Called during process init to register core wrappers */
|
||||
void RegisterCoreWrappers();
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
#include "hphp/runtime/server/static_content_cache.h"
|
||||
#include "hphp/runtime/base/zend_scanf.h"
|
||||
#include "hphp/runtime/base/pipe.h"
|
||||
#include "hphp/runtime/base/stream_wrapper_registry.h"
|
||||
#include "hphp/runtime/base/file_stream_wrapper.h"
|
||||
#include "hphp/system/systemlib.h"
|
||||
#include "hphp/util/logger.h"
|
||||
#include "hphp/util/util.h"
|
||||
@@ -95,6 +97,42 @@ static bool check_error(const char *function, int line, bool ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int accessSyscall(
|
||||
CStrRef path,
|
||||
int mode,
|
||||
bool useFileCache = false) {
|
||||
Stream::Wrapper* w = Stream::getWrapperFromURI(path);
|
||||
if (useFileCache && dynamic_cast<FileStreamWrapper*>(w)) {
|
||||
// This if block is needed for useFileCache
|
||||
return ::access(File::TranslatePath(path, useFileCache).data(), mode);
|
||||
}
|
||||
return w->access(path, mode);
|
||||
}
|
||||
|
||||
static int statSyscall(
|
||||
CStrRef path,
|
||||
struct stat* buf,
|
||||
bool useFileCache = false) {
|
||||
Stream::Wrapper* w = Stream::getWrapperFromURI(path);
|
||||
if (useFileCache && dynamic_cast<FileStreamWrapper*>(w)) {
|
||||
// This if block is needed for useFileCache
|
||||
return ::stat(File::TranslatePath(path, useFileCache).data(), buf);
|
||||
}
|
||||
return w->stat(path, buf);
|
||||
}
|
||||
|
||||
static int lstatSyscall(
|
||||
CStrRef path,
|
||||
struct stat* buf,
|
||||
bool useFileCache = false) {
|
||||
Stream::Wrapper* w = Stream::getWrapperFromURI(path);
|
||||
if (useFileCache && dynamic_cast<FileStreamWrapper*>(w)) {
|
||||
// This if block is needed for useFileCache
|
||||
return ::lstat(File::TranslatePath(path, useFileCache).data(), buf);
|
||||
}
|
||||
return w->lstat(path, buf);
|
||||
}
|
||||
|
||||
const StaticString
|
||||
s_dev("dev"),
|
||||
s_ino("ino"),
|
||||
@@ -580,13 +618,13 @@ Variant f_sha1_file(CStrRef filename, bool raw_output /* = false */) {
|
||||
|
||||
Variant f_fileperms(CStrRef filename) {
|
||||
struct stat sb;
|
||||
CHECK_SYSTEM(stat(File::TranslatePath(filename, true).data(), &sb));
|
||||
CHECK_SYSTEM(statSyscall(filename, &sb, true));
|
||||
return (int64_t)sb.st_mode;
|
||||
}
|
||||
|
||||
Variant f_fileinode(CStrRef filename) {
|
||||
struct stat sb;
|
||||
CHECK_SYSTEM(stat(File::TranslatePath(filename).data(), &sb));
|
||||
CHECK_SYSTEM(statSyscall(filename, &sb));
|
||||
return (int64_t)sb.st_ino;
|
||||
}
|
||||
|
||||
@@ -598,43 +636,43 @@ Variant f_filesize(CStrRef filename) {
|
||||
if (size >= 0) return size;
|
||||
}
|
||||
struct stat sb;
|
||||
CHECK_SYSTEM(stat(File::TranslatePath(filename, true).data(), &sb));
|
||||
CHECK_SYSTEM(statSyscall(filename, &sb, true));
|
||||
return (int64_t)sb.st_size;
|
||||
}
|
||||
|
||||
Variant f_fileowner(CStrRef filename) {
|
||||
struct stat sb;
|
||||
CHECK_SYSTEM(stat(File::TranslatePath(filename, true).data(), &sb));
|
||||
CHECK_SYSTEM(statSyscall(filename, &sb, true));
|
||||
return (int64_t)sb.st_uid;
|
||||
}
|
||||
|
||||
Variant f_filegroup(CStrRef filename) {
|
||||
struct stat sb;
|
||||
CHECK_SYSTEM(stat(File::TranslatePath(filename, true).data(), &sb));
|
||||
CHECK_SYSTEM(statSyscall(filename, &sb, true));
|
||||
return (int64_t)sb.st_gid;
|
||||
}
|
||||
|
||||
Variant f_fileatime(CStrRef filename) {
|
||||
struct stat sb;
|
||||
CHECK_SYSTEM(stat(File::TranslatePath(filename, true).data(), &sb));
|
||||
CHECK_SYSTEM(statSyscall(filename, &sb, true));
|
||||
return (int64_t)sb.st_atime;
|
||||
}
|
||||
|
||||
Variant f_filemtime(CStrRef filename) {
|
||||
struct stat sb;
|
||||
CHECK_SYSTEM(stat(File::TranslatePath(filename, true).data(), &sb));
|
||||
CHECK_SYSTEM(statSyscall(filename, &sb, true));
|
||||
return (int64_t)sb.st_mtime;
|
||||
}
|
||||
|
||||
Variant f_filectime(CStrRef filename) {
|
||||
struct stat sb;
|
||||
CHECK_SYSTEM(stat(File::TranslatePath(filename, true).data(), &sb));
|
||||
CHECK_SYSTEM(statSyscall(filename, &sb, true));
|
||||
return (int64_t)sb.st_ctime;
|
||||
}
|
||||
|
||||
Variant f_filetype(CStrRef filename) {
|
||||
struct stat sb;
|
||||
CHECK_SYSTEM(lstat(File::TranslatePath(filename).data(), &sb));
|
||||
CHECK_SYSTEM(lstatSyscall(filename, &sb));
|
||||
|
||||
switch (sb.st_mode & S_IFMT) {
|
||||
case S_IFLNK: return "link";
|
||||
@@ -650,16 +688,16 @@ Variant f_filetype(CStrRef filename) {
|
||||
|
||||
Variant f_linkinfo(CStrRef filename) {
|
||||
struct stat sb;
|
||||
CHECK_SYSTEM(stat(File::TranslatePath(filename).data(), &sb));
|
||||
CHECK_SYSTEM(statSyscall(filename, &sb));
|
||||
return (int64_t)sb.st_dev;
|
||||
}
|
||||
|
||||
bool f_is_writable(CStrRef filename) {
|
||||
struct stat sb;
|
||||
if (stat(File::TranslatePath(filename).data(), &sb)) {
|
||||
if (statSyscall(filename, &sb)) {
|
||||
return false;
|
||||
}
|
||||
CHECK_SYSTEM(access(File::TranslatePath(filename).data(), W_OK));
|
||||
CHECK_SYSTEM(accessSyscall(filename, W_OK));
|
||||
return true;
|
||||
/*
|
||||
int mask = S_IWOTH;
|
||||
@@ -691,8 +729,8 @@ bool f_is_writeable(CStrRef filename) {
|
||||
|
||||
bool f_is_readable(CStrRef filename) {
|
||||
struct stat sb;
|
||||
CHECK_SYSTEM(stat(File::TranslatePath(filename, true).data(), &sb));
|
||||
CHECK_SYSTEM(access(File::TranslatePath(filename, true).data(), R_OK));
|
||||
CHECK_SYSTEM(statSyscall(filename, &sb, true));
|
||||
CHECK_SYSTEM(accessSyscall(filename, R_OK, true));
|
||||
return true;
|
||||
/*
|
||||
int mask = S_IROTH;
|
||||
@@ -720,8 +758,8 @@ bool f_is_readable(CStrRef filename) {
|
||||
|
||||
bool f_is_executable(CStrRef filename) {
|
||||
struct stat sb;
|
||||
CHECK_SYSTEM(stat(File::TranslatePath(filename).data(), &sb));
|
||||
CHECK_SYSTEM(access(File::TranslatePath(filename).data(), X_OK));
|
||||
CHECK_SYSTEM(statSyscall(filename, &sb));
|
||||
CHECK_SYSTEM(accessSyscall(filename, X_OK));
|
||||
return true;
|
||||
/*
|
||||
int mask = S_IXOTH;
|
||||
@@ -749,7 +787,7 @@ bool f_is_executable(CStrRef filename) {
|
||||
|
||||
bool f_is_file(CStrRef filename) {
|
||||
struct stat sb;
|
||||
CHECK_SYSTEM(stat(File::TranslatePath(filename, true).data(), &sb));
|
||||
CHECK_SYSTEM(statSyscall(filename, &sb, true));
|
||||
return (sb.st_mode & S_IFMT) == S_IFREG;
|
||||
}
|
||||
|
||||
@@ -767,13 +805,13 @@ bool f_is_dir(CStrRef filename) {
|
||||
}
|
||||
|
||||
struct stat sb;
|
||||
CHECK_SYSTEM(stat(File::TranslatePath(filename).data(), &sb));
|
||||
CHECK_SYSTEM(statSyscall(filename, &sb));
|
||||
return (sb.st_mode & S_IFMT) == S_IFDIR;
|
||||
}
|
||||
|
||||
bool f_is_link(CStrRef filename) {
|
||||
struct stat sb;
|
||||
CHECK_SYSTEM(lstat(File::TranslatePath(filename).data(), &sb));
|
||||
CHECK_SYSTEM(lstatSyscall(filename, &sb));
|
||||
return (sb.st_mode & S_IFMT) == S_IFLNK;
|
||||
}
|
||||
|
||||
@@ -787,7 +825,7 @@ bool f_is_uploaded_file(CStrRef filename) {
|
||||
|
||||
bool f_file_exists(CStrRef filename) {
|
||||
if (filename.empty() ||
|
||||
(access(File::TranslatePath(filename, true).data(), F_OK)) < 0) {
|
||||
(accessSyscall(filename, F_OK, true)) < 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -795,13 +833,13 @@ bool f_file_exists(CStrRef filename) {
|
||||
|
||||
Variant f_stat(CStrRef filename) {
|
||||
struct stat sb;
|
||||
CHECK_SYSTEM(stat(File::TranslatePath(filename, true).data(), &sb));
|
||||
CHECK_SYSTEM(statSyscall(filename, &sb, true));
|
||||
return stat_impl(&sb);
|
||||
}
|
||||
|
||||
Variant f_lstat(CStrRef filename) {
|
||||
struct stat sb;
|
||||
CHECK_SYSTEM(lstat(File::TranslatePath(filename, true).data(), &sb));
|
||||
CHECK_SYSTEM(lstatSyscall(filename, &sb, true));
|
||||
return stat_impl(&sb);
|
||||
}
|
||||
|
||||
@@ -837,7 +875,7 @@ Variant f_realpath(CStrRef path) {
|
||||
StaticContentCache::TheFileCache->exists(translated.data(), false)) {
|
||||
return translated;
|
||||
}
|
||||
if (access(translated.c_str(), F_OK) == 0) {
|
||||
if (accessSyscall(path, F_OK) == 0) {
|
||||
char resolved_path[PATH_MAX];
|
||||
if (!realpath(translated.c_str(), resolved_path)) {
|
||||
return false;
|
||||
@@ -1005,7 +1043,7 @@ bool f_touch(CStrRef filename, int64_t mtime /* = 0 */, int64_t atime /* = 0 */)
|
||||
String translated = File::TranslatePath(filename);
|
||||
|
||||
/* create the file if it doesn't exist already */
|
||||
if (access(translated.data(), F_OK)) {
|
||||
if (accessSyscall(translated, F_OK)) {
|
||||
FILE *f = fopen(translated.data(), "w");
|
||||
if (f == NULL) {
|
||||
Logger::Verbose("%s/%d: Unable to create file %s because %s",
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário