From 7af3d5cbbbb7b1db2b0637d35f49e44131bd7f5d Mon Sep 17 00:00:00 2001 From: MacroModel <33865334+MacroModel@users.noreply.github.com> Date: Tue, 11 Nov 2025 13:40:52 +0800 Subject: [PATCH 1/9] Change argv and envp types in execveat declaration The POSIX API is poorly designed, allowing modifiable parameters that are never actually changed in practice. --- include/fast_io_hosted/process/process/posix.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fast_io_hosted/process/process/posix.h b/include/fast_io_hosted/process/process/posix.h index 161b9bf2..05b979eb 100644 --- a/include/fast_io_hosted/process/process/posix.h +++ b/include/fast_io_hosted/process/process/posix.h @@ -10,7 +10,7 @@ namespace posix { #if defined(__DARWIN_C_LEVEL) || defined(__MSDOS__) extern int libc_fexecve(int fd, char *const *argv, char *const *envp) noexcept __asm__("_fexecve"); -extern int libc_execveat(int dirfd, char const *pathname, char *const *argv, char *const *envp, int flags) noexcept __asm__("_execveat"); +extern int libc_execveat(int dirfd, char const *pathname, char const *const *argv, char const *const *envp, int flags) noexcept __asm__("_execveat"); extern int libc_kill(pid_t pid, int sig) noexcept __asm__("_kill"); extern pid_t libc_fork() noexcept __asm__("_fork"); extern pid_t libc_vfork() noexcept __asm__("_vfork"); @@ -20,7 +20,7 @@ extern pid_t libc_waitpid(pid_t pid, int *status, int options) noexcept __asm__( [[noreturn]] extern void libc_exit2(int status) noexcept __asm__("__exit"); #else extern int libc_fexecve(int fd, char *const *argv, char *const *envp) noexcept __asm__("fexecve"); -extern int libc_execveat(int dirfd, char const *pathname, char *const *argv, char *const *envp, int flags) noexcept __asm__("execveat"); +extern int libc_execveat(int dirfd, char const *pathname, char const *const *argv, char const *const *envp, int flags) noexcept __asm__("execveat"); extern int libc_kill(pid_t pid, int sig) noexcept __asm__("kill"); extern pid_t libc_fork() noexcept __asm__("fork"); extern pid_t libc_vfork() noexcept __asm__("vfork"); From a8d31630e7e08b8eb8a7d11451ead9a1c6b9b4e9 Mon Sep 17 00:00:00 2001 From: MacroModel <33865334+MacroModel@users.noreply.github.com> Date: Tue, 11 Nov 2025 14:11:52 +0800 Subject: [PATCH 2/9] Update posix.h --- include/fast_io_hosted/process/process/posix.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/fast_io_hosted/process/process/posix.h b/include/fast_io_hosted/process/process/posix.h index 05b979eb..0d271882 100644 --- a/include/fast_io_hosted/process/process/posix.h +++ b/include/fast_io_hosted/process/process/posix.h @@ -8,6 +8,11 @@ namespace fast_io namespace posix { +// The statement about argu[] and enopl] being constants is included to make explicit to future writers of language bindings that these objects are completely constant. +// Due toa limitation of the ISOC standard, it is not possible to state that idea in standard C. Specifying two levels of const-qualification for the argol] and enopll +// parameters for the exec functions may seem to be the natural choice, given that these functions do not modify either the array of pointers or the characters to which the +// function points, but this would disallow existing correct code. Instead, only the array of pointers is noted as constant. + #if defined(__DARWIN_C_LEVEL) || defined(__MSDOS__) extern int libc_fexecve(int fd, char *const *argv, char *const *envp) noexcept __asm__("_fexecve"); extern int libc_execveat(int dirfd, char const *pathname, char const *const *argv, char const *const *envp, int flags) noexcept __asm__("_execveat"); From 90edd865d60d065bd0a85c66c09002190ed74e34 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Wed, 12 Nov 2025 04:56:28 +0000 Subject: [PATCH 3/9] Refactor execveat function signatures in posix.h to improve const correctness Updated the parameter types for `libc_execveat` to accept non-const pointers for `argv` and `envp`, enhancing compatibility with existing code. Adjusted calls to `libc_execveat` in `vfork_and_execveat` to use `const_cast` for proper type handling. --- include/fast_io_hosted/process/process/posix.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/fast_io_hosted/process/process/posix.h b/include/fast_io_hosted/process/process/posix.h index 0d271882..ebe4c42b 100644 --- a/include/fast_io_hosted/process/process/posix.h +++ b/include/fast_io_hosted/process/process/posix.h @@ -8,14 +8,14 @@ namespace fast_io namespace posix { -// The statement about argu[] and enopl] being constants is included to make explicit to future writers of language bindings that these objects are completely constant. -// Due toa limitation of the ISOC standard, it is not possible to state that idea in standard C. Specifying two levels of const-qualification for the argol] and enopll -// parameters for the exec functions may seem to be the natural choice, given that these functions do not modify either the array of pointers or the characters to which the +// The statement about argu[] and enopl] being constants is included to make explicit to future writers of language bindings that these objects are completely constant. +// Due toa limitation of the ISOC standard, it is not possible to state that idea in standard C. Specifying two levels of const-qualification for the argol] and enopll +// parameters for the exec functions may seem to be the natural choice, given that these functions do not modify either the array of pointers or the characters to which the // function points, but this would disallow existing correct code. Instead, only the array of pointers is noted as constant. #if defined(__DARWIN_C_LEVEL) || defined(__MSDOS__) extern int libc_fexecve(int fd, char *const *argv, char *const *envp) noexcept __asm__("_fexecve"); -extern int libc_execveat(int dirfd, char const *pathname, char const *const *argv, char const *const *envp, int flags) noexcept __asm__("_execveat"); +extern int libc_execveat(int dirfd, char const *pathname, char *const *argv, char *const *envp, int flags) noexcept __asm__("_execveat"); extern int libc_kill(pid_t pid, int sig) noexcept __asm__("_kill"); extern pid_t libc_fork() noexcept __asm__("_fork"); extern pid_t libc_vfork() noexcept __asm__("_vfork"); @@ -25,7 +25,7 @@ extern pid_t libc_waitpid(pid_t pid, int *status, int options) noexcept __asm__( [[noreturn]] extern void libc_exit2(int status) noexcept __asm__("__exit"); #else extern int libc_fexecve(int fd, char *const *argv, char *const *envp) noexcept __asm__("fexecve"); -extern int libc_execveat(int dirfd, char const *pathname, char const *const *argv, char const *const *envp, int flags) noexcept __asm__("execveat"); +extern int libc_execveat(int dirfd, char const *pathname, char *const *argv, char *const *envp, int flags) noexcept __asm__("execveat"); extern int libc_kill(pid_t pid, int sig) noexcept __asm__("kill"); extern pid_t libc_fork() noexcept __asm__("fork"); extern pid_t libc_vfork() noexcept __asm__("vfork"); @@ -768,7 +768,7 @@ inline void vfork_and_execveat(pid_t &pid, int dirfd, char const *cstr, char con flags |= AT_SYMLINK_NOFOLLOW; } - auto ret{::fast_io::posix::libc_execveat(dirfd, cstr, args, envp, flags)}; + auto ret{::fast_io::posix::libc_execveat(dirfd, cstr, const_cast(args), const_cast(envp), flags)}; if (ret == -1) { t_errno = errno; @@ -791,7 +791,7 @@ inline void vfork_and_execveat(pid_t &pid, int dirfd, char const *cstr, char con flags |= AT_SYMLINK_NOFOLLOW; } - auto ret{::fast_io::posix::libc_execveat(dirfd, cstr, args, envp, flags)}; + auto ret{::fast_io::posix::libc_execveat(dirfd, cstr, const_cast(args), const_cast(envp), flags)}; if (ret == -1) { t_errno = errno; From d9d38f9c2e54fd636f7c849dba84207231bcb6f8 Mon Sep 17 00:00:00 2001 From: MacroModel <33865334+MacroModel@users.noreply.github.com> Date: Wed, 12 Nov 2025 13:30:03 +0800 Subject: [PATCH 4/9] Update bsd.h --- include/fast_io_driver/install_path/bsd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_io_driver/install_path/bsd.h b/include/fast_io_driver/install_path/bsd.h index a0615fef..90b1e806 100644 --- a/include/fast_io_driver/install_path/bsd.h +++ b/include/fast_io_driver/install_path/bsd.h @@ -27,7 +27,7 @@ inline ::fast_io::install_path get_module_install_path() char buffer1[PATH_MAX + 1]; char buffer2[PATH_MAX + 1]; char *resolved{}; - int length = -1; + // int length = -1; #if defined(__NetBSD__) int mib[4]{CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME}; From 91eacda5508c2d8a94ad4bdfa3bddef734343155 Mon Sep 17 00:00:00 2001 From: MacroModel <33865334+MacroModel@users.noreply.github.com> Date: Wed, 12 Nov 2025 15:24:38 +0800 Subject: [PATCH 5/9] Update nt_at.h --- include/fast_io_hosted/filesystem/nt_at.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_io_hosted/filesystem/nt_at.h b/include/fast_io_hosted/filesystem/nt_at.h index 3be2375a..6a3c2de7 100644 --- a/include/fast_io_hosted/filesystem/nt_at.h +++ b/include/fast_io_hosted/filesystem/nt_at.h @@ -851,7 +851,7 @@ inline ::fast_io::details::basic_ct_string nt_readlinkat_impl(void *d ::fast_io::basic_nt_family_file<(zw ? nt_family::zw : nt_family::nt), char> file{ nt_call_determine_kernel_callback(dirhd, path_c_str, path_size, kernel, nt_create_callback{md})}; - throw_nt_error(0xC0000002); + throw_nt_error(0xC0000275u /*STATUS_NOT_A_REPARSE_POINT*/); return {}; #endif From d1983f04e95353dc52abffc2c89674e4f828a158 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sat, 15 Nov 2025 23:38:10 +0800 Subject: [PATCH 6/9] update --- include/fast_io_driver/install_path/linux.h | 2 +- include/fast_io_hosted/filesystem/nt_at.h | 48 +++++++++++++------ .../fast_io_hosted/process/process/posix.h | 4 +- 3 files changed, 36 insertions(+), 18 deletions(-) diff --git a/include/fast_io_driver/install_path/linux.h b/include/fast_io_driver/install_path/linux.h index f42f7169..42fecf31 100644 --- a/include/fast_io_driver/install_path/linux.h +++ b/include/fast_io_driver/install_path/linux.h @@ -24,7 +24,7 @@ inline ::fast_io::install_path get_module_install_path() char buffer[path_max + 1]; ::fast_io::install_path ret; - using my_ssize_t = ::std::make_signed_t<::std::size_t>; + using my_ssize_t [[maybe_unused]] = ::std::make_signed_t<::std::size_t>; #if defined(__linux__) && defined(__NR_readlink) auto resolved{::fast_io::system_call<__NR_readlink, my_ssize_t>("/proc/self/exe", buffer, path_max)}; system_call_throw_error(resolved); diff --git a/include/fast_io_hosted/filesystem/nt_at.h b/include/fast_io_hosted/filesystem/nt_at.h index 6a3c2de7..459d7a83 100644 --- a/include/fast_io_hosted/filesystem/nt_at.h +++ b/include/fast_io_hosted/filesystem/nt_at.h @@ -56,35 +56,53 @@ namespace win32::nt::details inline constexpr nt_open_mode calculate_nt_delete_flag(nt_at_flags flags) noexcept { + // FILE_DELETE_ON_CLOSE is not used here. Instead, use FILE_DISPOSITION_INFORMATION to control deletion! + + // FILE_DELETE_ON_CLOSE schedules deletion at handle close. + // The actual delete operation happens inside NtClose, which does not provide detailed error codes. + // Therefore, you cannot reliably retrieve the actual delete failure reason. + nt_open_mode mode{ - .DesiredAccess = 0x00010000, // FILE_GENERIC_READ - .FileAttributes = 0x80, // FILE_ATTRIBUTE_NORMAL - .ShareAccess = 0x00000007, // FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE - .CreateDisposition = 0x00000001, /*OPEN_EXISTING => FILE_OPEN*/ - .CreateOptions = 0x00001000 /*FILE_DELETE_ON_CLOSE*/ + .DesiredAccess = 0x00010000 | 0x00100000, // DELETE | SYNCHRONIZE + .FileAttributes = 0x80, // FILE_ATTRIBUTE_NORMAL + .ShareAccess = 0x00000007, // FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE + .CreateDisposition = 0x00000001, // OPEN_EXISTING => FILE_OPEN + .CreateOptions = 0x00000020 | 0x00004000 // FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT }; + if ((flags & nt_at_flags::symlink_nofollow) == nt_at_flags::symlink_nofollow) { mode.CreateOptions |= 0x00200000; // FILE_FLAG_OPEN_REPARSE_POINT => FILE_OPEN_REPARSE_POINT (0x00200000) } + if ((flags & nt_at_flags::removedir) == nt_at_flags::removedir) { - mode.CreateOptions |= 0x00004000; // FILE_OPEN_FOR_BACKUP_INTENT mode.CreateOptions |= 0x00000001; // FILE_DIRECTORY_FILE } else { - mode.CreateOptions |= 0x00000040; // FILE_NON_DIRECTORY_FILE 0x00000040 + mode.CreateOptions |= 0x00000040; // FILE_NON_DIRECTORY_FILE } + return mode; } template inline void nt_unlinkat_impl(void *dirhd, char16_t const *path_c_str, ::std::size_t path_size, nt_at_flags flags, bool kernel) { - auto status{nt_close( - nt_call_determine_kernel_callback(dirhd, path_c_str, path_size, kernel, nt_create_callback{calculate_nt_delete_flag(flags)}))}; - if (status) + ::fast_io::basic_nt_family_file<(zw ? nt_family::zw : nt_family::nt), char> file{ + nt_call_determine_kernel_callback(dirhd, path_c_str, path_size, kernel, nt_create_callback{calculate_nt_delete_flag(flags)})}; + + ::fast_io::win32::nt::io_status_block IoStatusBlock; // no initialization needed + ::fast_io::win32::nt::file_disposition_information fdi{.DeleteFile = true}; + + auto status{::fast_io::win32::nt::nt_set_information_file(file.native_handle(), + __builtin_addressof(IoStatusBlock), + __builtin_addressof(fdi), + sizeof(fdi), + ::fast_io::win32::nt::file_information_class::FileDispositionInformation)}; + + if (status) [[unlikely]] { throw_nt_error(status); } @@ -107,7 +125,7 @@ inline void nt_mkdirat_impl(void *dirhd, char16_t const *path_c_str, ::std::size } auto status{nt_close(nt_call_determine_kernel_callback(dirhd, path_c_str, path_size, kernel, nt_create_callback{m_dir_mode}))}; - + if (status) { throw_nt_error(status); @@ -777,10 +795,10 @@ inline ::fast_io::details::basic_ct_string nt_readlinkat_impl(void *d { #if !defined(_WIN32_WINNT) || _WIN32_WINNT > 0x0600 constexpr ::fast_io::win32::nt::details::nt_open_mode md{ - .DesiredAccess = 0x00100000 | 0x0080, // SYNCHRONIZE | FILE_READ_ATTRIBUTES - .FileAttributes = 0x80, // FILE_ATTRIBUTE_NORMAL - .ShareAccess = 0x00000007, // FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE - .CreateDisposition = 0x00000001, // OPEN_EXISTING => FILE_OPEN + .DesiredAccess = 0x00100000 | 0x0080, // SYNCHRONIZE | FILE_READ_ATTRIBUTES + .FileAttributes = 0x80, // FILE_ATTRIBUTE_NORMAL + .ShareAccess = 0x00000007, // FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE + .CreateDisposition = 0x00000001, // OPEN_EXISTING => FILE_OPEN .CreateOptions = 0x00200000 | 0x00000020 // FILE_FLAG_OPEN_REPARSE_POINT | FILE_SYNCHRONOUS_IO_NONALERT }; diff --git a/include/fast_io_hosted/process/process/posix.h b/include/fast_io_hosted/process/process/posix.h index ebe4c42b..e9fd621a 100644 --- a/include/fast_io_hosted/process/process/posix.h +++ b/include/fast_io_hosted/process/process/posix.h @@ -135,7 +135,7 @@ namespace details * - The returned path may differ from original open() argument due to symlinks or namespaces. */ -inline void portable_fd_path(int fd, char *buf, ::std::size_t bufsz) +inline void portable_fd_path([[maybe_unused]] int fd, char *buf, ::std::size_t bufsz) { if (buf == nullptr || bufsz == 0u) [[unlikely]] { @@ -184,7 +184,7 @@ inline void portable_fd_path(int fd, char *buf, ::std::size_t bufsz) ::fast_io::obuffer_view linkpath_ov{linkpath, linkpath + all_sz}; ::fast_io::operations::print_freestanding(linkpath_ov, path_str, fd, ::fast_io::mnp::chvw(::fast_io::char_literal_v)); - using my_ssize_t = ::std::make_signed_t<::std::size_t>; + using my_ssize_t [[maybe_unused]] = ::std::make_signed_t<::std::size_t>; #if defined(__linux__) && defined(__NR_readlink) auto resolved{::fast_io::system_call<__NR_readlink, my_ssize_t>(linkpath, buf, bufsz - 1u)}; From 9cd40950b8bb850fb6d39e1226924774130781f0 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sat, 15 Nov 2025 23:49:31 +0800 Subject: [PATCH 7/9] update --- include/fast_io_hosted/filesystem/nt_at.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_io_hosted/filesystem/nt_at.h b/include/fast_io_hosted/filesystem/nt_at.h index 459d7a83..a612b6d2 100644 --- a/include/fast_io_hosted/filesystem/nt_at.h +++ b/include/fast_io_hosted/filesystem/nt_at.h @@ -852,7 +852,7 @@ inline ::fast_io::details::basic_ct_string nt_readlinkat_impl(void *d #endif else { - throw_nt_error(0xC0000002); + throw_nt_error(0xC0000275u /*STATUS_NOT_A_REPARSE_POINT*/); } return {}; From 1985da12a58e3fc67cf16d244b0c4db4e105bb09 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sun, 16 Nov 2025 00:17:46 +0800 Subject: [PATCH 8/9] Enforce no-follow mode for unlinkat operations in nt_at.h to match POSIX semantics - Updated `calculate_nt_delete_flag` to unconditionally set `FILE_FLAG_OPEN_REPARSE_POINT` flag. - Removed conditional check for `symlink_nofollow` flag as POSIX requires unlinkat() to always operate in no-follow mode. - Added comment explaining that symlinks must be unlinked as directory entries and never resolved, matching POSIX behavior. --- include/fast_io_hosted/filesystem/nt_at.h | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/include/fast_io_hosted/filesystem/nt_at.h b/include/fast_io_hosted/filesystem/nt_at.h index a612b6d2..a6bf99c6 100644 --- a/include/fast_io_hosted/filesystem/nt_at.h +++ b/include/fast_io_hosted/filesystem/nt_at.h @@ -62,19 +62,18 @@ inline constexpr nt_open_mode calculate_nt_delete_flag(nt_at_flags flags) noexce // The actual delete operation happens inside NtClose, which does not provide detailed error codes. // Therefore, you cannot reliably retrieve the actual delete failure reason. + // POSIX requires unlinkat() to always operate in no-follow mode (symlinks are + // unconditionally unlinked as directory entries and never resolved). Therefore, + // we must enforce the same no-follow behavior here. + nt_open_mode mode{ - .DesiredAccess = 0x00010000 | 0x00100000, // DELETE | SYNCHRONIZE - .FileAttributes = 0x80, // FILE_ATTRIBUTE_NORMAL - .ShareAccess = 0x00000007, // FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE - .CreateDisposition = 0x00000001, // OPEN_EXISTING => FILE_OPEN - .CreateOptions = 0x00000020 | 0x00004000 // FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT + .DesiredAccess = 0x00010000 | 0x00100000, // DELETE | SYNCHRONIZE + .FileAttributes = 0x80, // FILE_ATTRIBUTE_NORMAL + .ShareAccess = 0x00000007, // FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE + .CreateDisposition = 0x00000001, // OPEN_EXISTING => FILE_OPEN + .CreateOptions = 0x00000020 | 0x00004000 | 0x00200000 // FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_FLAG_OPEN_REPARSE_POINT }; - if ((flags & nt_at_flags::symlink_nofollow) == nt_at_flags::symlink_nofollow) - { - mode.CreateOptions |= 0x00200000; // FILE_FLAG_OPEN_REPARSE_POINT => FILE_OPEN_REPARSE_POINT (0x00200000) - } - if ((flags & nt_at_flags::removedir) == nt_at_flags::removedir) { mode.CreateOptions |= 0x00000001; // FILE_DIRECTORY_FILE From e6c9fe9b10b606d4458aacbe8f634d68468f30e0 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sun, 16 Nov 2025 17:59:39 +0800 Subject: [PATCH 9/9] fix --- include/fast_io_hosted/filesystem/nt_at.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_io_hosted/filesystem/nt_at.h b/include/fast_io_hosted/filesystem/nt_at.h index a6bf99c6..09f7f3aa 100644 --- a/include/fast_io_hosted/filesystem/nt_at.h +++ b/include/fast_io_hosted/filesystem/nt_at.h @@ -98,7 +98,7 @@ inline void nt_unlinkat_impl(void *dirhd, char16_t const *path_c_str, ::std::siz auto status{::fast_io::win32::nt::nt_set_information_file(file.native_handle(), __builtin_addressof(IoStatusBlock), __builtin_addressof(fdi), - sizeof(fdi), + static_cast<::std::uint_least32_t>(sizeof(fdi)), ::fast_io::win32::nt::file_information_class::FileDispositionInformation)}; if (status) [[unlikely]]