Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 8 additions & 26 deletions runtime-light/stdlib/file/file-system-functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@
#include <unistd.h>
#include <utility>

#include "runtime-common/core/allocator/script-allocator.h"
#include "runtime-common/core/runtime-core.h"
#include "runtime-common/core/std/containers.h"
#include "runtime-common/stdlib/array/array-functions.h"
#include "runtime-common/stdlib/string/string-functions.h"
#include "runtime-light/coroutine/task.h"
Expand Down Expand Up @@ -204,40 +202,24 @@ inline Optional<string> f$file_get_contents(const string& stream) noexcept {
}

inline Optional<array<string>> f$file(const string& name) noexcept {
struct stat stat_buf {};

auto expected_file{kphp::fs::file::open(name.c_str(), "r")};
auto expected_file{kphp::fs::file::open({name.c_str(), name.size()}, "r")};
if (!expected_file.has_value()) {
return false;
}
if (!k2::stat({name.c_str(), name.size()}, std::addressof(stat_buf)).has_value()) {
return false;
}
if (!S_ISREG(stat_buf.st_mode)) {
kphp::log::warning("regular file expected as first argument in function file, \"{}\" is given", name.c_str());
return false;
}

const size_t size{static_cast<size_t>(stat_buf.st_size)};
if (size > string::max_size()) {
kphp::log::warning("file \"{}\" is too large", name.c_str());
auto expected_file_content{std::move(*expected_file).get_contents()};
if (!expected_file_content.has_value()) {
kphp::log::warning("file::get_contents returned code {}", expected_file_content.error());
return false;
}

kphp::stl::vector<std::byte, kphp::memory::script_allocator> file_content;
file_content.resize(size);
{
auto file{std::move(*expected_file)};
if (auto expected_read_result{file.read(file_content)}; !expected_read_result.has_value() || *expected_read_result < size) {
return false;
}
}
auto file_content{std::move(*expected_file_content)};
const size_t size{file_content.size()};

array<string> result;
int32_t prev{-1};
for (size_t i{0}; i < size; i++) {
if (static_cast<char>(file_content[i]) == '\n' || i + 1 == size) {
result.push_back(string{reinterpret_cast<char*>(file_content.data()) + prev + 1, static_cast<string::size_type>(i - prev)});
if (file_content[i] == '\n' || i + 1 == size) {
result.push_back(file_content.substr(prev + 1, static_cast<string::size_type>(i - prev)));
prev = i;
}
}
Expand Down
93 changes: 92 additions & 1 deletion runtime-light/stdlib/file/resource.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include <memory>
#include <span>
#include <string_view>
#include <sys/mman.h>
#include <sys/stat.h>
#include <tuple>
#include <type_traits>
#include <utility>
Expand Down Expand Up @@ -45,6 +47,73 @@ inline constexpr std::string_view UDP_SCHEME_PREFIX = "udp://";

// ================================================================================================

class mmap {
k2::descriptor m_descriptor{k2::INVALID_PLATFORM_DESCRIPTOR};
void* m_addr{nullptr};
size_t m_length{};

mmap(k2::descriptor descriptor, void* addr, size_t length) noexcept
: m_descriptor{descriptor},
m_addr{addr},
m_length{length} {}

public:
mmap(mmap&& other) noexcept
: m_descriptor{std::exchange(other.m_descriptor, k2::INVALID_PLATFORM_DESCRIPTOR)},
m_addr{std::exchange(other.m_addr, nullptr)},
m_length{std::exchange(other.m_length, {})} {}

mmap& operator=(mmap&& other) noexcept {
if (this != std::addressof(other)) {
std::ignore = close();
m_descriptor = std::exchange(other.m_descriptor, k2::INVALID_PLATFORM_DESCRIPTOR);
m_addr = std::exchange(other.m_addr, nullptr);
m_length = std::exchange(other.m_length, {});
}
return *this;
}

~mmap() {
std::ignore = close();
}

mmap(const mmap&) = delete;
mmap& operator=(const mmap&) = delete;

static auto create(size_t length, int32_t prot, int32_t flags, k2::descriptor fd, uint64_t offset) noexcept -> std::expected<mmap, int32_t>;

auto madvise(int32_t advise) noexcept -> std::expected<void, int32_t>;
auto data() const noexcept -> std::span<const std::byte>;
auto close() noexcept -> std::expected<void, int32_t>;
};

inline auto mmap::create(size_t length, int32_t prot, int32_t flags, k2::descriptor fd, uint64_t offset) noexcept -> std::expected<mmap, int32_t> {
k2::descriptor descriptor{k2::INVALID_PLATFORM_DESCRIPTOR};
auto* addr{k2::mmap(std::addressof(descriptor), nullptr, length, prot, flags, fd, offset)};
if (addr == MAP_FAILED) [[unlikely]] {
return std::unexpected{k2::errno_efault};
}
return mmap{descriptor, addr, length};
}

inline auto mmap::madvise(int32_t advise) noexcept -> std::expected<void, int32_t> {
return k2::madvise(m_addr, m_length, advise);
}

inline auto mmap::data() const noexcept -> std::span<const std::byte> {
return {reinterpret_cast<const std::byte*>(m_addr), m_length};
}

inline auto mmap::close() noexcept -> std::expected<void, int32_t> {
if (m_descriptor == k2::INVALID_PLATFORM_DESCRIPTOR) [[unlikely]] {
return std::unexpected{k2::errno_enodev};
}
k2::free_descriptor(std::exchange(m_descriptor, k2::INVALID_PLATFORM_DESCRIPTOR));
return {};
}

// ================================================================================================

struct resource : public refcountable_polymorphic_php_classes<may_be_mixed_base> {
const char* get_class() const noexcept final {
return "resource";
Expand Down Expand Up @@ -146,7 +215,29 @@ inline auto file::pread(std::span<std::byte> buf, uint64_t offset) noexcept -> s
}

inline auto file::get_contents() noexcept -> std::expected<string, int32_t> {
return std::unexpected{m_descriptor != k2::INVALID_PLATFORM_DESCRIPTOR ? k2::errno_efault : k2::errno_enodev};
struct stat stat_buf {};

if (auto expected{k2::fstat(m_descriptor, std::addressof(stat_buf))}; !expected.has_value()) {
return std::unexpected{expected.error()};
}
if (!S_ISREG(stat_buf.st_mode)) {
return std::unexpected{k2::errno_einval};
}

const size_t size{static_cast<size_t>(stat_buf.st_size)};
if (size > string::max_size()) {
return std::unexpected{k2::errno_erange};
}

auto expected_mmap{kphp::fs::mmap::create(size, PROT_READ, MAP_PRIVATE | MAP_POPULATE, m_descriptor, 0)};
if (!expected_mmap.has_value()) {
return std::unexpected{expected_mmap.error()};
}

auto& mmap{*expected_mmap};
std::ignore = mmap.madvise(MADV_SEQUENTIAL);
auto data{mmap.data()};
return string{reinterpret_cast<const char*>(data.data()), static_cast<string::size_type>(data.size())};
}

inline auto file::flush() noexcept -> std::expected<void, int32_t> {
Expand Down
2 changes: 1 addition & 1 deletion tests/phpt/dl/464_gzip.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@ok k2_skip
@ok
<?php
#ifndef KPHP
if(!function_exists('gzdecode')){
Expand Down
Loading