Skip to content
Merged
30 changes: 30 additions & 0 deletions examples/0036.at/readlink.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#include <fast_io.h>

int main(int argc, char **argv)
{
if (argc != 2)
{
if (argc == 0)
{
return 1;
}
::fast_io::io::perr("Usage: ", fast_io::mnp::os_c_str(*argv), " <symlink>\n");
return 1;
}

#if __cpp_exceptions
try
#endif
{
auto target{::fast_io::native_readlinkat<char>(::fast_io::at_fdcwd(), fast_io::mnp::os_c_str(argv[1]))};
::fast_io::println(target);
}
#if __cpp_exceptions
catch (fast_io::error e)
{
::fast_io::io::perrln(e);
}
#endif
}


7 changes: 7 additions & 0 deletions include/fast_io_hosted/filesystem/apis.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ enum class posix_api_22
renameat,
linkat
};

enum class posix_api_12
{
symlinkat
};

enum class posix_api_1x
{
faccessat,
Expand All @@ -24,4 +26,9 @@ enum class posix_api_1x
unlinkat
};

enum class posix_api_ct
{
readlinkat
};

} // namespace fast_io::details
22 changes: 22 additions & 0 deletions include/fast_io_hosted/filesystem/dos.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ class dos_directory_file FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE : public dos_
{
noexcept_call(::closedir, this->dirp.dirp);
}
if (this->dirp.fd != -1) [[likely]]
{
details::sys_close(this->dirp.fd);
}
this->dirp = newdir;
return *this;
}
Expand All @@ -147,6 +151,10 @@ class dos_directory_file FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE : public dos_
{
noexcept_call(::closedir, this->dirp.dirp);
}
if (this->dirp.fd != -1) [[likely]]
{
details::sys_close(this->dirp.fd);
}
this->dirp = other.release();
return *this;
}
Expand All @@ -157,16 +165,25 @@ class dos_directory_file FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE : public dos_
{
noexcept_call(::closedir, this->dirp.dirp);
}
if (this->dirp.fd != -1) [[likely]]
{
details::sys_close(this->dirp.fd);
}
this->dirp = dirp1;
}

inline void close()
{
if (*this) [[likely]]
{
int fd_to_close{this->dirp.fd};
int ret{noexcept_call(::closedir, this->dirp.dirp)};
this->dirp.dirp = nullptr;
this->dirp.fd = -1;
if (fd_to_close != -1)
{
details::sys_close(fd_to_close);
}
if (ret == -1)
{
throw_posix_error();
Expand All @@ -180,6 +197,11 @@ class dos_directory_file FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE : public dos_
{
noexcept_call(::closedir, this->dirp.dirp);
}
if (this->dirp.fd != -1) [[likely]]
{
// best-effort close for fd; ignore failures in destructor
details::sys_close(this->dirp.fd);
}
}
};

Expand Down
50 changes: 44 additions & 6 deletions include/fast_io_hosted/filesystem/dos_at.h
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,26 @@ inline auto dos1x_api_dispatcher(int dirfd, char const *path, Args... args)
}
}

template <::std::integral char_type>
inline ::fast_io::details::basic_ct_string<char_type> dos_readlinkat_impl(int dirfd, char const *pathname)
{
// DOS does not support readlink, so you must first verify its validity before throwing a einval exception (not symlink).
::fast_io::system_call_throw_error(::fast_io::posix::my_dos_access(::fast_io::details::my_dos_concat_tlc_path(dirfd, pathname).c_str(), 0));

throw_posix_error(EINVAL);

return {};
}

template <::std::integral char_type, posix_api_ct dsp, typename... Args>
inline auto dosct_api_dispatcher(int dirfd, char const *path, Args... args)
{
if constexpr (dsp == ::fast_io::details::posix_api_ct::readlinkat)
{
return dos_readlinkat_impl<char_type>(dirfd, path, args...);
}
}

template <posix_api_22 dsp, ::fast_io::constructible_to_os_c_str old_path_type,
::fast_io::constructible_to_os_c_str new_path_type, typename... Args>
inline auto dos_deal_with22(int olddirfd, old_path_type const &oldpath, int newdirfd, new_path_type const &newpath, Args... args)
Expand Down Expand Up @@ -293,6 +313,12 @@ inline auto dos_deal_with1x(int dirfd, path_type const &path, Args... args)
return ::fast_io::posix_api_common(path, [&](char const *path_c_str) { return dos1x_api_dispatcher<dsp>(dirfd, path_c_str, args...); });
}

template <::std::integral char_type, posix_api_ct dsp, ::fast_io::constructible_to_os_c_str path_type, typename... Args>
inline auto dos_deal_withct(int dirfd, path_type const &path, Args... args)
{
return ::fast_io::posix_api_common(path, [&](char const *path_c_str) { return dosct_api_dispatcher<char_type, dsp>(dirfd, path_c_str, args...); });
}

} // namespace details

template <::fast_io::constructible_to_os_c_str old_path_type, ::fast_io::constructible_to_os_c_str new_path_type>
Expand Down Expand Up @@ -337,17 +363,17 @@ inline void native_symlinkat(old_path_type const &oldpath, posix_at_entry newent


template <::fast_io::constructible_to_os_c_str path_type>
inline void dos_faccessat(posix_at_entry ent, path_type const &path, [[maybe_unused]] access_how mode,
dos_at_flags flags = dos_at_flags::symlink_nofollow)
inline void dos_faccessat(posix_at_entry ent, path_type const &path, access_how mode,
[[maybe_unused]] dos_at_flags flags = dos_at_flags::symlink_nofollow)
{
::fast_io::details::dos_deal_with1x<::fast_io::details::posix_api_1x::faccessat>(ent.fd, path, static_cast<int>(flags));
::fast_io::details::dos_deal_with1x<::fast_io::details::posix_api_1x::faccessat>(ent.fd, path, static_cast<int>(mode));
}

template <::fast_io::constructible_to_os_c_str path_type>
inline void native_faccessat(posix_at_entry ent, path_type const &path, [[maybe_unused]] access_how mode,
dos_at_flags flags = dos_at_flags::symlink_nofollow)
inline void native_faccessat(posix_at_entry ent, path_type const &path, access_how mode,
[[maybe_unused]] dos_at_flags flags = dos_at_flags::symlink_nofollow)
{
::fast_io::details::dos_deal_with1x<::fast_io::details::posix_api_1x::faccessat>(ent.fd, path, static_cast<int>(flags));
::fast_io::details::dos_deal_with1x<::fast_io::details::posix_api_1x::faccessat>(ent.fd, path, static_cast<int>(mode));
}

template <::fast_io::constructible_to_os_c_str path_type>
Expand Down Expand Up @@ -448,4 +474,16 @@ inline void native_utimensat(posix_at_entry ent, path_type const &path, unix_tim
last_modification_time);
}

template <::std::integral char_type, ::fast_io::constructible_to_os_c_str path_type>
inline ::fast_io::details::basic_ct_string<char_type> dos_readlinkat(posix_at_entry ent, path_type const &path)
{
return ::fast_io::details::dos_deal_withct<char_type, ::fast_io::details::posix_api_ct::readlinkat>(ent.fd, path);
}

template <::std::integral char_type, ::fast_io::constructible_to_os_c_str path_type>
inline ::fast_io::details::basic_ct_string<char_type> native_readlinkat(posix_at_entry ent, path_type const &path)
{
return ::fast_io::details::dos_deal_withct<char_type, ::fast_io::details::posix_api_ct::readlinkat>(ent.fd, path);
}

} // namespace fast_io
19 changes: 19 additions & 0 deletions include/fast_io_hosted/filesystem/fsutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,23 @@ find_dot_and_sep(char_type const *beg_ptr, ::std::size_t namlen) noexcept
}
}

template <::std::integral char_type>
using basic_ct_string = ::fast_io::containers::basic_string<char_type, ::fast_io::native_global_allocator>;

template <::std::integral char_type, typename... Args>
inline constexpr basic_ct_string<char_type> concat_ct(Args &&...args)
{
constexpr bool type_error{::fast_io::operations::defines::print_freestanding_okay<::fast_io::details::dummy_buffer_output_stream<char_type>,Args...>};
if constexpr (type_error)
{
return ::fast_io::details::decay::basic_general_concat_phase1_decay_impl<false, char_type, ::fast_io::containers::basic_string<char_type, ::fast_io::native_global_allocator>>(
io_print_forward<char_type>(io_print_alias(args))...);
}
else
{
static_assert(type_error, "some types are not printable, so we cannot concat ::fast_io::containers::basic_string<char_type>");
return {};
}
}

} // namespace fast_io::details
Loading