Example #1
0
bool UserFile::chmod(const String& path, int64_t mode) {
  return invokeMetadata(
    PackedArrayInit(3)
      .append(path)
      .append(6) // STREAM_META_ACCESS
      .append(mode)
      .toArray(),
    "chmod");
}
Example #2
0
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;
}
Example #3
0
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");
}
Example #4
0
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;
}
Example #5
0
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;
}
Example #6
0
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;
}
Example #7
0
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;
}
Example #8
0
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;
}
Example #9
0
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;
}
Example #10
0
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));
}
Example #11
0
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;
}
Example #12
0
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;
}
Example #13
0
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;
}
Example #14
0
/**
 * 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;
}