From 21b4af305e198921cb82fcc57412f4b7fceb42dc Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Tue, 9 Dec 2025 15:48:28 +0300 Subject: [PATCH 01/17] add builtin --- .../stdlib/file/file-system-functions.h | 46 ++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/runtime-light/stdlib/file/file-system-functions.h b/runtime-light/stdlib/file/file-system-functions.h index 700d73f0f9..1680b0c92d 100644 --- a/runtime-light/stdlib/file/file-system-functions.h +++ b/runtime-light/stdlib/file/file-system-functions.h @@ -58,7 +58,7 @@ inline string f$basename(const string& path, const string& suffix = {}) noexcept } inline Optional f$filesize(const string& filename) noexcept { - struct stat stat {}; + struct stat stat{}; if (auto errc{k2::stat({filename.c_str(), filename.size()}, std::addressof(stat))}; errc != k2::errno_ok) [[unlikely]] { return false; } @@ -197,3 +197,47 @@ inline Optional f$file_get_contents(const string& stream) noexcept { } return false; } + +inline Optional> f$file(const string& name) noexcept { + struct stat stat_buf; + uint64_t file_fd; + + if (!k2::fopen(std::addressof(file_fd), name.c_str(), "r")) { + return false; + } + if (!k2::stat(name.c_str(), std::addressof(stat_buf))) { + k2::free_descriptor(file_fd); + return false; + } + if (!S_ISREG(stat_buf.st_mode)) { + k2::free_descriptor(file_fd); + 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(stat_buf.st_size)}; + if (size > string::max_size()) { + k2::free_descriptor(file_fd); + kphp::log::warning("file \"{}\" is too large", name.c_str()); + return false; + } + + string res(static_cast(size), false); + char* s{res.buffer()}; + if (k2::read(file_fd, size, s) < size) { + k2::free_descriptor(file_fd); + return false; + } + k2::free_descriptor(file_fd); + + array result; + int prev{-1}; + for (size_t i = 0; i < size; i++) { + if (s[i] == '\n' || i + 1 == size) { + result.push_back(string(s + prev + 1, i - prev)); + prev = i; + } + } + + return result; +} From 7e05b177acae83dcad17e4d55879083fa9a1b8c2 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Tue, 9 Dec 2025 16:14:01 +0300 Subject: [PATCH 02/17] minorfix --- builtin-functions/kphp-light/stdlib/file-functions.txt | 5 ++--- runtime-light/stdlib/file/file-system-functions.h | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/builtin-functions/kphp-light/stdlib/file-functions.txt b/builtin-functions/kphp-light/stdlib/file-functions.txt index 334aec33d2..5a8d6d89ff 100644 --- a/builtin-functions/kphp-light/stdlib/file-functions.txt +++ b/builtin-functions/kphp-light/stdlib/file-functions.txt @@ -40,8 +40,9 @@ function vsprintf ($format ::: string, $args ::: array) ::: string; function file_exists ($name ::: string) ::: bool; -// === UNSUPPORTED === +function file ($name ::: string) ::: string[] | false; +// === UNSUPPORTED === /** @kphp-extern-func-info stub generation-required */ function chmod ($name ::: string, $mode ::: int) ::: bool; /** @kphp-extern-func-info stub generation-required */ @@ -49,8 +50,6 @@ function copy ($from ::: string, $to ::: string) ::: bool; /** @kphp-extern-func-info stub generation-required */ function dirname ($name ::: string) ::: string; /** @kphp-extern-func-info stub generation-required */ -function file ($name ::: string) ::: string[] | false; -/** @kphp-extern-func-info stub generation-required */ function file_put_contents ($name ::: string, $content ::: mixed, $flags ::: int = 0) ::: int | false; /** @kphp-extern-func-info stub generation-required */ function filectime ($name ::: string) ::: int | false; diff --git a/runtime-light/stdlib/file/file-system-functions.h b/runtime-light/stdlib/file/file-system-functions.h index 1680b0c92d..e0a6d45ad1 100644 --- a/runtime-light/stdlib/file/file-system-functions.h +++ b/runtime-light/stdlib/file/file-system-functions.h @@ -202,10 +202,10 @@ inline Optional> f$file(const string& name) noexcept { struct stat stat_buf; uint64_t file_fd; - if (!k2::fopen(std::addressof(file_fd), name.c_str(), "r")) { + if (k2::fopen(std::addressof(file_fd), name.c_str(), "r")) { return false; } - if (!k2::stat(name.c_str(), std::addressof(stat_buf))) { + if (k2::stat(name.c_str(), std::addressof(stat_buf))) { k2::free_descriptor(file_fd); return false; } From 45624545cb402c6c0ce00723cba3020f9b3cf3d7 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Tue, 9 Dec 2025 16:16:08 +0300 Subject: [PATCH 03/17] minor fix --- runtime-light/stdlib/file/file-system-functions.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime-light/stdlib/file/file-system-functions.h b/runtime-light/stdlib/file/file-system-functions.h index e0a6d45ad1..26f8347dc7 100644 --- a/runtime-light/stdlib/file/file-system-functions.h +++ b/runtime-light/stdlib/file/file-system-functions.h @@ -58,7 +58,7 @@ inline string f$basename(const string& path, const string& suffix = {}) noexcept } inline Optional f$filesize(const string& filename) noexcept { - struct stat stat{}; + struct stat stat {}; if (auto errc{k2::stat({filename.c_str(), filename.size()}, std::addressof(stat))}; errc != k2::errno_ok) [[unlikely]] { return false; } From b764b8dfab7341c2eaf78b3643461331d1483b79 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Tue, 9 Dec 2025 18:38:10 +0300 Subject: [PATCH 04/17] minifix --- runtime-light/stdlib/file/file-system-functions.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime-light/stdlib/file/file-system-functions.h b/runtime-light/stdlib/file/file-system-functions.h index 26f8347dc7..332bc5dd46 100644 --- a/runtime-light/stdlib/file/file-system-functions.h +++ b/runtime-light/stdlib/file/file-system-functions.h @@ -202,10 +202,10 @@ inline Optional> f$file(const string& name) noexcept { struct stat stat_buf; uint64_t file_fd; - if (k2::fopen(std::addressof(file_fd), name.c_str(), "r")) { + if (k2::fopen(std::addressof(file_fd), name.c_str(), "r") != k2::errno_ok) { return false; } - if (k2::stat(name.c_str(), std::addressof(stat_buf))) { + if (k2::stat(name.c_str(), std::addressof(stat_buf)) != k2::errno_ok) { k2::free_descriptor(file_fd); return false; } From 6471b4a679a07e835f7d586e09e75e9af03240cc Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Wed, 10 Dec 2025 15:49:36 +0300 Subject: [PATCH 05/17] add is_file, add k2_lstat --- .../kphp-light/stdlib/file-functions.txt | 4 ++-- runtime-light/k2-platform/k2-api.h | 7 ++++++ runtime-light/k2-platform/k2-header.h | 23 +++++++++++++++++++ .../stdlib/file/file-system-functions.h | 8 +++++++ 4 files changed, 40 insertions(+), 2 deletions(-) diff --git a/builtin-functions/kphp-light/stdlib/file-functions.txt b/builtin-functions/kphp-light/stdlib/file-functions.txt index 5a8d6d89ff..e7398871ee 100644 --- a/builtin-functions/kphp-light/stdlib/file-functions.txt +++ b/builtin-functions/kphp-light/stdlib/file-functions.txt @@ -42,6 +42,8 @@ function file_exists ($name ::: string) ::: bool; function file ($name ::: string) ::: string[] | false; +function is_file ($name ::: string) ::: bool; + // === UNSUPPORTED === /** @kphp-extern-func-info stub generation-required */ function chmod ($name ::: string, $mode ::: int) ::: bool; @@ -58,8 +60,6 @@ function filemtime ($name ::: string) ::: int | false; /** @kphp-extern-func-info stub generation-required */ function is_dir ($name ::: string) ::: bool; /** @kphp-extern-func-info stub generation-required */ -function is_file ($name ::: string) ::: bool; -/** @kphp-extern-func-info stub generation-required */ function is_readable ($name ::: string) ::: bool; /** @kphp-extern-func-info stub generation-required */ function mkdir ($name ::: string, $mode ::: int = 0777, $recursive ::: bool = false) ::: bool; diff --git a/runtime-light/k2-platform/k2-api.h b/runtime-light/k2-platform/k2-api.h index 95d189ae71..4ed2124ac6 100644 --- a/runtime-light/k2-platform/k2-api.h +++ b/runtime-light/k2-platform/k2-api.h @@ -418,6 +418,13 @@ inline int32_t stat(std::string_view path, struct stat* stat) noexcept { return k2::errno_ok; } +inline int32_t lstat(std::string_view path, struct stat* stat) noexcept { + if (auto error_code{k2_lstat(path.data(), path.size(), stat)}; error_code != k2::errno_ok) [[unlikely]] { + return error_code; + } + return k2::errno_ok; +} + using CommandArg = CommandArg; enum class CommandStdoutPolicy : uint8_t { NoCapture, Capture }; diff --git a/runtime-light/k2-platform/k2-header.h b/runtime-light/k2-platform/k2-header.h index 9a73d202f7..bb0bae3ee9 100644 --- a/runtime-light/k2-platform/k2-header.h +++ b/runtime-light/k2-platform/k2-header.h @@ -735,6 +735,29 @@ int32_t k2_canonicalize(const char* path, size_t pathlen, char* const* resolved_ */ int32_t k2_stat(const char* pathname, size_t pathname_len, struct stat* statbuf); + /** + * Semantically equivalent to libc's `lstat`. + * + * Possible `errno`: + * `EACCES` => Search permission is denied for one of the directories in the path prefix of `pathname`. + * `EINVAL` => `pathname` or `statbuf` is `NULL`. + * `EFAULT` => Bad address. + * `ELOOP` => Too many symbolic links encountered while traversing the path. + * `ENAMETOOLONG` => `pathname` is too long. + * `ENOENT` => A component of `pathname` does not exist or is a dangling symbolic link. + * `ENOMEM` => Out of memory (i.e., kernel memory). + * `ENOTDIR` => A component of the path prefix of `pathname` is not a directory. + * `EOVERFLOW` => `pathname` refers to a file whose size, inode number, + * or number of blocks cannot be represented in, respectively, + * the types `off_t`, `ino_t`, or `blkcnt_t`. This error can occur + * when, for example, an application compiled on a 32-bit + * platform without `-D_FILE_OFFSET_BITS=64` calls `lstat()` on a + * file whose size exceeds `(1<<31)-1` bytes. + * `ERANGE` => Failed to convert `st_size`, `st_blksize`, or `st_blocks` to `int64_t`. + * `ENOSYS` => Internal error. + */ +int32_t k2_lstat(const char* pathname, size_t pathname_len, struct stat* statbuf); + struct CommandArg { const char* arg; size_t arg_len; diff --git a/runtime-light/stdlib/file/file-system-functions.h b/runtime-light/stdlib/file/file-system-functions.h index 332bc5dd46..ea6e780c9e 100644 --- a/runtime-light/stdlib/file/file-system-functions.h +++ b/runtime-light/stdlib/file/file-system-functions.h @@ -241,3 +241,11 @@ inline Optional> f$file(const string& name) noexcept { return result; } + +inline bool f$is_file(const string& name) noexcept { + struct stat stat_buf; + if (k2::lstat(name.c_str(), &stat_buf) != k2::errno_ok) { + return false; + } + return S_ISREG(stat_buf.st_mode); +} From 3c97c797579de386265bb2142bc7ffaca1d864b2 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Wed, 10 Dec 2025 15:51:22 +0300 Subject: [PATCH 06/17] minor fix --- runtime-light/k2-platform/k2-header.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime-light/k2-platform/k2-header.h b/runtime-light/k2-platform/k2-header.h index bb0bae3ee9..e64067f360 100644 --- a/runtime-light/k2-platform/k2-header.h +++ b/runtime-light/k2-platform/k2-header.h @@ -735,7 +735,7 @@ int32_t k2_canonicalize(const char* path, size_t pathlen, char* const* resolved_ */ int32_t k2_stat(const char* pathname, size_t pathname_len, struct stat* statbuf); - /** +/** * Semantically equivalent to libc's `lstat`. * * Possible `errno`: From 879e148d05a3666a1e0d3d5cb43bf713eadf60fa Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Wed, 10 Dec 2025 15:56:26 +0300 Subject: [PATCH 07/17] minor fix --- runtime-light/stdlib/file/file-system-functions.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime-light/stdlib/file/file-system-functions.h b/runtime-light/stdlib/file/file-system-functions.h index ea6e780c9e..df3772d9e9 100644 --- a/runtime-light/stdlib/file/file-system-functions.h +++ b/runtime-light/stdlib/file/file-system-functions.h @@ -244,7 +244,7 @@ inline Optional> f$file(const string& name) noexcept { inline bool f$is_file(const string& name) noexcept { struct stat stat_buf; - if (k2::lstat(name.c_str(), &stat_buf) != k2::errno_ok) { + if (k2::lstat(name.c_str(), std::addressof(stat_buf)) != k2::errno_ok) { return false; } return S_ISREG(stat_buf.st_mode); From e643a877a42ca0fe4ba51ccd0253b193376f20aa Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Thu, 11 Dec 2025 17:53:16 +0300 Subject: [PATCH 08/17] minor fix --- .../stdlib/file/file-system-functions.h | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/runtime-light/stdlib/file/file-system-functions.h b/runtime-light/stdlib/file/file-system-functions.h index df3772d9e9..ebca02ffcf 100644 --- a/runtime-light/stdlib/file/file-system-functions.h +++ b/runtime-light/stdlib/file/file-system-functions.h @@ -200,41 +200,41 @@ inline Optional f$file_get_contents(const string& stream) noexcept { inline Optional> f$file(const string& name) noexcept { struct stat stat_buf; - uint64_t file_fd; - if (k2::fopen(std::addressof(file_fd), name.c_str(), "r") != k2::errno_ok) { + auto open_res = kphp::fs::file::open(name.c_str(), "r"); + if (!open_res.has_value()) { return false; } + auto& file = open_res.value(); + if (k2::stat(name.c_str(), std::addressof(stat_buf)) != k2::errno_ok) { - k2::free_descriptor(file_fd); return false; } if (!S_ISREG(stat_buf.st_mode)) { - k2::free_descriptor(file_fd); 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(stat_buf.st_size)}; if (size > string::max_size()) { - k2::free_descriptor(file_fd); kphp::log::warning("file \"{}\" is too large", name.c_str()); return false; } - string res(static_cast(size), false); - char* s{res.buffer()}; - if (k2::read(file_fd, size, s) < size) { - k2::free_descriptor(file_fd); + string res{static_cast(size), false}; + char* res_buffer{res.buffer()}; + std::span spn{reinterpret_cast(res_buffer), res.size()}; + if (auto rd_status = file.read(spn); !rd_status.has_value() || rd_status.value() < size) { return false; } - k2::free_descriptor(file_fd); + + file.close(); array result; - int prev{-1}; - for (size_t i = 0; i < size; i++) { - if (s[i] == '\n' || i + 1 == size) { - result.push_back(string(s + prev + 1, i - prev)); + int32_t prev{-1}; + for (size_t i{0}; i < size; i++) { + if (res_buffer[i] == '\n' || i + 1 == size) { + result.push_back(string(res_buffer + prev + 1, i - prev)); prev = i; } } @@ -243,7 +243,7 @@ inline Optional> f$file(const string& name) noexcept { } inline bool f$is_file(const string& name) noexcept { - struct stat stat_buf; + struct stat stat_buf {}; if (k2::lstat(name.c_str(), std::addressof(stat_buf)) != k2::errno_ok) { return false; } From 411abdc7048f8306808be6d2af7afc844d144724 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Fri, 12 Dec 2025 15:09:11 +0300 Subject: [PATCH 09/17] fixes --- runtime-light/k2-platform/k2-api.h | 12 ++++---- runtime-light/state/component-state.cpp | 5 ++-- .../stdlib/file/file-system-functions.h | 30 ++++++++++--------- runtime-light/stdlib/kml/kml-file-api.h | 4 +-- runtime/files.cpp | 1 + 5 files changed, 28 insertions(+), 24 deletions(-) diff --git a/runtime-light/k2-platform/k2-api.h b/runtime-light/k2-platform/k2-api.h index 4ed2124ac6..0fc134d7f2 100644 --- a/runtime-light/k2-platform/k2-api.h +++ b/runtime-light/k2-platform/k2-api.h @@ -411,18 +411,18 @@ inline auto canonicalize(std::string_view path) noexcept { return return_type{{unique_ptr_type{resolved_path, std::invoke(deleter_creator, resolved_path_len, resolved_path_align)}, resolved_path_len}}; } -inline int32_t stat(std::string_view path, struct stat* stat) noexcept { +inline std::expected stat(std::string_view path, struct stat* stat) noexcept { if (auto error_code{k2_stat(path.data(), path.size(), stat)}; error_code != k2::errno_ok) [[unlikely]] { - return error_code; + return std::unexpected{error_code}; } - return k2::errno_ok; + return {}; } -inline int32_t lstat(std::string_view path, struct stat* stat) noexcept { +inline std::expected lstat(std::string_view path, struct stat* stat) noexcept { if (auto error_code{k2_lstat(path.data(), path.size(), stat)}; error_code != k2::errno_ok) [[unlikely]] { - return error_code; + return std::unexpected{error_code}; } - return k2::errno_ok; + return {}; } using CommandArg = CommandArg; diff --git a/runtime-light/state/component-state.cpp b/runtime-light/state/component-state.cpp index 62e8bd93db..7c94afbbab 100644 --- a/runtime-light/state/component-state.cpp +++ b/runtime-light/state/component-state.cpp @@ -86,8 +86,9 @@ void ComponentState::parse_runtime_config_arg(std::string_view value_view) noexc } struct stat stat {}; - if (auto error_code{k2::stat({runtime_config_path.get(), runtime_config_path_size}, std::addressof(stat))}; error_code != k2::errno_ok) [[unlikely]] { - return kphp::log::warning("error getting runtime-config stat: error code -> {}", error_code); + if (auto error_code_expected{k2::stat({runtime_config_path.get(), runtime_config_path_size}, std::addressof(stat))}; !error_code_expected.has_value()) + [[unlikely]] { + return kphp::log::warning("error getting runtime-config stat: error code -> {}", error_code_expected.error()); } const auto runtime_config_mem{std::unique_ptr{ diff --git a/runtime-light/stdlib/file/file-system-functions.h b/runtime-light/stdlib/file/file-system-functions.h index ebca02ffcf..dc8f90b553 100644 --- a/runtime-light/stdlib/file/file-system-functions.h +++ b/runtime-light/stdlib/file/file-system-functions.h @@ -16,7 +16,9 @@ #include #include +#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/string/string-functions.h" #include "runtime-light/coroutine/task.h" #include "runtime-light/k2-platform/k2-api.h" @@ -59,7 +61,7 @@ inline string f$basename(const string& path, const string& suffix = {}) noexcept inline Optional f$filesize(const string& filename) noexcept { struct stat stat {}; - if (auto errc{k2::stat({filename.c_str(), filename.size()}, std::addressof(stat))}; errc != k2::errno_ok) [[unlikely]] { + if (auto errc_expected{k2::stat({filename.c_str(), filename.size()}, std::addressof(stat))}; !errc_expected.has_value()) [[unlikely]] { return false; } return static_cast(stat.st_size); @@ -199,15 +201,13 @@ inline Optional f$file_get_contents(const string& stream) noexcept { } inline Optional> f$file(const string& name) noexcept { - struct stat stat_buf; + struct stat stat_buf {}; - auto open_res = kphp::fs::file::open(name.c_str(), "r"); - if (!open_res.has_value()) { + auto open_result{kphp::fs::file::open(name.c_str(), "r")}; + if (!open_result.has_value()) { return false; } - auto& file = open_res.value(); - - if (k2::stat(name.c_str(), std::addressof(stat_buf)) != k2::errno_ok) { + if (!k2::stat(name.c_str(), std::addressof(stat_buf)).has_value()) { return false; } if (!S_ISREG(stat_buf.st_mode)) { @@ -221,10 +221,12 @@ inline Optional> f$file(const string& name) noexcept { return false; } - string res{static_cast(size), false}; - char* res_buffer{res.buffer()}; - std::span spn{reinterpret_cast(res_buffer), res.size()}; - if (auto rd_status = file.read(spn); !rd_status.has_value() || rd_status.value() < size) { + auto& file{open_result.value()}; + + kphp::stl::vector read_result(size); + char* read_result_data{read_result.data()}; + std::span temp_span{reinterpret_cast(read_result_data), read_result.size()}; + if (auto rd_status{file.read(temp_span)}; !rd_status.has_value() || rd_status.value() < size) { return false; } @@ -233,8 +235,8 @@ inline Optional> f$file(const string& name) noexcept { array result; int32_t prev{-1}; for (size_t i{0}; i < size; i++) { - if (res_buffer[i] == '\n' || i + 1 == size) { - result.push_back(string(res_buffer + prev + 1, i - prev)); + if (read_result_data[i] == '\n' || i + 1 == size) { + result.push_back(string{read_result_data + prev + 1, static_cast(i - prev)}); prev = i; } } @@ -244,7 +246,7 @@ inline Optional> f$file(const string& name) noexcept { inline bool f$is_file(const string& name) noexcept { struct stat stat_buf {}; - if (k2::lstat(name.c_str(), std::addressof(stat_buf)) != k2::errno_ok) { + if (!k2::lstat(name.c_str(), std::addressof(stat_buf)).has_value()) { return false; } return S_ISREG(stat_buf.st_mode); diff --git a/runtime-light/stdlib/kml/kml-file-api.h b/runtime-light/stdlib/kml/kml-file-api.h index 7606fe36be..394adbda92 100644 --- a/runtime-light/stdlib/kml/kml-file-api.h +++ b/runtime-light/stdlib/kml/kml-file-api.h @@ -120,8 +120,8 @@ class dir_traverser final : public kphp::kml::dir_traverser_interface {}, path -> {}", error_code, direntry_path); + if (auto error_code_expected{k2::stat(direntry_path, std::addressof(stat))}; !error_code_expected.has_value()) [[unlikely]] { + kphp::log::warning("[kml] failed to get stat: error code -> {}, path -> {}", error_code_expected.error(), direntry_path); return std::nullopt; } diff --git a/runtime/files.cpp b/runtime/files.cpp index 781ef78ccf..25d13374eb 100644 --- a/runtime/files.cpp +++ b/runtime/files.cpp @@ -313,6 +313,7 @@ bool f$is_dir(const string& name) { bool f$is_file(const string& name) { struct stat stat_buf; dl::enter_critical_section(); // OK + // TODO: the semantics in PHP are different if (lstat(name.c_str(), &stat_buf) < 0) { dl::leave_critical_section(); return false; From 3005e5018e9227abd3ac84f62aed933404422593 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Mon, 15 Dec 2025 14:35:07 +0300 Subject: [PATCH 10/17] minor fix --- runtime-light/stdlib/file/file-system-functions.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/runtime-light/stdlib/file/file-system-functions.h b/runtime-light/stdlib/file/file-system-functions.h index dc8f90b553..bf349ccd70 100644 --- a/runtime-light/stdlib/file/file-system-functions.h +++ b/runtime-light/stdlib/file/file-system-functions.h @@ -223,10 +223,8 @@ inline Optional> f$file(const string& name) noexcept { auto& file{open_result.value()}; - kphp::stl::vector read_result(size); - char* read_result_data{read_result.data()}; - std::span temp_span{reinterpret_cast(read_result_data), read_result.size()}; - if (auto rd_status{file.read(temp_span)}; !rd_status.has_value() || rd_status.value() < size) { + kphp::stl::vector read_result(size); + if (auto rd_status{file.read(read_result)}; !rd_status.has_value() || rd_status.value() < size) { return false; } @@ -235,8 +233,8 @@ inline Optional> f$file(const string& name) noexcept { array result; int32_t prev{-1}; for (size_t i{0}; i < size; i++) { - if (read_result_data[i] == '\n' || i + 1 == size) { - result.push_back(string{read_result_data + prev + 1, static_cast(i - prev)}); + if (static_cast(read_result[i]) == '\n' || i + 1 == size) { + result.push_back(string{reinterpret_cast(read_result.data()) + prev + 1, static_cast(i - prev)}); prev = i; } } From 4cd91d636c9a0b18a0828f5d9f61432ae32fedf1 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Mon, 15 Dec 2025 14:39:08 +0300 Subject: [PATCH 11/17] minor fix --- runtime-light/stdlib/file/file-system-functions.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime-light/stdlib/file/file-system-functions.h b/runtime-light/stdlib/file/file-system-functions.h index bf349ccd70..a3e7c61ec1 100644 --- a/runtime-light/stdlib/file/file-system-functions.h +++ b/runtime-light/stdlib/file/file-system-functions.h @@ -223,7 +223,7 @@ inline Optional> f$file(const string& name) noexcept { auto& file{open_result.value()}; - kphp::stl::vector read_result(size); + kphp::stl::vector read_result{size}; if (auto rd_status{file.read(read_result)}; !rd_status.has_value() || rd_status.value() < size) { return false; } From 9eb5da7aae75d0d5696555c4929bb1707412c832 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Mon, 15 Dec 2025 16:10:56 +0300 Subject: [PATCH 12/17] minor fix --- runtime-light/state/component-state.cpp | 4 ++-- runtime-light/stdlib/file/file-system-functions.h | 3 ++- runtime-light/stdlib/kml/kml-file-api.h | 4 ++-- runtime/files.cpp | 1 - 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/runtime-light/state/component-state.cpp b/runtime-light/state/component-state.cpp index 7c94afbbab..d0b49a9795 100644 --- a/runtime-light/state/component-state.cpp +++ b/runtime-light/state/component-state.cpp @@ -86,9 +86,9 @@ void ComponentState::parse_runtime_config_arg(std::string_view value_view) noexc } struct stat stat {}; - if (auto error_code_expected{k2::stat({runtime_config_path.get(), runtime_config_path_size}, std::addressof(stat))}; !error_code_expected.has_value()) + if (auto stat_result{k2::stat({runtime_config_path.get(), runtime_config_path_size}, std::addressof(stat))}; !stat_result.has_value()) [[unlikely]] { - return kphp::log::warning("error getting runtime-config stat: error code -> {}", error_code_expected.error()); + return kphp::log::warning("error getting runtime-config stat: error code -> {}", stat_result.error()); } const auto runtime_config_mem{std::unique_ptr{ diff --git a/runtime-light/stdlib/file/file-system-functions.h b/runtime-light/stdlib/file/file-system-functions.h index a3e7c61ec1..eed8561c77 100644 --- a/runtime-light/stdlib/file/file-system-functions.h +++ b/runtime-light/stdlib/file/file-system-functions.h @@ -61,7 +61,7 @@ inline string f$basename(const string& path, const string& suffix = {}) noexcept inline Optional f$filesize(const string& filename) noexcept { struct stat stat {}; - if (auto errc_expected{k2::stat({filename.c_str(), filename.size()}, std::addressof(stat))}; !errc_expected.has_value()) [[unlikely]] { + if (auto stat_result{k2::stat({filename.c_str(), filename.size()}, std::addressof(stat))}; !stat_result.has_value()) [[unlikely]] { return false; } return static_cast(stat.st_size); @@ -244,6 +244,7 @@ inline Optional> f$file(const string& name) noexcept { inline bool f$is_file(const string& name) noexcept { struct stat stat_buf {}; + // TODO: the semantics in PHP are different: PHP expects stat if (!k2::lstat(name.c_str(), std::addressof(stat_buf)).has_value()) { return false; } diff --git a/runtime-light/stdlib/kml/kml-file-api.h b/runtime-light/stdlib/kml/kml-file-api.h index 394adbda92..3d6f78ccf8 100644 --- a/runtime-light/stdlib/kml/kml-file-api.h +++ b/runtime-light/stdlib/kml/kml-file-api.h @@ -120,8 +120,8 @@ class dir_traverser final : public kphp::kml::dir_traverser_interface {}, path -> {}", error_code_expected.error(), direntry_path); + if (auto stat_result{k2::stat(direntry_path, std::addressof(stat))}; !stat_result.has_value()) [[unlikely]] { + kphp::log::warning("[kml] failed to get stat: error code -> {}, path -> {}", stat_result.error(), direntry_path); return std::nullopt; } diff --git a/runtime/files.cpp b/runtime/files.cpp index 25d13374eb..781ef78ccf 100644 --- a/runtime/files.cpp +++ b/runtime/files.cpp @@ -313,7 +313,6 @@ bool f$is_dir(const string& name) { bool f$is_file(const string& name) { struct stat stat_buf; dl::enter_critical_section(); // OK - // TODO: the semantics in PHP are different if (lstat(name.c_str(), &stat_buf) < 0) { dl::leave_critical_section(); return false; From 6e67c47690f33ecae30aadf6c979e4877c84d227 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Mon, 15 Dec 2025 16:12:09 +0300 Subject: [PATCH 13/17] minor fix --- runtime-light/state/component-state.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/runtime-light/state/component-state.cpp b/runtime-light/state/component-state.cpp index d0b49a9795..ec8983b873 100644 --- a/runtime-light/state/component-state.cpp +++ b/runtime-light/state/component-state.cpp @@ -85,9 +85,8 @@ void ComponentState::parse_runtime_config_arg(std::string_view value_view) noexc return kphp::log::warning("error opening runtime-config: error code -> {}", expected_runtime_config_file.error()); } - struct stat stat {}; - if (auto stat_result{k2::stat({runtime_config_path.get(), runtime_config_path_size}, std::addressof(stat))}; !stat_result.has_value()) - [[unlikely]] { + struct stat stat{}; + if (auto stat_result{k2::stat({runtime_config_path.get(), runtime_config_path_size}, std::addressof(stat))}; !stat_result.has_value()) [[unlikely]] { return kphp::log::warning("error getting runtime-config stat: error code -> {}", stat_result.error()); } From 55ca8e7682a24ba5768e90709f3cd12431d8b1ef Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Mon, 15 Dec 2025 16:14:21 +0300 Subject: [PATCH 14/17] minor fix --- runtime-light/state/component-state.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime-light/state/component-state.cpp b/runtime-light/state/component-state.cpp index ec8983b873..e6a16746e1 100644 --- a/runtime-light/state/component-state.cpp +++ b/runtime-light/state/component-state.cpp @@ -85,7 +85,7 @@ void ComponentState::parse_runtime_config_arg(std::string_view value_view) noexc return kphp::log::warning("error opening runtime-config: error code -> {}", expected_runtime_config_file.error()); } - struct stat stat{}; + struct stat stat {}; if (auto stat_result{k2::stat({runtime_config_path.get(), runtime_config_path_size}, std::addressof(stat))}; !stat_result.has_value()) [[unlikely]] { return kphp::log::warning("error getting runtime-config stat: error code -> {}", stat_result.error()); } From 0dc3b6be7161931df0acd5194a20c29b64084d68 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Mon, 15 Dec 2025 16:43:26 +0300 Subject: [PATCH 15/17] minor fix --- runtime-light/stdlib/file/file-system-functions.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/runtime-light/stdlib/file/file-system-functions.h b/runtime-light/stdlib/file/file-system-functions.h index eed8561c77..f4ccc44aa4 100644 --- a/runtime-light/stdlib/file/file-system-functions.h +++ b/runtime-light/stdlib/file/file-system-functions.h @@ -223,8 +223,8 @@ inline Optional> f$file(const string& name) noexcept { auto& file{open_result.value()}; - kphp::stl::vector read_result{size}; - if (auto rd_status{file.read(read_result)}; !rd_status.has_value() || rd_status.value() < size) { + kphp::stl::vector file_content{size}; + if (auto rd_status{file.read(file_content)}; !rd_status.has_value() || rd_status.value() < size) { return false; } @@ -233,8 +233,8 @@ inline Optional> f$file(const string& name) noexcept { array result; int32_t prev{-1}; for (size_t i{0}; i < size; i++) { - if (static_cast(read_result[i]) == '\n' || i + 1 == size) { - result.push_back(string{reinterpret_cast(read_result.data()) + prev + 1, static_cast(i - prev)}); + if (static_cast(file_content[i]) == '\n' || i + 1 == size) { + result.push_back(string{reinterpret_cast(file_content.data()) + prev + 1, static_cast(i - prev)}); prev = i; } } From e33310e1be23c9a7091f132b0efff61c355e629f Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Tue, 16 Dec 2025 16:10:46 +0300 Subject: [PATCH 16/17] minor fix --- runtime-light/state/component-state.cpp | 5 +++-- runtime-light/stdlib/file/file-system-functions.h | 15 +++++++-------- runtime-light/stdlib/kml/kml-file-api.h | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/runtime-light/state/component-state.cpp b/runtime-light/state/component-state.cpp index e6a16746e1..16981067fa 100644 --- a/runtime-light/state/component-state.cpp +++ b/runtime-light/state/component-state.cpp @@ -86,8 +86,9 @@ void ComponentState::parse_runtime_config_arg(std::string_view value_view) noexc } struct stat stat {}; - if (auto stat_result{k2::stat({runtime_config_path.get(), runtime_config_path_size}, std::addressof(stat))}; !stat_result.has_value()) [[unlikely]] { - return kphp::log::warning("error getting runtime-config stat: error code -> {}", stat_result.error()); + if (auto expected_stat_result{k2::stat({runtime_config_path.get(), runtime_config_path_size}, std::addressof(stat))}; !expected_stat_result.has_value()) + [[unlikely]] { + return kphp::log::warning("error getting runtime-config stat: error code -> {}", expected_stat_result.error()); } const auto runtime_config_mem{std::unique_ptr{ diff --git a/runtime-light/stdlib/file/file-system-functions.h b/runtime-light/stdlib/file/file-system-functions.h index f4ccc44aa4..ff7835491c 100644 --- a/runtime-light/stdlib/file/file-system-functions.h +++ b/runtime-light/stdlib/file/file-system-functions.h @@ -203,8 +203,8 @@ inline Optional f$file_get_contents(const string& stream) noexcept { inline Optional> f$file(const string& name) noexcept { struct stat stat_buf {}; - auto open_result{kphp::fs::file::open(name.c_str(), "r")}; - if (!open_result.has_value()) { + auto expected_file{kphp::fs::file::open(name.c_str(), "r")}; + if (!expected_file.has_value()) { return false; } if (!k2::stat(name.c_str(), std::addressof(stat_buf)).has_value()) { @@ -221,15 +221,14 @@ inline Optional> f$file(const string& name) noexcept { return false; } - auto& file{open_result.value()}; - kphp::stl::vector file_content{size}; - if (auto rd_status{file.read(file_content)}; !rd_status.has_value() || rd_status.value() < size) { - return false; + { + 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; + } } - file.close(); - array result; int32_t prev{-1}; for (size_t i{0}; i < size; i++) { diff --git a/runtime-light/stdlib/kml/kml-file-api.h b/runtime-light/stdlib/kml/kml-file-api.h index 3d6f78ccf8..99d79ed6b7 100644 --- a/runtime-light/stdlib/kml/kml-file-api.h +++ b/runtime-light/stdlib/kml/kml-file-api.h @@ -120,8 +120,8 @@ class dir_traverser final : public kphp::kml::dir_traverser_interface {}, path -> {}", stat_result.error(), direntry_path); + if (auto expected_stat_result{k2::stat(direntry_path, std::addressof(stat))}; !expected_stat_result.has_value()) [[unlikely]] { + kphp::log::warning("[kml] failed to get stat: error code -> {}, path -> {}", expected_stat_result.error(), direntry_path); return std::nullopt; } From 9d0605cd7400063e91149bdd3c6bf090b6fde33f Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Tue, 16 Dec 2025 16:47:40 +0300 Subject: [PATCH 17/17] minor fix --- runtime-light/stdlib/file/file-system-functions.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/runtime-light/stdlib/file/file-system-functions.h b/runtime-light/stdlib/file/file-system-functions.h index ff7835491c..67829322d6 100644 --- a/runtime-light/stdlib/file/file-system-functions.h +++ b/runtime-light/stdlib/file/file-system-functions.h @@ -221,9 +221,10 @@ inline Optional> f$file(const string& name) noexcept { return false; } - kphp::stl::vector file_content{size}; + kphp::stl::vector file_content; + file_content.resize(size); { - auto& file{std::move(*expected_file)}; + 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; }