216 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9// REQUIRES: can-create-symlinks10// UNSUPPORTED: c++03, c++11, c++1411// UNSUPPORTED: no-filesystem12 13// Starting in Android N (API 24), SELinux policy prevents the shell user from14// creating a FIFO file.15// XFAIL: LIBCXX-ANDROID-FIXME && !android-device-api={{21|22|23}}16 17// <filesystem>18 19// file_status symlink_status(const path& p);20// file_status symlink_status(const path& p, error_code& ec) noexcept;21 22#include <filesystem>23 24#include "assert_macros.h"25#include "test_macros.h"26#include "filesystem_test_helper.h"27namespace fs = std::filesystem;28using namespace fs;29 30static void signature_test()31{32 const path p; ((void)p);33 std::error_code ec; ((void)ec);34 ASSERT_NOT_NOEXCEPT(symlink_status(p));35 ASSERT_NOEXCEPT(symlink_status(p, ec));36}37 38static void test_symlink_status_not_found()39{40 static_test_env static_env;41 const std::errc expect_errc = std::errc::no_such_file_or_directory;42 const path cases[] {43 static_env.DNE44 };45 for (auto& p : cases) {46 std::error_code ec = std::make_error_code(std::errc::address_in_use);47 // test non-throwing overload.48 file_status st = symlink_status(p, ec);49 assert(ErrorIs(ec, expect_errc));50 assert(st.type() == file_type::not_found);51 assert(st.permissions() == perms::unknown);52 // test throwing overload. It should not throw even though it reports53 // that the file was not found.54 TEST_DOES_NOT_THROW(st = status(p));55 assert(st.type() == file_type::not_found);56 assert(st.permissions() == perms::unknown);57 }58}59 60// Windows doesn't support setting perms::none to trigger failures61// reading directories. Imaginary files under GetWindowsInaccessibleDir()62// produce no_such_file_or_directory, not the error codes this test checks63// for. Finally, status() for a too long file name doesn't return errors64// on windows.65#ifndef TEST_WIN_NO_FILESYSTEM_PERMS_NONE66static void test_symlink_status_cannot_resolve()67{68 scoped_test_env env;69 const path dir = env.create_dir("dir");70 const path file_in_dir = env.create_file("dir/file", 42);71 const path sym_in_dir = env.create_symlink("dir/file", "dir/bad_sym");72 const path sym_points_in_dir = env.create_symlink("dir/file", "sym");73 permissions(dir, perms::none);74 75 const std::errc set_errc = std::errc::address_in_use;76 const std::errc expect_errc = std::errc::permission_denied;77 78 const path fail_cases[] = {79 file_in_dir, sym_in_dir80 };81 for (auto& p : fail_cases)82 {83 { // test non-throwing case84 std::error_code ec = std::make_error_code(set_errc);85 file_status st = symlink_status(p, ec);86 assert(ErrorIs(ec, expect_errc));87 assert(st.type() == file_type::none);88 assert(st.permissions() == perms::unknown);89 }90#ifndef TEST_HAS_NO_EXCEPTIONS91 { // test throwing case92 try {93 (void)symlink_status(p);94 } catch (filesystem_error const& err) {95 assert(err.path1() == p);96 assert(err.path2() == "");97 assert(ErrorIs(err.code(), expect_errc));98 }99 }100#endif101 }102 // Test that a symlink that points into a directory without read perms103 // can be stat-ed using symlink_status104 {105 std::error_code ec = std::make_error_code(set_errc);106 file_status st = symlink_status(sym_points_in_dir, ec);107 assert(!ec);108 assert(st.type() == file_type::symlink);109 assert(st.permissions() != perms::unknown);110 // test non-throwing version111 TEST_DOES_NOT_THROW(st = symlink_status(sym_points_in_dir));112 assert(st.type() == file_type::symlink);113 assert(st.permissions() != perms::unknown);114 }115}116#endif // TEST_WIN_NO_FILESYSTEM_PERMS_NONE117 118 119static void symlink_status_file_types_test()120{121 static_test_env static_env;122 scoped_test_env env;123 struct TestCase {124 path p;125 file_type expect_type;126 } cases[] = {127 {static_env.BadSymlink, file_type::symlink},128 {static_env.File, file_type::regular},129 {static_env.SymlinkToFile, file_type::symlink},130 {static_env.Dir, file_type::directory},131 {static_env.SymlinkToDir, file_type::symlink},132 // file_type::block files tested elsewhere133#ifndef _WIN32134 {static_env.CharFile, file_type::character},135#endif136#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(_WIN32) // No support for domain sockets137 {env.create_socket("socket"), file_type::socket},138#endif139#ifndef _WIN32140 {env.create_fifo("fifo"), file_type::fifo}141#endif142 };143 for (const auto& TC : cases) {144 // test non-throwing case145 std::error_code ec = std::make_error_code(std::errc::address_in_use);146 file_status st = symlink_status(TC.p, ec);147 assert(!ec);148 assert(st.type() == TC.expect_type);149 assert(st.permissions() != perms::unknown);150 // test throwing case151 TEST_DOES_NOT_THROW(st = symlink_status(TC.p));152 assert(st.type() == TC.expect_type);153 assert(st.permissions() != perms::unknown);154 }155}156 157static void test_block_file()158{159 const path possible_paths[] = {160 "/dev/drive0", // Apple161 "/dev/sda", // Linux162 "/dev/loop0" // Linux163 // No FreeBSD files known164 };165 path p;166 for (const path& possible_p : possible_paths) {167 std::error_code ec;168 if (exists(possible_p, ec)) {169 p = possible_p;170 break;171 }172 }173 if (p == path{}) {174 // No possible path found.175 return;176 }177 scoped_test_env env;178 { // test block file179 // test non-throwing case180 std::error_code ec = std::make_error_code(std::errc::address_in_use);181 file_status st = symlink_status(p, ec);182 assert(!ec);183 assert(st.type() == file_type::block);184 assert(st.permissions() != perms::unknown);185 // test throwing case186 TEST_DOES_NOT_THROW(st = symlink_status(p));187 assert(st.type() == file_type::block);188 assert(st.permissions() != perms::unknown);189 }190 const path sym = env.make_env_path("sym");191 create_symlink(p, sym);192 { // test symlink to block file193 // test non-throwing case194 std::error_code ec = std::make_error_code(std::errc::address_in_use);195 file_status st = symlink_status(sym, ec);196 assert(!ec);197 assert(st.type() == file_type::symlink);198 assert(st.permissions() != perms::unknown);199 // test throwing case200 TEST_DOES_NOT_THROW(st = symlink_status(sym));201 assert(st.type() == file_type::symlink);202 assert(st.permissions() != perms::unknown);203 }204}205 206int main(int, char**) {207 signature_test();208 test_symlink_status_not_found();209#ifndef TEST_WIN_NO_FILESYSTEM_PERMS_NONE210 test_symlink_status_cannot_resolve();211#endif212 symlink_status_file_types_test();213 test_block_file();214 return 0;215}216