bool UserFile::chmod(const String& path, int64_t mode) { return invokeMetadata( PackedArrayInit(3) .append(path) .append(6) // STREAM_META_ACCESS .append(mode) .toArray(), "chmod"); }
bool EventHook::RunInterceptHandler(ActRec* ar) { const Func* func = ar->m_func; if (LIKELY(func->maybeIntercepted() == 0)) return true; // Intercept only original generator / async function calls, not resumption. if (ar->inGenerator()) return true; Variant *h = get_intercept_handler(func->fullNameRef(), &func->maybeIntercepted()); if (!h) return true; JIT::VMRegAnchor _; PC savePc = g_context->m_pc; Variant doneFlag = true; Variant called_on; if (ar->hasThis()) { called_on = Variant(ar->getThis()); } else if (ar->hasClass()) { // For static methods, give handler the name of called class called_on = Variant(const_cast<StringData*>(ar->getClass()->name())); } Variant intArgs = PackedArrayInit(5) .append(ar->m_func->fullNameRef()) .append(called_on) .append(get_frame_args_with_ref(ar)) .append(h->asCArrRef()[1]) .appendRef(doneFlag) .toArray(); Variant ret = vm_call_user_func(h->asCArrRef()[0], intArgs); if (doneFlag.toBoolean()) { Offset pcOff; ActRec* outer = g_context->getPrevVMState(ar, &pcOff); frame_free_locals_inl_no_hook<true>(ar, ar->m_func->numLocals()); Stack& stack = g_context->getStack(); stack.top() = (Cell*)(ar + 1); cellDup(*ret.asCell(), *stack.allocTV()); g_context->m_fp = outer; g_context->m_pc = outer ? outer->m_func->unit()->at(pcOff) : nullptr; return false; } g_context->m_fp = ar; g_context->m_pc = savePc; return true; }
bool UserFile::touch(const String& path, int64_t mtime, int64_t atime) { if (atime == 0) { atime = mtime; } return invokeMetadata( PackedArrayInit(3) .append(path) .append(1) // STREAM_META_TOUCH .append(atime ? make_packed_array(mtime, atime) : Array::Create()) .toArray(), "touch"); }
bool UserFile::unlink(const String& filename) { // bool unlink($path) bool invoked = false; Variant ret = invoke( m_Unlink, s_unlink, PackedArrayInit(1) .append(filename) .toArray(), invoked ); if (invoked && (ret.toBoolean() == true)) { return true; } return false; }
bool UserFile::unlink(const String& filename) { // bool unlink($path) bool invoked = false; Variant ret = invoke( m_Unlink, s_unlink, PackedArrayInit(1) .append(filename) .toArray(), invoked ); if (invoked && (ret.toBoolean() == true)) { return true; } raise_warning("\"%s::unlink\" call failed", m_cls->name()->data()); return false; }
bool UserFile::rmdir(const String& filename, int options) { // bool rmdir($path, $options) bool invoked = false; Variant ret = invoke( m_Rmdir, s_rmdir, PackedArrayInit(2) .append(filename) .append(options) .toArray(), invoked ); if (invoked && (ret.toBoolean() == true)) { return true; } return false; }
bool UserFile::rename(const String& oldname, const String& newname) { // bool rename($oldname, $newname); bool invoked = false; Variant ret = invoke( m_Rename, s_rename, PackedArrayInit(2) .append(oldname) .append(newname) .toArray(), invoked ); if (invoked && (ret.toBoolean() == true)) { return true; } return false; }
bool UserFile::rmdir(const String& filename, int options) { // bool rmdir($path, $options) bool invoked = false; Variant ret = invoke( m_Rmdir, s_rmdir, PackedArrayInit(2) .append(filename) .append(options) .toArray(), invoked ); if (invoked && (ret.toBoolean() == true)) { return true; } raise_warning("\"%s::rmdir\" call failed", m_cls->name()->data()); return false; }
bool UserFile::rename(const String& oldname, const String& newname) { // bool rename($oldname, $newname); bool invoked = false; Variant ret = invoke( m_Rename, s_rename, PackedArrayInit(2) .append(oldname) .append(newname) .toArray(), invoked ); if (invoked && (ret.toBoolean() == true)) { return true; } raise_warning("\"%s::rename\" call failed", m_cls->name()->data()); return false; }
Resource UserFile::invokeCast(int castas) { bool invoked = false; Variant ret = invoke( m_StreamCast, s_stream_cast, PackedArrayInit(1) .append(castas) .toArray(), invoked ); if (!invoked) { raise_warning( "%s::stream_cast is not implemented!", m_cls->name()->data() ); return Resource(); } if (ret.toBoolean() == false) { return Resource(); } auto f = dyn_cast_or_null<File>(ret); if (!f) { raise_warning( "%s::stream_cast must return a stream resource", m_cls->name()->data() ); return Resource(); } if (f == this) { raise_warning( "%s::stream_cast must not return itself", m_cls->name()->data() ); return Resource(); } return Resource(std::move(f)); }
bool UserFile::open(CStrRef filename, CStrRef mode) { // bool stream_open($path, $mode, $options, &$opened_path) bool success = false; Variant opened_path; Variant ret = invoke( m_StreamOpen, s_stream_open, PackedArrayInit(4) .append(filename) .append(mode) .append(m_options) .appendRef(opened_path) .toArray(), success ); if (success && (ret.toBoolean() == true)) { return true; } raise_warning("\"%s::stream_open\" call failed", m_cls->name()->data()); return false; }
bool UserFile::openImpl(const String& filename, const String& mode, int options) { // bool stream_open($path, $mode, $options, &$opened_path) bool invoked = false; Variant opened_path; Variant ret = invoke( m_StreamOpen, s_stream_open, PackedArrayInit(4) .append(filename) .append(mode) .append(options) .appendRef(opened_path) .toArray(), invoked ); if (invoked && (ret.toBoolean() == true)) { m_closed = false; return true; } raise_warning("\"%s::stream_open\" call failed", m_cls->name()->data()); return false; }
bool EventHook::RunInterceptHandler(ActRec* ar) { const Func* func = ar->func(); if (LIKELY(func->maybeIntercepted() == 0)) return true; // Intercept only original generator / async function calls, not resumption. if (ar->resumed()) return true; Variant* h = get_intercept_handler(func->fullNameStr(), &func->maybeIntercepted()); if (!h) return true; /* * In production mode, only functions that we have assumed can be * intercepted during static analysis should actually be * intercepted. */ if (RuntimeOption::RepoAuthoritative && !RuntimeOption::EvalJitEnableRenameFunction) { if (!(func->attrs() & AttrInterceptable)) { raise_error("fb_intercept was used on a non-interceptable function (%s) " "in RepoAuthoritative mode", func->fullName()->data()); } } VMRegAnchor _; PC savePc = vmpc(); Variant doneFlag = true; Variant called_on; if (ar->hasThis()) { called_on = Variant(ar->getThis()); } else if (ar->hasClass()) { // For static methods, give handler the name of called class called_on = Variant(const_cast<StringData*>(ar->getClass()->name())); } Variant intArgs = PackedArrayInit(5) .append(VarNR(ar->func()->fullName())) .append(called_on) .append(get_frame_args_with_ref(ar)) .append(h->asCArrRef()[1]) .appendRef(doneFlag) .toArray(); Variant ret = vm_call_user_func(h->asCArrRef()[0], intArgs); if (doneFlag.toBoolean()) { Offset pcOff; ActRec* outer = g_context->getPrevVMState(ar, &pcOff); frame_free_locals_inl_no_hook<true>(ar, ar->func()->numLocals()); Stack& stack = vmStack(); stack.top() = (Cell*)(ar + 1); cellDup(*ret.asCell(), *stack.allocTV()); vmfp() = outer; vmpc() = outer ? outer->func()->unit()->at(pcOff) : nullptr; return false; } vmfp() = ar; vmpc() = savePc; return true; }
/** * invokeHandler returns true if any autoload handlers were executed, * false otherwise. When this function returns true, it is the caller's * responsibility to check if the given class or interface exists. */ bool AutoloadHandler::invokeHandler(const String& className, bool forceSplStack /* = false */) { if (className.empty()) { return false; } if (!m_map.isNull()) { ClassExistsChecker ce; Result res = loadFromMap(className, s_class, true, ce); if (res == ContinueAutoloading) { if (ce(className)) return true; } else { if (res != Failure) return res == Success; } } // If we end up in a recursive autoload loop where we try to load the // same class twice, just fail the load to mimic PHP as many frameworks // rely on it unless we are forcing a restart (due to spl_autoload_call) // in which case autoload is allowed to be reentrant. if (!forceSplStack) { if (m_loading.exists(className)) { return false; } m_loading.add(className, className); } else { // We can still overflow the stack if there is a loop when using // spl_autoload_call directly, but this behavior matches the reference // implementation. m_loading.append(className); } // Make sure state is cleaned up from this load; autoloading of arbitrary // code below can throw SCOPE_EXIT { String l_className = m_loading.pop(); assert(l_className == className); }; Array params = PackedArrayInit(1).append(className).toArray(); if (!m_spl_stack_inited && !forceSplStack) { if (function_exists(s___autoload)) { invoke(s___autoload, params, -1, true, false); return true; } return false; } if (!m_spl_stack_inited || m_handlers.empty()) { return false; } Object autoloadException; for (const HandlerBundle& hb : m_handlers) { try { vm_call_user_func_cufiter(*hb.m_cufIter, params); } catch (Object& ex) { assert(ex.instanceof(SystemLib::s_ExceptionClass)); if (autoloadException.isNull()) { autoloadException = ex; } else { Object cur = ex; Variant next = cur->o_get(s_previous, false, s_exception); while (next.isObject()) { cur = next.toObject(); next = cur->o_get(s_previous, false, s_exception); } cur->o_set(s_previous, autoloadException, s_exception); autoloadException = ex; } } if (Unit::lookupClass(className.get()) != nullptr) { break; } } if (!autoloadException.isNull()) { throw autoloadException; } return true; }