Add sub-controls for Hack array compat runtime checks
[hiphop-php.git] / hphp / runtime / base / file-stream-wrapper.cpp
blob0924347aeb0eb0f22aa592c2a4ec152058fd3313
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/runtime/base/file-stream-wrapper.h"
18 #include "hphp/runtime/base/unit-cache.h"
19 #include "hphp/runtime/base/runtime-error.h"
20 #include "hphp/runtime/base/plain-file.h"
21 #include "hphp/runtime/base/directory.h"
22 #include "hphp/runtime/server/static-content-cache.h"
23 #include "hphp/runtime/base/file-util.h"
24 #include "hphp/runtime/base/string-util.h"
25 #include "hphp/runtime/ext/stream/ext_stream.h"
27 #include <boost/filesystem/operations.hpp>
29 #include <memory>
31 #include <folly/portability/Stdlib.h>
32 #include <folly/portability/SysStat.h>
34 namespace HPHP {
35 ///////////////////////////////////////////////////////////////////////////////
37 req::ptr<MemFile> FileStreamWrapper::openFromCache(const String& filename,
38 const String& mode) {
39 if (!StaticContentCache::TheFileCache) {
40 return nullptr;
43 String relative =
44 FileCache::GetRelativePath(File::TranslatePath(filename).c_str());
45 auto file = req::make<MemFile>();
46 bool ret = file->open(relative, mode);
47 if (ret) {
48 return file;
50 return nullptr;
53 req::ptr<File>
54 FileStreamWrapper::open(const String& filename, const String& mode, int options,
55 const req::ptr<StreamContext>& /*context*/) {
56 String fname;
57 if (StringUtil::IsFileUrl(filename)) {
58 fname = StringUtil::DecodeFileUrl(filename);
59 if (fname.empty()) {
60 raise_warning("invalid file:// URL");
61 return nullptr;
63 } else {
64 fname = filename;
67 if (auto file = openFromCache(fname, mode)) {
68 return file;
71 if (options & File::USE_INCLUDE_PATH) {
72 struct stat s;
73 String resolved_fname = resolveVmInclude(fname.get(), "", &s);
74 if (!resolved_fname.isNull()) {
75 fname = resolved_fname;
79 auto file = req::make<PlainFile>();
80 bool ret = file->open(File::TranslatePath(fname), mode);
81 if (!ret) {
82 raise_warning("%s", file->getLastError().c_str());
83 return nullptr;
85 return file;
88 req::ptr<Directory> FileStreamWrapper::opendir(const String& path) {
89 auto tpath = File::TranslatePath(path);
90 if (File::IsVirtualDirectory(tpath)) {
91 return req::make<CachedDirectory>(tpath);
94 auto dir = req::make<PlainDirectory>(tpath);
95 if (!dir->isValid()) {
96 raise_warning("%s", dir->getLastError().c_str());
97 return nullptr;
99 return dir;
102 int FileStreamWrapper::unlink(const String& path) {
103 int ret = ::unlink(File::TranslatePath(path).data());
104 if (ret != 0) {
105 raise_warning(
106 "%s(%s): %s",
107 __FUNCTION__,
108 path.c_str(),
109 folly::errnoStr(errno).c_str()
112 return ret;
115 int FileStreamWrapper::rename(const String& oldname, const String& newname) {
116 int ret =
117 RuntimeOption::UseDirectCopy ?
118 FileUtil::directRename(File::TranslatePath(oldname).data(),
119 File::TranslatePath(newname).data())
121 FileUtil::rename(File::TranslatePath(oldname).data(),
122 File::TranslatePath(newname).data());
123 return ret;
126 int FileStreamWrapper::mkdir(const String& path, int mode, int options) {
127 if (options & k_STREAM_MKDIR_RECURSIVE) {
128 ERROR_RAISE_WARNING(mkdir_recursive(path, mode));
129 return ret;
131 ERROR_RAISE_WARNING(::mkdir(File::TranslatePath(path).data(), mode));
132 return ret;
135 int FileStreamWrapper::mkdir_recursive(const String& path, int mode) {
136 String fullpath = File::TranslatePath(path);
137 if (fullpath.size() > PATH_MAX) {
138 errno = ENAMETOOLONG;
139 return -1;
142 // Check first if the whole path exists
143 if (access(fullpath.data(), F_OK) >= 0) {
144 errno = EEXIST;
145 return -1;
148 char dir[PATH_MAX+1];
149 char *p;
150 strncpy(dir, fullpath.data(), sizeof(dir));
152 for (p = dir + 1; *p; p++) {
153 if (FileUtil::isDirSeparator(*p)) {
154 *p = '\0';
155 if (::access(dir, F_OK) < 0) {
156 if (::mkdir(dir, mode) < 0) {
157 return -1;
160 *p = FileUtil::getDirSeparator();
164 if (::access(dir, F_OK) < 0) {
165 if (::mkdir(dir, mode) < 0) {
166 return -1;
170 return 0;
173 ///////////////////////////////////////////////////////////////////////////////