Skip to content

Commit 7335ee2

Browse files
authored
[k2] support file_get_contents (#1592)
1 parent 8ce579e commit 7335ee2

3 files changed

Lines changed: 101 additions & 28 deletions

File tree

runtime-light/stdlib/file/file-system-functions.h

Lines changed: 8 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@
1616
#include <unistd.h>
1717
#include <utility>
1818

19-
#include "runtime-common/core/allocator/script-allocator.h"
2019
#include "runtime-common/core/runtime-core.h"
21-
#include "runtime-common/core/std/containers.h"
2220
#include "runtime-common/stdlib/array/array-functions.h"
2321
#include "runtime-common/stdlib/string/string-functions.h"
2422
#include "runtime-light/coroutine/task.h"
@@ -204,40 +202,24 @@ inline Optional<string> f$file_get_contents(const string& stream) noexcept {
204202
}
205203

206204
inline Optional<array<string>> f$file(const string& name) noexcept {
207-
struct stat stat_buf {};
208-
209-
auto expected_file{kphp::fs::file::open(name.c_str(), "r")};
205+
auto expected_file{kphp::fs::file::open({name.c_str(), name.size()}, "r")};
210206
if (!expected_file.has_value()) {
211207
return false;
212208
}
213-
if (!k2::stat({name.c_str(), name.size()}, std::addressof(stat_buf)).has_value()) {
214-
return false;
215-
}
216-
if (!S_ISREG(stat_buf.st_mode)) {
217-
kphp::log::warning("regular file expected as first argument in function file, \"{}\" is given", name.c_str());
218-
return false;
219-
}
220209

221-
const size_t size{static_cast<size_t>(stat_buf.st_size)};
222-
if (size > string::max_size()) {
223-
kphp::log::warning("file \"{}\" is too large", name.c_str());
210+
auto expected_file_content{std::move(*expected_file).get_contents()};
211+
if (!expected_file_content.has_value()) {
212+
kphp::log::warning("file::get_contents returned code {}", expected_file_content.error());
224213
return false;
225214
}
226-
227-
kphp::stl::vector<std::byte, kphp::memory::script_allocator> file_content;
228-
file_content.resize(size);
229-
{
230-
auto file{std::move(*expected_file)};
231-
if (auto expected_read_result{file.read(file_content)}; !expected_read_result.has_value() || *expected_read_result < size) {
232-
return false;
233-
}
234-
}
215+
auto file_content{std::move(*expected_file_content)};
216+
const size_t size{file_content.size()};
235217

236218
array<string> result;
237219
int32_t prev{-1};
238220
for (size_t i{0}; i < size; i++) {
239-
if (static_cast<char>(file_content[i]) == '\n' || i + 1 == size) {
240-
result.push_back(string{reinterpret_cast<char*>(file_content.data()) + prev + 1, static_cast<string::size_type>(i - prev)});
221+
if (file_content[i] == '\n' || i + 1 == size) {
222+
result.push_back(file_content.substr(prev + 1, static_cast<string::size_type>(i - prev)));
241223
prev = i;
242224
}
243225
}

runtime-light/stdlib/file/resource.h

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#include <memory>
1414
#include <span>
1515
#include <string_view>
16+
#include <sys/mman.h>
17+
#include <sys/stat.h>
1618
#include <tuple>
1719
#include <type_traits>
1820
#include <utility>
@@ -45,6 +47,73 @@ inline constexpr std::string_view UDP_SCHEME_PREFIX = "udp://";
4547

4648
// ================================================================================================
4749

50+
class mmap {
51+
k2::descriptor m_descriptor{k2::INVALID_PLATFORM_DESCRIPTOR};
52+
void* m_addr{nullptr};
53+
size_t m_length{};
54+
55+
mmap(k2::descriptor descriptor, void* addr, size_t length) noexcept
56+
: m_descriptor{descriptor},
57+
m_addr{addr},
58+
m_length{length} {}
59+
60+
public:
61+
mmap(mmap&& other) noexcept
62+
: m_descriptor{std::exchange(other.m_descriptor, k2::INVALID_PLATFORM_DESCRIPTOR)},
63+
m_addr{std::exchange(other.m_addr, nullptr)},
64+
m_length{std::exchange(other.m_length, {})} {}
65+
66+
mmap& operator=(mmap&& other) noexcept {
67+
if (this != std::addressof(other)) {
68+
std::ignore = close();
69+
m_descriptor = std::exchange(other.m_descriptor, k2::INVALID_PLATFORM_DESCRIPTOR);
70+
m_addr = std::exchange(other.m_addr, nullptr);
71+
m_length = std::exchange(other.m_length, {});
72+
}
73+
return *this;
74+
}
75+
76+
~mmap() {
77+
std::ignore = close();
78+
}
79+
80+
mmap(const mmap&) = delete;
81+
mmap& operator=(const mmap&) = delete;
82+
83+
static auto create(size_t length, int32_t prot, int32_t flags, k2::descriptor fd, uint64_t offset) noexcept -> std::expected<mmap, int32_t>;
84+
85+
auto madvise(int32_t advise) noexcept -> std::expected<void, int32_t>;
86+
auto data() const noexcept -> std::span<const std::byte>;
87+
auto close() noexcept -> std::expected<void, int32_t>;
88+
};
89+
90+
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> {
91+
k2::descriptor descriptor{k2::INVALID_PLATFORM_DESCRIPTOR};
92+
auto* addr{k2::mmap(std::addressof(descriptor), nullptr, length, prot, flags, fd, offset)};
93+
if (addr == MAP_FAILED) [[unlikely]] {
94+
return std::unexpected{k2::errno_efault};
95+
}
96+
return mmap{descriptor, addr, length};
97+
}
98+
99+
inline auto mmap::madvise(int32_t advise) noexcept -> std::expected<void, int32_t> {
100+
return k2::madvise(m_addr, m_length, advise);
101+
}
102+
103+
inline auto mmap::data() const noexcept -> std::span<const std::byte> {
104+
return {reinterpret_cast<const std::byte*>(m_addr), m_length};
105+
}
106+
107+
inline auto mmap::close() noexcept -> std::expected<void, int32_t> {
108+
if (m_descriptor == k2::INVALID_PLATFORM_DESCRIPTOR) [[unlikely]] {
109+
return std::unexpected{k2::errno_enodev};
110+
}
111+
k2::free_descriptor(std::exchange(m_descriptor, k2::INVALID_PLATFORM_DESCRIPTOR));
112+
return {};
113+
}
114+
115+
// ================================================================================================
116+
48117
struct resource : public refcountable_polymorphic_php_classes<may_be_mixed_base> {
49118
const char* get_class() const noexcept final {
50119
return "resource";
@@ -146,7 +215,29 @@ inline auto file::pread(std::span<std::byte> buf, uint64_t offset) noexcept -> s
146215
}
147216

148217
inline auto file::get_contents() noexcept -> std::expected<string, int32_t> {
149-
return std::unexpected{m_descriptor != k2::INVALID_PLATFORM_DESCRIPTOR ? k2::errno_efault : k2::errno_enodev};
218+
struct stat stat_buf {};
219+
220+
if (auto expected{k2::fstat(m_descriptor, std::addressof(stat_buf))}; !expected.has_value()) {
221+
return std::unexpected{expected.error()};
222+
}
223+
if (!S_ISREG(stat_buf.st_mode)) {
224+
return std::unexpected{k2::errno_einval};
225+
}
226+
227+
const size_t size{static_cast<size_t>(stat_buf.st_size)};
228+
if (size > string::max_size()) {
229+
return std::unexpected{k2::errno_erange};
230+
}
231+
232+
auto expected_mmap{kphp::fs::mmap::create(size, PROT_READ, MAP_PRIVATE | MAP_POPULATE, m_descriptor, 0)};
233+
if (!expected_mmap.has_value()) {
234+
return std::unexpected{expected_mmap.error()};
235+
}
236+
237+
auto& mmap{*expected_mmap};
238+
std::ignore = mmap.madvise(MADV_SEQUENTIAL);
239+
auto data{mmap.data()};
240+
return string{reinterpret_cast<const char*>(data.data()), static_cast<string::size_type>(data.size())};
150241
}
151242

152243
inline auto file::flush() noexcept -> std::expected<void, int32_t> {

tests/phpt/dl/464_gzip.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@ok k2_skip
1+
@ok
22
<?php
33
#ifndef KPHP
44
if(!function_exists('gzdecode')){

0 commit comments

Comments
 (0)