2022-01-20 18:27:56 +00:00
|
|
|
// This file Copyright (C) 2013-2022 Mnemosyne LLC.
|
|
|
|
// It may be used under GPLv2 (SPDX: GPL-2.0), GPLv3 (SPDX: GPL-3.0),
|
|
|
|
// or any future license endorsed by Mnemosyne LLC.
|
|
|
|
// License text can be found in the licenses/ folder.
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
#include <array>
|
|
|
|
#include <cstring>
|
2022-03-21 20:22:50 +00:00
|
|
|
#include <ostream>
|
2020-08-11 18:11:55 +00:00
|
|
|
#include <string>
|
2022-04-08 01:50:26 +00:00
|
|
|
#include <string_view>
|
2022-05-21 16:10:58 +00:00
|
|
|
#include <utility>
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
#ifndef _WIN32
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#else
|
|
|
|
#include <windows.h>
|
|
|
|
#endif
|
|
|
|
|
2022-03-21 20:22:50 +00:00
|
|
|
#include "transmission.h"
|
|
|
|
|
|
|
|
#include "error.h"
|
|
|
|
#include "file.h"
|
|
|
|
#include "tr-macros.h"
|
2022-05-22 01:17:00 +00:00
|
|
|
#include "tr-strbuf.h"
|
2022-03-21 20:22:50 +00:00
|
|
|
|
|
|
|
#include "test-fixtures.h"
|
|
|
|
|
2020-08-11 18:11:55 +00:00
|
|
|
#if !defined(__OpenBSD__)
|
|
|
|
#define HAVE_UNIFIED_BUFFER_CACHE
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef _WIN32
|
|
|
|
#define NATIVE_PATH_SEP "/"
|
|
|
|
#else
|
|
|
|
#define NATIVE_PATH_SEP "\\"
|
|
|
|
#endif
|
|
|
|
|
2021-11-13 00:10:04 +00:00
|
|
|
using namespace std::literals;
|
|
|
|
|
2020-08-11 18:11:55 +00:00
|
|
|
namespace libtransmission
|
|
|
|
{
|
|
|
|
|
|
|
|
namespace test
|
|
|
|
{
|
|
|
|
|
|
|
|
class FileTest : public SessionTest
|
|
|
|
{
|
|
|
|
protected:
|
|
|
|
auto createTestDir(std::string const& child_name)
|
|
|
|
{
|
2022-07-23 07:13:18 +00:00
|
|
|
auto test_dir = tr_pathbuf{ session_->configDir(), '/', child_name };
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_dir_create(test_dir, 0, 0777);
|
2020-08-11 18:11:55 +00:00
|
|
|
return test_dir;
|
|
|
|
}
|
|
|
|
|
2022-01-24 19:07:55 +00:00
|
|
|
static bool createSymlink(char const* dst_path, char const* src_path, [[maybe_unused]] bool dst_is_dir)
|
2020-08-11 18:11:55 +00:00
|
|
|
{
|
|
|
|
#ifndef _WIN32
|
|
|
|
|
|
|
|
return symlink(src_path, dst_path) != -1;
|
|
|
|
|
|
|
|
#else
|
|
|
|
wchar_t* wide_src_path = tr_win32_utf8_to_native(src_path, -1);
|
|
|
|
wchar_t* wide_dst_path = tr_win32_utf8_to_native(dst_path, -1);
|
|
|
|
|
|
|
|
auto const ret = CreateSymbolicLinkW(wide_dst_path, wide_src_path, dst_is_dir ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0);
|
|
|
|
|
|
|
|
tr_free(wide_dst_path);
|
|
|
|
tr_free(wide_src_path);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2022-01-24 19:07:55 +00:00
|
|
|
static bool createHardlink(char const* dst_path, char const* src_path)
|
2020-08-11 18:11:55 +00:00
|
|
|
{
|
|
|
|
#ifndef _WIN32
|
|
|
|
|
|
|
|
return link(src_path, dst_path) != -1;
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
wchar_t* wide_src_path = tr_win32_utf8_to_native(src_path, -1);
|
|
|
|
wchar_t* wide_dst_path = tr_win32_utf8_to_native(dst_path, -1);
|
|
|
|
|
|
|
|
auto const ret = CreateHardLinkW(wide_dst_path, wide_src_path, nullptr);
|
|
|
|
|
|
|
|
tr_free(wide_dst_path);
|
|
|
|
tr_free(wide_src_path);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2022-01-24 19:07:55 +00:00
|
|
|
static void clearPathInfo(tr_sys_path_info* info)
|
2020-08-11 18:11:55 +00:00
|
|
|
{
|
|
|
|
*info = {};
|
|
|
|
}
|
|
|
|
|
2022-01-24 19:07:55 +00:00
|
|
|
static bool pathContainsNoSymlinks(char const* path)
|
2020-08-11 18:11:55 +00:00
|
|
|
{
|
|
|
|
char const* p = path;
|
|
|
|
|
|
|
|
while (*p != '\0')
|
|
|
|
{
|
|
|
|
tr_sys_path_info info;
|
|
|
|
char const* slash_pos = strchr(p, '/');
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
|
|
|
char const* backslash_pos = strchr(p, '\\');
|
|
|
|
|
|
|
|
if (slash_pos == nullptr || (backslash_pos != nullptr && backslash_pos < slash_pos))
|
|
|
|
{
|
|
|
|
slash_pos = backslash_pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (slash_pos == nullptr)
|
|
|
|
{
|
|
|
|
slash_pos = p + strlen(p) - 1;
|
|
|
|
}
|
|
|
|
|
2021-12-16 02:09:46 +00:00
|
|
|
auto const path_part = std::string{ path, size_t(slash_pos - path + 1) };
|
2022-05-24 04:05:16 +00:00
|
|
|
|
|
|
|
if (!tr_sys_path_get_info(path_part.c_str(), TR_SYS_PATH_NO_FOLLOW, &info) ||
|
2020-08-11 18:11:55 +00:00
|
|
|
(info.type != TR_SYS_PATH_IS_FILE && info.type != TR_SYS_PATH_IS_DIRECTORY))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
p = slash_pos + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-01-24 19:07:55 +00:00
|
|
|
static bool validatePermissions([[maybe_unused]] char const* path, [[maybe_unused]] unsigned int permissions)
|
2020-08-11 18:11:55 +00:00
|
|
|
{
|
|
|
|
#ifndef _WIN32
|
|
|
|
|
|
|
|
struct stat sb = {};
|
|
|
|
return stat(path, &sb) != -1 && (sb.st_mode & 0777) == permissions;
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
/* No UNIX permissions on Windows */
|
|
|
|
return true;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
struct XnameTestData
|
|
|
|
{
|
|
|
|
char const* input;
|
|
|
|
char const* output;
|
|
|
|
};
|
|
|
|
|
2022-03-21 20:22:50 +00:00
|
|
|
static void testPathXname(XnameTestData const* data, size_t data_size, std::string (*func)(std::string_view, tr_error**))
|
2020-08-11 18:11:55 +00:00
|
|
|
{
|
|
|
|
for (size_t i = 0; i < data_size; ++i)
|
|
|
|
{
|
|
|
|
tr_error* err = nullptr;
|
2022-03-21 20:22:50 +00:00
|
|
|
auto const name = func(data[i].input, &err);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
if (data[i].output != nullptr)
|
|
|
|
{
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_NE(""sv, name);
|
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
|
|
|
EXPECT_EQ(data[i].output, name);
|
2020-08-11 18:11:55 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(""sv, name);
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_NE(nullptr, err);
|
|
|
|
tr_error_clear(&err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
static void testDirReadImpl(tr_pathbuf const& path, bool* have1, bool* have2)
|
2020-08-11 18:11:55 +00:00
|
|
|
{
|
|
|
|
*have1 = *have2 = false;
|
|
|
|
|
|
|
|
tr_error* err = nullptr;
|
2022-04-22 16:35:56 +00:00
|
|
|
auto dd = tr_sys_dir_open(path, &err);
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_NE(TR_BAD_SYS_DIR, dd);
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
char const* name;
|
|
|
|
while ((name = tr_sys_dir_read_name(dd, &err)) != nullptr)
|
|
|
|
{
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strcmp(name, "a") == 0)
|
|
|
|
{
|
|
|
|
*have1 = true;
|
|
|
|
}
|
|
|
|
else if (strcmp(name, "b") == 0)
|
|
|
|
{
|
|
|
|
*have2 = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FAIL();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
EXPECT_TRUE(tr_sys_dir_close(dd, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
TEST_F(FileTest, getInfo)
|
|
|
|
{
|
|
|
|
auto const test_dir = createTestDir(currentTestName());
|
|
|
|
tr_sys_path_info info;
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
auto const path1 = tr_pathbuf{ test_dir, "/a"sv };
|
|
|
|
auto const path2 = tr_pathbuf{ test_dir, "/b"sv };
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
// Can't get info of non-existent file/directory
|
|
|
|
tr_error* err = nullptr;
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_get_info(path1, 0, &info, &err));
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_NE(nullptr, err);
|
|
|
|
tr_error_clear(&err);
|
|
|
|
|
|
|
|
auto t = time(nullptr);
|
|
|
|
createFileWithContents(path1, "test");
|
|
|
|
|
|
|
|
// Good file info
|
|
|
|
clearPathInfo(&info);
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_path_get_info(path1, 0, &info, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(TR_SYS_PATH_IS_FILE, info.type);
|
|
|
|
EXPECT_EQ(4, info.size);
|
2022-03-25 00:03:15 +00:00
|
|
|
EXPECT_GE(info.last_modified_at, t - 1);
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_LE(info.last_modified_at, time(nullptr) + 1);
|
|
|
|
|
|
|
|
// Good file info (by handle)
|
2022-04-22 16:35:56 +00:00
|
|
|
auto fd = tr_sys_file_open(path1, TR_SYS_FILE_READ, 0);
|
2020-08-11 18:11:55 +00:00
|
|
|
clearPathInfo(&info);
|
|
|
|
EXPECT_TRUE(tr_sys_file_get_info(fd, &info, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(TR_SYS_PATH_IS_FILE, info.type);
|
|
|
|
EXPECT_EQ(4, info.size);
|
2022-03-25 00:03:15 +00:00
|
|
|
EXPECT_GE(info.last_modified_at, t - 1);
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_LE(info.last_modified_at, time(nullptr) + 1);
|
2022-03-27 17:37:29 +00:00
|
|
|
tr_sys_file_close(fd);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path1);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
// Good directory info
|
|
|
|
t = time(nullptr);
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_dir_create(path1, 0, 0777);
|
2020-08-11 18:11:55 +00:00
|
|
|
clearPathInfo(&info);
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_path_get_info(path1, 0, &info, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(TR_SYS_PATH_IS_DIRECTORY, info.type);
|
|
|
|
EXPECT_NE(uint64_t(-1), info.size);
|
|
|
|
EXPECT_GE(info.last_modified_at, t - 1);
|
|
|
|
EXPECT_LE(info.last_modified_at, time(nullptr) + 1);
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path1);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
if (createSymlink(path1, path2, false))
|
2020-08-11 18:11:55 +00:00
|
|
|
{
|
|
|
|
// Can't get info of non-existent file/directory
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_get_info(path1, 0, &info, &err));
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_NE(nullptr, err);
|
|
|
|
tr_error_clear(&err);
|
|
|
|
|
|
|
|
t = time(nullptr);
|
|
|
|
createFileWithContents(path2, "test");
|
|
|
|
|
|
|
|
// Good file info
|
|
|
|
clearPathInfo(&info);
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_path_get_info(path1, 0, &info, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(TR_SYS_PATH_IS_FILE, info.type);
|
|
|
|
EXPECT_EQ(4, info.size);
|
|
|
|
EXPECT_GE(info.last_modified_at, t - 1);
|
|
|
|
EXPECT_LE(info.last_modified_at, time(nullptr) + 1);
|
|
|
|
|
|
|
|
// Good file info (by handle)
|
2022-04-22 16:35:56 +00:00
|
|
|
fd = tr_sys_file_open(path1, TR_SYS_FILE_READ, 0);
|
2020-08-11 18:11:55 +00:00
|
|
|
clearPathInfo(&info);
|
|
|
|
EXPECT_TRUE(tr_sys_file_get_info(fd, &info, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(TR_SYS_PATH_IS_FILE, info.type);
|
|
|
|
EXPECT_EQ(4, info.size);
|
|
|
|
EXPECT_GE(info.last_modified_at, t - 1);
|
|
|
|
EXPECT_LE(info.last_modified_at, time(nullptr) + 1);
|
2022-03-27 17:37:29 +00:00
|
|
|
tr_sys_file_close(fd);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path2);
|
|
|
|
tr_sys_path_remove(path1);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
// Good directory info
|
|
|
|
t = time(nullptr);
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_dir_create(path2, 0, 0777);
|
|
|
|
EXPECT_TRUE(createSymlink(path1, path2, true)); /* Win32: directory and file symlinks differ :( */
|
2020-08-11 18:11:55 +00:00
|
|
|
clearPathInfo(&info);
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_path_get_info(path1, 0, &info, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(TR_SYS_PATH_IS_DIRECTORY, info.type);
|
|
|
|
EXPECT_NE(uint64_t(-1), info.size);
|
|
|
|
EXPECT_GE(info.last_modified_at, t - 1);
|
|
|
|
EXPECT_LE(info.last_modified_at, time(nullptr) + 1);
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path2);
|
|
|
|
tr_sys_path_remove(path1);
|
2020-08-11 18:11:55 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fprintf(stderr, "WARNING: [%s] unable to run symlink tests\n", __FUNCTION__);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(FileTest, pathExists)
|
|
|
|
{
|
|
|
|
auto const test_dir = createTestDir(currentTestName());
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
auto const path1 = tr_pathbuf{ test_dir, "/a"sv };
|
|
|
|
auto const path2 = tr_pathbuf{ test_dir, "/b"sv };
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
// Non-existent file does not exist
|
|
|
|
tr_error* err = nullptr;
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_exists(path1, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
// Create file and see that it exists
|
|
|
|
createFileWithContents(path1, "test");
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_path_exists(path1, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path1);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
// Create directory and see that it exists
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_dir_create(path1, 0, 0777);
|
|
|
|
EXPECT_TRUE(tr_sys_path_exists(path1, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path1);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
if (createSymlink(path1, path2, false))
|
2020-08-11 18:11:55 +00:00
|
|
|
{
|
|
|
|
// Non-existent file does not exist (via symlink)
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_exists(path1, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
// Create file and see that it exists (via symlink)
|
|
|
|
createFileWithContents(path2, "test");
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_path_exists(path1, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path2);
|
|
|
|
tr_sys_path_remove(path1);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
/* Create directory and see that it exists (via symlink) */
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_dir_create(path2, 0, 0777);
|
|
|
|
EXPECT_TRUE(createSymlink(path1, path2, true)); /* Win32: directory and file symlinks differ :( */
|
|
|
|
EXPECT_TRUE(tr_sys_path_exists(path1, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path2);
|
|
|
|
tr_sys_path_remove(path1);
|
2020-08-11 18:11:55 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fprintf(stderr, "WARNING: [%s] unable to run symlink tests\n", __FUNCTION__);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(FileTest, pathIsRelative)
|
|
|
|
{
|
|
|
|
EXPECT_TRUE(tr_sys_path_is_relative(""));
|
|
|
|
EXPECT_TRUE(tr_sys_path_is_relative("."));
|
|
|
|
EXPECT_TRUE(tr_sys_path_is_relative(".."));
|
|
|
|
EXPECT_TRUE(tr_sys_path_is_relative("x"));
|
|
|
|
EXPECT_TRUE(tr_sys_path_is_relative("\\"));
|
|
|
|
EXPECT_TRUE(tr_sys_path_is_relative(":"));
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
|
|
|
EXPECT_TRUE(tr_sys_path_is_relative("/"));
|
|
|
|
EXPECT_TRUE(tr_sys_path_is_relative("\\x"));
|
|
|
|
EXPECT_TRUE(tr_sys_path_is_relative("/x"));
|
|
|
|
EXPECT_TRUE(tr_sys_path_is_relative("\\x\\y"));
|
|
|
|
EXPECT_TRUE(tr_sys_path_is_relative("/x/y"));
|
|
|
|
EXPECT_TRUE(tr_sys_path_is_relative("C:x"));
|
|
|
|
EXPECT_TRUE(tr_sys_path_is_relative("C:x\\y"));
|
|
|
|
EXPECT_TRUE(tr_sys_path_is_relative("C:x/y"));
|
|
|
|
|
|
|
|
EXPECT_FALSE(tr_sys_path_is_relative("\\\\"));
|
|
|
|
EXPECT_FALSE(tr_sys_path_is_relative("//"));
|
|
|
|
EXPECT_FALSE(tr_sys_path_is_relative("\\\\x"));
|
|
|
|
EXPECT_FALSE(tr_sys_path_is_relative("//x"));
|
|
|
|
EXPECT_FALSE(tr_sys_path_is_relative("\\\\x\\y"));
|
|
|
|
EXPECT_FALSE(tr_sys_path_is_relative("//x/y"));
|
|
|
|
EXPECT_FALSE(tr_sys_path_is_relative("\\\\.\\x"));
|
|
|
|
EXPECT_FALSE(tr_sys_path_is_relative("//./x"));
|
|
|
|
|
|
|
|
EXPECT_FALSE(tr_sys_path_is_relative("a:"));
|
|
|
|
EXPECT_FALSE(tr_sys_path_is_relative("a:\\"));
|
|
|
|
EXPECT_FALSE(tr_sys_path_is_relative("a:/"));
|
|
|
|
EXPECT_FALSE(tr_sys_path_is_relative("Z:"));
|
|
|
|
EXPECT_FALSE(tr_sys_path_is_relative("Z:\\"));
|
|
|
|
EXPECT_FALSE(tr_sys_path_is_relative("Z:/"));
|
|
|
|
|
|
|
|
#else /* _WIN32 */
|
|
|
|
|
|
|
|
EXPECT_FALSE(tr_sys_path_is_relative("/"));
|
|
|
|
EXPECT_FALSE(tr_sys_path_is_relative("/x"));
|
|
|
|
EXPECT_FALSE(tr_sys_path_is_relative("/x/y"));
|
|
|
|
EXPECT_FALSE(tr_sys_path_is_relative("//x"));
|
|
|
|
|
|
|
|
#endif /* _WIN32 */
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(FileTest, pathIsSame)
|
|
|
|
{
|
2022-05-22 01:17:00 +00:00
|
|
|
// NOLINTBEGIN(readability-suspicious-call-argument)
|
|
|
|
|
2020-08-11 18:11:55 +00:00
|
|
|
auto const test_dir = createTestDir(currentTestName());
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
auto const path1 = tr_pathbuf{ test_dir, "/a"sv };
|
|
|
|
auto const path2 = tr_pathbuf{ test_dir, "/b"sv };
|
|
|
|
auto path3 = tr_pathbuf{ path2, "/c"sv };
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
/* Two non-existent files are not the same */
|
|
|
|
tr_error* err = nullptr;
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_is_same(path1, path1, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_is_same(path1, path2, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
/* Two same files are the same */
|
|
|
|
createFileWithContents(path1, "test");
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_path_is_same(path1, path1, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
/* Existent and non-existent files are not the same */
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_is_same(path1, path2, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_is_same(path2, path1, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
/* Two separate files (even with same content) are not the same */
|
|
|
|
createFileWithContents(path2, "test");
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_is_same(path1, path2, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path1);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
/* Two same directories are the same */
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_dir_create(path1, 0, 0777);
|
|
|
|
EXPECT_TRUE(tr_sys_path_is_same(path1, path1, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
/* File and directory are not the same */
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_is_same(path1, path2, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_is_same(path2, path1, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path2);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
/* Two separate directories are not the same */
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_dir_create(path2, 0, 0777);
|
|
|
|
EXPECT_FALSE(tr_sys_path_is_same(path1, path2, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path1);
|
|
|
|
tr_sys_path_remove(path2);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
if (createSymlink(path1, ".", true))
|
2020-08-11 18:11:55 +00:00
|
|
|
{
|
|
|
|
/* Directory and symlink pointing to it are the same */
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_path_is_same(path1, test_dir.data(), &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_path_is_same(test_dir.data(), path1, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
/* Non-existent file and symlink are not the same */
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_is_same(path1, path2, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_is_same(path2, path1, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
/* Symlinks pointing to different directories are not the same */
|
2022-04-22 16:35:56 +00:00
|
|
|
createSymlink(path2, "..", true);
|
|
|
|
EXPECT_FALSE(tr_sys_path_is_same(path1, path2, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_is_same(path2, path1, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path2);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
/* Symlinks pointing to same directory are the same */
|
2022-04-22 16:35:56 +00:00
|
|
|
createSymlink(path2, ".", true);
|
|
|
|
EXPECT_TRUE(tr_sys_path_is_same(path1, path2, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path2);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
/* Directory and symlink pointing to another directory are not the same */
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_dir_create(path2, 0, 0777);
|
|
|
|
EXPECT_FALSE(tr_sys_path_is_same(path1, path2, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_is_same(path2, path1, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
/* Symlinks pointing to same directory are the same */
|
2022-04-22 16:35:56 +00:00
|
|
|
createSymlink(path3, "..", true);
|
|
|
|
EXPECT_TRUE(tr_sys_path_is_same(path1, path3, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path1);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
/* File and symlink pointing to directory are not the same */
|
|
|
|
createFileWithContents(path1, "test");
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_is_same(path1, path3, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_is_same(path3, path1, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path3);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
/* File and symlink pointing to same file are the same */
|
2022-04-22 16:35:56 +00:00
|
|
|
createSymlink(path3, path1, false);
|
|
|
|
EXPECT_TRUE(tr_sys_path_is_same(path1, path3, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_path_is_same(path3, path1, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
/* Symlinks pointing to non-existent files are not the same */
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path1);
|
|
|
|
createSymlink(path1, "missing", false);
|
|
|
|
tr_sys_path_remove(path3);
|
|
|
|
createSymlink(path3, "missing", false);
|
|
|
|
EXPECT_FALSE(tr_sys_path_is_same(path1, path3, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_is_same(path3, path1, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path3);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
/* Symlinks pointing to same non-existent file are not the same */
|
2021-11-13 00:10:04 +00:00
|
|
|
createSymlink(path3.c_str(), ".." NATIVE_PATH_SEP "missing", false);
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_is_same(path1, path3, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_is_same(path3, path1, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
/* Non-existent file and symlink pointing to non-existent file are not the same */
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path3);
|
|
|
|
EXPECT_FALSE(tr_sys_path_is_same(path1, path3, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_is_same(path3, path1, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path2);
|
|
|
|
tr_sys_path_remove(path1);
|
2020-08-11 18:11:55 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fprintf(stderr, "WARNING: [%s] unable to run symlink tests\n", __FUNCTION__);
|
|
|
|
}
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
path3.assign(test_dir, "/c"sv);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
createFileWithContents(path1, "test");
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
if (createHardlink(path2, path1))
|
2020-08-11 18:11:55 +00:00
|
|
|
{
|
|
|
|
/* File and hardlink to it are the same */
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_path_is_same(path1, path2, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
/* Two hardlinks to the same file are the same */
|
2022-04-22 16:35:56 +00:00
|
|
|
createHardlink(path3, path2);
|
|
|
|
EXPECT_TRUE(tr_sys_path_is_same(path2, path3, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_path_is_same(path1, path3, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path2);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_path_is_same(path1, path3, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path3);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
/* File and hardlink to another file are not the same */
|
|
|
|
createFileWithContents(path3, "test");
|
2022-04-22 16:35:56 +00:00
|
|
|
createHardlink(path2, path3);
|
|
|
|
EXPECT_FALSE(tr_sys_path_is_same(path1, path2, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_is_same(path2, path1, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path3);
|
|
|
|
tr_sys_path_remove(path2);
|
2020-08-11 18:11:55 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fprintf(stderr, "WARNING: [%s] unable to run hardlink tests\n", __FUNCTION__);
|
|
|
|
}
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
if (createSymlink(path2, path1, false) && createHardlink(path3, path1))
|
2020-08-11 18:11:55 +00:00
|
|
|
{
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_path_is_same(path2, path3, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fprintf(stderr, "WARNING: [%s] unable to run combined symlink and hardlink tests\n", __FUNCTION__);
|
|
|
|
}
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path3);
|
|
|
|
tr_sys_path_remove(path2);
|
|
|
|
tr_sys_path_remove(path1);
|
2022-05-22 01:17:00 +00:00
|
|
|
|
|
|
|
// NOLINTEND(readability-suspicious-call-argument)
|
2020-08-11 18:11:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(FileTest, pathResolve)
|
|
|
|
{
|
|
|
|
auto const test_dir = createTestDir(currentTestName());
|
|
|
|
|
|
|
|
tr_error* err = nullptr;
|
2022-04-22 16:35:56 +00:00
|
|
|
auto const path1 = tr_pathbuf{ test_dir, "/a"sv };
|
|
|
|
auto const path2 = tr_pathbuf{ test_dir, "/b"sv };
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
createFileWithContents(path1, "test");
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
if (createSymlink(path2, path1, false))
|
2020-08-11 18:11:55 +00:00
|
|
|
{
|
2022-04-22 16:35:56 +00:00
|
|
|
auto tmp = makeString(tr_sys_path_resolve(path2, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_TRUE(pathContainsNoSymlinks(tmp.c_str()));
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path2);
|
|
|
|
tr_sys_path_remove(path1);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_dir_create(path1, 0, 0755);
|
|
|
|
EXPECT_TRUE(createSymlink(path2, path1, true)); /* Win32: directory and file symlinks differ :( */
|
|
|
|
tmp = makeString(tr_sys_path_resolve(path2, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_TRUE(pathContainsNoSymlinks(tmp.c_str()));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fprintf(stderr, "WARNING: [%s] unable to run symlink tests\n", __FUNCTION__);
|
|
|
|
}
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path2);
|
|
|
|
tr_sys_path_remove(path1);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
|
|
|
{
|
|
|
|
char* tmp;
|
|
|
|
|
|
|
|
tmp = tr_sys_path_resolve("\\\\127.0.0.1\\NonExistent", &err);
|
|
|
|
EXPECT_EQ(nullptr, tmp);
|
|
|
|
EXPECT_NE(nullptr, err);
|
|
|
|
tr_error_clear(&err);
|
|
|
|
|
|
|
|
tmp = tr_sys_path_resolve("\\\\127.0.0.1\\ADMIN$\\NonExistent", &err);
|
|
|
|
EXPECT_EQ(nullptr, tmp);
|
|
|
|
EXPECT_NE(nullptr, err);
|
|
|
|
tr_error_clear(&err);
|
|
|
|
|
|
|
|
tmp = tr_sys_path_resolve("\\\\127.0.0.1\\ADMIN$\\System32", &err);
|
|
|
|
EXPECT_STREQ("\\\\127.0.0.1\\ADMIN$\\System32", tmp);
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
tr_free(tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2022-05-21 16:10:58 +00:00
|
|
|
TEST_F(FileTest, pathBasename)
|
2020-08-11 18:11:55 +00:00
|
|
|
{
|
|
|
|
auto const common_xname_tests = std::vector<XnameTestData>{
|
|
|
|
XnameTestData{ "/", "/" },
|
|
|
|
{ "", "." },
|
|
|
|
#ifdef _WIN32
|
2021-08-15 09:41:48 +00:00
|
|
|
{ "\\", "/" },
|
2020-08-11 18:11:55 +00:00
|
|
|
/* Invalid paths */
|
|
|
|
{ "\\\\\\", nullptr },
|
|
|
|
{ "123:", nullptr },
|
|
|
|
/* Reserved characters */
|
|
|
|
{ "<", nullptr },
|
|
|
|
{ ">", nullptr },
|
|
|
|
{ ":", nullptr },
|
|
|
|
{ "\"", nullptr },
|
|
|
|
{ "|", nullptr },
|
|
|
|
{ "?", nullptr },
|
|
|
|
{ "*", nullptr },
|
|
|
|
{ "a\\<", nullptr },
|
|
|
|
{ "a\\>", nullptr },
|
|
|
|
{ "a\\:", nullptr },
|
|
|
|
{ "a\\\"", nullptr },
|
|
|
|
{ "a\\|", nullptr },
|
|
|
|
{ "a\\?", nullptr },
|
|
|
|
{ "a\\*", nullptr },
|
|
|
|
{ "c:\\a\\b<c\\d", nullptr },
|
|
|
|
{ "c:\\a\\b>c\\d", nullptr },
|
|
|
|
{ "c:\\a\\b:c\\d", nullptr },
|
|
|
|
{ "c:\\a\\b\"c\\d", nullptr },
|
|
|
|
{ "c:\\a\\b|c\\d", nullptr },
|
|
|
|
{ "c:\\a\\b?c\\d", nullptr },
|
2021-08-15 09:41:48 +00:00
|
|
|
{ "c:\\a\\b*c\\d", nullptr },
|
2020-08-11 18:11:55 +00:00
|
|
|
#else
|
2021-08-15 09:41:48 +00:00
|
|
|
{ "////", "/" },
|
2020-08-11 18:11:55 +00:00
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
testPathXname(common_xname_tests.data(), common_xname_tests.size(), tr_sys_path_basename);
|
2022-05-21 16:10:58 +00:00
|
|
|
// testPathXname(common_xname_tests.data(), common_xname_tests.size(), tr_sys_path_dirname);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
auto const basename_tests = std::vector<XnameTestData>{
|
|
|
|
XnameTestData{ "a", "a" },
|
|
|
|
{ "aa", "aa" },
|
|
|
|
{ "/aa", "aa" },
|
|
|
|
{ "/a/b/c", "c" },
|
|
|
|
{ "/a/b/c/", "c" },
|
|
|
|
#ifdef _WIN32
|
2021-08-15 09:41:48 +00:00
|
|
|
{ "c:\\a\\b\\c", "c" },
|
2020-08-11 18:11:55 +00:00
|
|
|
{ "c:", "/" },
|
|
|
|
{ "c:/", "/" },
|
|
|
|
{ "c:\\", "/" },
|
|
|
|
{ "c:a/b", "b" },
|
|
|
|
{ "c:a", "a" },
|
|
|
|
{ "\\\\a\\b\\c", "c" },
|
|
|
|
{ "//a/b", "b" },
|
|
|
|
{ "//1.2.3.4/b", "b" },
|
|
|
|
{ "\\\\a", "a" },
|
|
|
|
{ "\\\\1.2.3.4", "1.2.3.4" },
|
|
|
|
{ "\\", "/" },
|
2021-08-15 09:41:48 +00:00
|
|
|
{ "\\a", "a" },
|
2020-08-11 18:11:55 +00:00
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
testPathXname(basename_tests.data(), basename_tests.size(), tr_sys_path_basename);
|
2022-05-21 16:10:58 +00:00
|
|
|
}
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-05-21 16:10:58 +00:00
|
|
|
TEST_F(FileTest, pathDirname)
|
|
|
|
{
|
2020-08-11 18:11:55 +00:00
|
|
|
#ifdef _WIN32
|
2022-05-21 16:10:58 +00:00
|
|
|
static auto constexpr DirnameTests = std::array<std::pair<std::string_view, std::string_view>, 48>{ {
|
|
|
|
{ "C:\\a/b\\c"sv, "C:\\a/b"sv },
|
|
|
|
{ "C:\\a/b\\c\\"sv, "C:\\a/b"sv },
|
|
|
|
{ "C:\\a/b"sv, "C:\\a"sv },
|
|
|
|
{ "C:/a"sv, "C:/"sv },
|
|
|
|
{ "C:"sv, "C:"sv },
|
|
|
|
{ "C:/"sv, "C:/"sv },
|
|
|
|
{ "c:a/b"sv, "c:a"sv },
|
|
|
|
{ "c:a"sv, "c:"sv },
|
|
|
|
{ "\\\\a"sv, "\\"sv },
|
|
|
|
{ "\\\\1.2.3.4"sv, "\\"sv },
|
|
|
|
{ "\\\\"sv, "\\"sv },
|
|
|
|
{ "a/b\\c"sv, "a/b"sv },
|
|
|
|
// taken from Node.js unit tests
|
|
|
|
// https://github.com/nodejs/node/blob/e46c680bf2b211bbd52cf959ca17ee98c7f657f5/test/parallel/test-path-dirname.js
|
|
|
|
{ "c:\\"sv, "c:\\"sv },
|
|
|
|
{ "c:\\foo"sv, "c:\\"sv },
|
|
|
|
{ "c:\\foo\\"sv, "c:\\"sv },
|
|
|
|
{ "c:\\foo\\bar"sv, "c:\\foo"sv },
|
|
|
|
{ "c:\\foo\\bar\\"sv, "c:\\foo"sv },
|
|
|
|
{ "c:\\foo\\bar\\baz"sv, "c:\\foo\\bar"sv },
|
|
|
|
{ "c:\\foo bar\\baz"sv, "c:\\foo bar"sv },
|
|
|
|
{ "\\"sv, "\\"sv },
|
|
|
|
{ "\\foo"sv, "\\"sv },
|
|
|
|
{ "\\foo\\"sv, "\\"sv },
|
|
|
|
{ "\\foo\\bar"sv, "\\foo"sv },
|
|
|
|
{ "\\foo\\bar\\"sv, "\\foo"sv },
|
|
|
|
{ "\\foo\\bar\\baz"sv, "\\foo\\bar"sv },
|
|
|
|
{ "\\foo bar\\baz"sv, "\\foo bar"sv },
|
|
|
|
{ "c:"sv, "c:"sv },
|
|
|
|
{ "c:foo"sv, "c:"sv },
|
|
|
|
{ "c:foo\\"sv, "c:"sv },
|
|
|
|
{ "c:foo\\bar"sv, "c:foo"sv },
|
|
|
|
{ "c:foo\\bar\\"sv, "c:foo"sv },
|
|
|
|
{ "c:foo\\bar\\baz"sv, "c:foo\\bar"sv },
|
|
|
|
{ "c:foo bar\\baz"sv, "c:foo bar"sv },
|
|
|
|
{ "file:stream"sv, "."sv },
|
|
|
|
{ "dir\\file:stream"sv, "dir"sv },
|
|
|
|
{ "\\\\unc\\share"sv, "\\\\unc\\share"sv },
|
|
|
|
{ "\\\\unc\\share\\foo"sv, "\\\\unc\\share\\"sv },
|
|
|
|
{ "\\\\unc\\share\\foo\\"sv, "\\\\unc\\share\\"sv },
|
|
|
|
{ "\\\\unc\\share\\foo\\bar"sv, "\\\\unc\\share\\foo"sv },
|
|
|
|
{ "\\\\unc\\share\\foo\\bar\\"sv, "\\\\unc\\share\\foo"sv },
|
|
|
|
{ "\\\\unc\\share\\foo\\bar\\baz"sv, "\\\\unc\\share\\foo\\bar"sv },
|
|
|
|
{ "/a/b/"sv, "/a"sv },
|
|
|
|
{ "/a/b"sv, "/a"sv },
|
|
|
|
{ "/a"sv, "/"sv },
|
|
|
|
{ ""sv, "."sv },
|
|
|
|
{ "/"sv, "/"sv },
|
|
|
|
{ "////"sv, "/"sv },
|
|
|
|
{ "foo"sv, "."sv },
|
|
|
|
} };
|
|
|
|
#else
|
|
|
|
static auto constexpr DirnameTests = std::array<std::pair<std::string_view, std::string_view>, 15>{ {
|
|
|
|
// taken from Node.js unit tests
|
|
|
|
// https://github.com/nodejs/node/blob/e46c680bf2b211bbd52cf959ca17ee98c7f657f5/test/parallel/test-path-dirname.js
|
|
|
|
{ "/a/b/"sv, "/a"sv },
|
|
|
|
{ "/a/b"sv, "/a"sv },
|
|
|
|
{ "/a"sv, "/"sv },
|
|
|
|
{ ""sv, "."sv },
|
|
|
|
{ "/"sv, "/"sv },
|
|
|
|
{ "////"sv, "/"sv },
|
|
|
|
{ "//a"sv, "//"sv },
|
|
|
|
{ "foo"sv, "."sv },
|
|
|
|
// taken from dirname(3) manpage
|
|
|
|
{ "usr"sv, "."sv },
|
|
|
|
{ "/usr/lib", "/usr"sv },
|
|
|
|
{ "/usr/"sv, "/"sv },
|
|
|
|
{ "/usr/"sv, "/"sv },
|
|
|
|
{ "/"sv, "/"sv },
|
|
|
|
{ "."sv, "."sv },
|
|
|
|
{ ".."sv, "."sv },
|
|
|
|
} };
|
2020-08-11 18:11:55 +00:00
|
|
|
#endif
|
|
|
|
|
2022-05-21 16:10:58 +00:00
|
|
|
for (auto const& [input, expected] : DirnameTests)
|
|
|
|
{
|
|
|
|
EXPECT_EQ(expected, tr_sys_path_dirname(input)) << "input[" << input << "] expected [" << expected << "] actual ["
|
|
|
|
<< tr_sys_path_dirname(input) << ']' << std::endl;
|
2022-05-22 01:17:00 +00:00
|
|
|
|
|
|
|
auto path = tr_pathbuf{ input };
|
|
|
|
path.popdir();
|
|
|
|
EXPECT_EQ(expected, path) << "input[" << input << "] expected [" << expected << "] actual [" << path << ']'
|
|
|
|
<< std::endl;
|
2022-05-21 16:10:58 +00:00
|
|
|
}
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
/* TODO: is_same(dirname(x) + '/' + basename(x), x) */
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(FileTest, pathRename)
|
|
|
|
{
|
|
|
|
auto const test_dir = createTestDir(currentTestName());
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
auto const path1 = tr_pathbuf{ test_dir, "/a"sv };
|
|
|
|
auto const path2 = tr_pathbuf{ test_dir, "/b"sv };
|
|
|
|
auto path3 = tr_pathbuf{ path2, "/c"sv };
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
createFileWithContents(path1, "test");
|
|
|
|
|
|
|
|
/* Preconditions */
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_path_exists(path1));
|
|
|
|
EXPECT_FALSE(tr_sys_path_exists(path2));
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
/* Forward rename works */
|
|
|
|
tr_error* err = nullptr;
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_path_rename(path1, path2, &err));
|
|
|
|
EXPECT_FALSE(tr_sys_path_exists(path1));
|
|
|
|
EXPECT_TRUE(tr_sys_path_exists(path2));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
/* Backward rename works */
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_path_rename(path2, path1, &err));
|
|
|
|
EXPECT_TRUE(tr_sys_path_exists(path1));
|
|
|
|
EXPECT_FALSE(tr_sys_path_exists(path2));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
/* Another backward rename [of non-existent file] does not work */
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_rename(path2, path1, &err));
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_NE(nullptr, err);
|
|
|
|
tr_error_clear(&err);
|
|
|
|
|
|
|
|
/* Rename to file which couldn't be created does not work */
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_rename(path1, path3, &err));
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_NE(nullptr, err);
|
|
|
|
tr_error_clear(&err);
|
|
|
|
|
|
|
|
/* Rename of non-existent file does not work */
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_rename(path3, path2, &err));
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_NE(nullptr, err);
|
|
|
|
tr_error_clear(&err);
|
|
|
|
|
|
|
|
createFileWithContents(path2, "test");
|
|
|
|
|
|
|
|
/* Renaming file does overwrite existing file */
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_path_rename(path2, path1, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_dir_create(path2, 0, 0777);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
/* Renaming file does not overwrite existing directory, and vice versa */
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_rename(path1, path2, &err));
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_NE(nullptr, err);
|
|
|
|
tr_error_clear(&err);
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_rename(path2, path1, &err));
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_NE(nullptr, err);
|
|
|
|
tr_error_clear(&err);
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path2);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
path3.assign(test_dir, "/c"sv);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
if (createSymlink(path2, path1, false))
|
2020-08-11 18:11:55 +00:00
|
|
|
{
|
|
|
|
/* Preconditions */
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_path_exists(path2));
|
|
|
|
EXPECT_FALSE(tr_sys_path_exists(path3));
|
|
|
|
EXPECT_TRUE(tr_sys_path_is_same(path1, path2));
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
/* Rename of symlink works, files stay the same */
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_path_rename(path2, path3, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_exists(path2));
|
|
|
|
EXPECT_TRUE(tr_sys_path_exists(path3));
|
|
|
|
EXPECT_TRUE(tr_sys_path_is_same(path1, path3));
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path3);
|
2020-08-11 18:11:55 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fprintf(stderr, "WARNING: [%s] unable to run symlink tests\n", __FUNCTION__);
|
|
|
|
}
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
if (createHardlink(path2, path1))
|
2020-08-11 18:11:55 +00:00
|
|
|
{
|
|
|
|
/* Preconditions */
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_path_exists(path2));
|
|
|
|
EXPECT_FALSE(tr_sys_path_exists(path3));
|
|
|
|
EXPECT_TRUE(tr_sys_path_is_same(path1, path2));
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
/* Rename of hardlink works, files stay the same */
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_path_rename(path2, path3, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_exists(path2));
|
|
|
|
EXPECT_TRUE(tr_sys_path_exists(path3));
|
|
|
|
EXPECT_TRUE(tr_sys_path_is_same(path1, path3));
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path3);
|
2020-08-11 18:11:55 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fprintf(stderr, "WARNING: [%s] unable to run hardlink tests\n", __FUNCTION__);
|
|
|
|
}
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path1);
|
2020-08-11 18:11:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(FileTest, pathRemove)
|
|
|
|
{
|
|
|
|
auto const test_dir = createTestDir(currentTestName());
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
auto const path1 = tr_pathbuf{ test_dir, "/a"sv };
|
|
|
|
auto const path2 = tr_pathbuf{ test_dir, "/b"sv };
|
|
|
|
auto const path3 = tr_pathbuf{ path2, "/c"sv };
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
/* Can't remove non-existent file/directory */
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_exists(path1));
|
2020-08-11 18:11:55 +00:00
|
|
|
tr_error* err = nullptr;
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_remove(path1, &err));
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_NE(nullptr, err);
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_exists(path1));
|
2020-08-11 18:11:55 +00:00
|
|
|
tr_error_clear(&err);
|
|
|
|
|
|
|
|
/* Removing file works */
|
|
|
|
createFileWithContents(path1, "test");
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_path_exists(path1));
|
|
|
|
EXPECT_TRUE(tr_sys_path_remove(path1, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_exists(path1));
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
/* Removing empty directory works */
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_dir_create(path1, 0, 0777);
|
|
|
|
EXPECT_TRUE(tr_sys_path_exists(path1));
|
|
|
|
EXPECT_TRUE(tr_sys_path_remove(path1, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_exists(path1));
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
/* Removing non-empty directory fails */
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_dir_create(path2, 0, 0777);
|
2020-08-11 18:11:55 +00:00
|
|
|
createFileWithContents(path3, "test");
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_path_exists(path2));
|
|
|
|
EXPECT_TRUE(tr_sys_path_exists(path3));
|
|
|
|
EXPECT_FALSE(tr_sys_path_remove(path2, &err));
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_NE(nullptr, err);
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_path_exists(path2));
|
|
|
|
EXPECT_TRUE(tr_sys_path_exists(path3));
|
2020-08-11 18:11:55 +00:00
|
|
|
tr_error_clear(&err);
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path3);
|
|
|
|
tr_sys_path_remove(path2);
|
2020-08-11 18:11:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(FileTest, pathNativeSeparators)
|
|
|
|
{
|
|
|
|
EXPECT_EQ(nullptr, tr_sys_path_native_separators(nullptr));
|
|
|
|
|
2020-09-07 21:19:10 +00:00
|
|
|
struct LocalTest
|
2020-08-11 18:11:55 +00:00
|
|
|
{
|
|
|
|
std::string input;
|
|
|
|
std::string expected_output;
|
|
|
|
};
|
|
|
|
|
2021-08-15 09:41:48 +00:00
|
|
|
auto const tests = std::array<LocalTest, 5>{
|
2020-09-07 21:19:10 +00:00
|
|
|
LocalTest{ "", "" },
|
2020-08-11 18:11:55 +00:00
|
|
|
{ "a", TR_IF_WIN32("a", "a") },
|
|
|
|
{ "/", TR_IF_WIN32("\\", "/") },
|
|
|
|
{ "/a/b/c", TR_IF_WIN32("\\a\\b\\c", "/a/b/c") },
|
|
|
|
{ "C:\\a/b\\c", TR_IF_WIN32("C:\\a\\b\\c", "C:\\a/b\\c") },
|
|
|
|
};
|
|
|
|
|
|
|
|
for (auto const& test : tests)
|
|
|
|
{
|
|
|
|
auto buf = std::string(test.input);
|
|
|
|
char* const output = tr_sys_path_native_separators(&buf.front());
|
|
|
|
EXPECT_EQ(test.expected_output, output);
|
|
|
|
EXPECT_EQ(buf.data(), output);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(FileTest, fileOpen)
|
|
|
|
{
|
|
|
|
auto const test_dir = createTestDir(currentTestName());
|
|
|
|
|
|
|
|
// can't open non-existent file
|
2022-04-22 16:35:56 +00:00
|
|
|
auto const path1 = tr_pathbuf{ test_dir, "/a"sv };
|
|
|
|
EXPECT_FALSE(tr_sys_path_exists(path1));
|
2020-08-11 18:11:55 +00:00
|
|
|
tr_error* err = nullptr;
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_EQ(TR_BAD_SYS_FILE, tr_sys_file_open(path1, TR_SYS_FILE_READ, 0600, &err));
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_NE(nullptr, err);
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_exists(path1));
|
2020-08-11 18:11:55 +00:00
|
|
|
tr_error_clear(&err);
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_EQ(TR_BAD_SYS_FILE, tr_sys_file_open(path1, TR_SYS_FILE_WRITE, 0600, &err));
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_NE(nullptr, err);
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_exists(path1));
|
2020-08-11 18:11:55 +00:00
|
|
|
tr_error_clear(&err);
|
|
|
|
|
|
|
|
// can't open directory
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_dir_create(path1, 0, 0777);
|
2020-08-11 18:11:55 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
// this works on *NIX
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_EQ(TR_BAD_SYS_FILE, tr_sys_file_open(path1, TR_SYS_FILE_READ, 0600, &err));
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_NE(nullptr, err);
|
|
|
|
tr_error_clear(&err);
|
|
|
|
#endif
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_EQ(TR_BAD_SYS_FILE, tr_sys_file_open(path1, TR_SYS_FILE_WRITE, 0600, &err));
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_NE(nullptr, err);
|
|
|
|
tr_error_clear(&err);
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path1);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
// can create non-existent file
|
2022-04-22 16:35:56 +00:00
|
|
|
auto fd = tr_sys_file_open(path1, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE, 0640, &err);
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_NE(TR_BAD_SYS_FILE, fd);
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2022-03-27 17:37:29 +00:00
|
|
|
tr_sys_file_close(fd);
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_path_exists(path1));
|
|
|
|
EXPECT_TRUE(validatePermissions(path1, 0640));
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
// can open existing file
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_path_exists(path1));
|
|
|
|
fd = tr_sys_file_open(path1, TR_SYS_FILE_READ, 0600, &err);
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_NE(TR_BAD_SYS_FILE, fd);
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2022-03-27 17:37:29 +00:00
|
|
|
tr_sys_file_close(fd);
|
2022-04-22 16:35:56 +00:00
|
|
|
fd = tr_sys_file_open(path1, TR_SYS_FILE_WRITE, 0600, &err);
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_NE(TR_BAD_SYS_FILE, fd);
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2022-03-27 17:37:29 +00:00
|
|
|
tr_sys_file_close(fd);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path1);
|
2020-08-11 18:11:55 +00:00
|
|
|
createFileWithContents(path1, "test");
|
|
|
|
|
|
|
|
/* Can't create new file if it already exists */
|
2022-04-22 16:35:56 +00:00
|
|
|
fd = tr_sys_file_open(path1, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE_NEW, 0640, &err);
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(TR_BAD_SYS_FILE, fd);
|
|
|
|
EXPECT_NE(nullptr, err);
|
|
|
|
tr_error_clear(&err);
|
|
|
|
tr_sys_path_info info;
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_get_info(path1, TR_SYS_PATH_NO_FOLLOW, &info);
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(4, info.size);
|
|
|
|
|
|
|
|
/* Pointer is at the end of file */
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_get_info(path1, TR_SYS_PATH_NO_FOLLOW, &info);
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(4, info.size);
|
2022-04-22 16:35:56 +00:00
|
|
|
fd = tr_sys_file_open(path1, TR_SYS_FILE_WRITE | TR_SYS_FILE_APPEND, 0600, &err);
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_NE(TR_BAD_SYS_FILE, fd);
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2022-03-27 17:37:29 +00:00
|
|
|
tr_sys_file_write(fd, "s", 1, nullptr); /* On *NIX, pointer is positioned on each write but not initially */
|
2021-08-15 09:41:48 +00:00
|
|
|
auto n = uint64_t{};
|
2022-03-27 17:37:29 +00:00
|
|
|
tr_sys_file_seek(fd, 0, TR_SEEK_CUR, &n);
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(5, n);
|
2022-03-27 17:37:29 +00:00
|
|
|
tr_sys_file_close(fd);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
/* File gets truncated */
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_get_info(path1, TR_SYS_PATH_NO_FOLLOW, &info);
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(5, info.size);
|
2022-04-22 16:35:56 +00:00
|
|
|
fd = tr_sys_file_open(path1, TR_SYS_FILE_WRITE | TR_SYS_FILE_TRUNCATE, 0600, &err);
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_NE(TR_BAD_SYS_FILE, fd);
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2022-03-27 17:37:29 +00:00
|
|
|
tr_sys_file_get_info(fd, &info);
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(0, info.size);
|
2022-03-27 17:37:29 +00:00
|
|
|
tr_sys_file_close(fd);
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_get_info(path1, TR_SYS_PATH_NO_FOLLOW, &info);
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(0, info.size);
|
|
|
|
|
|
|
|
/* TODO: symlink and hardlink tests */
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path1);
|
2020-08-11 18:11:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(FileTest, fileReadWriteSeek)
|
|
|
|
{
|
|
|
|
auto const test_dir = createTestDir(currentTestName());
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
auto const path1 = tr_pathbuf{ test_dir, "/a"sv };
|
|
|
|
auto const fd = tr_sys_file_open(path1, TR_SYS_FILE_READ | TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE, 0600);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
uint64_t n;
|
|
|
|
tr_error* err = nullptr;
|
|
|
|
EXPECT_TRUE(tr_sys_file_seek(fd, 0, TR_SEEK_CUR, &n, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(0, n);
|
|
|
|
|
|
|
|
EXPECT_TRUE(tr_sys_file_write(fd, "test", 4, &n, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(4, n);
|
|
|
|
|
|
|
|
EXPECT_TRUE(tr_sys_file_seek(fd, 0, TR_SEEK_CUR, &n, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(4, n);
|
|
|
|
|
|
|
|
EXPECT_TRUE(tr_sys_file_seek(fd, 0, TR_SEEK_SET, &n, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(0, n);
|
|
|
|
|
|
|
|
auto buf = std::array<char, 100>{};
|
|
|
|
EXPECT_TRUE(tr_sys_file_read(fd, buf.data(), buf.size(), &n, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(4, n);
|
|
|
|
|
|
|
|
EXPECT_EQ(0, memcmp("test", buf.data(), 4));
|
|
|
|
|
|
|
|
EXPECT_TRUE(tr_sys_file_seek(fd, -3, TR_SEEK_CUR, &n, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(1, n);
|
|
|
|
|
|
|
|
EXPECT_TRUE(tr_sys_file_write(fd, "E", 1, &n, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(1, n);
|
|
|
|
|
|
|
|
EXPECT_TRUE(tr_sys_file_seek(fd, -2, TR_SEEK_CUR, &n, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(0, n);
|
|
|
|
|
|
|
|
EXPECT_TRUE(tr_sys_file_read(fd, buf.data(), buf.size(), &n, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(4, n);
|
|
|
|
|
|
|
|
EXPECT_EQ(0, memcmp("tEst", buf.data(), 4));
|
|
|
|
|
|
|
|
EXPECT_TRUE(tr_sys_file_seek(fd, 0, TR_SEEK_END, &n, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(4, n);
|
|
|
|
|
|
|
|
EXPECT_TRUE(tr_sys_file_write(fd, " ok", 3, &n, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(3, n);
|
|
|
|
|
|
|
|
EXPECT_TRUE(tr_sys_file_seek(fd, 0, TR_SEEK_SET, &n, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(0, n);
|
|
|
|
|
|
|
|
EXPECT_TRUE(tr_sys_file_read(fd, buf.data(), buf.size(), &n, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(7, n);
|
|
|
|
|
|
|
|
EXPECT_EQ(0, memcmp("tEst ok", buf.data(), 7));
|
|
|
|
|
|
|
|
EXPECT_TRUE(tr_sys_file_write_at(fd, "-", 1, 4, &n, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(1, n);
|
|
|
|
|
|
|
|
EXPECT_TRUE(tr_sys_file_read_at(fd, buf.data(), 5, 2, &n, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(5, n);
|
|
|
|
|
|
|
|
EXPECT_EQ(0, memcmp("st-ok", buf.data(), 5));
|
|
|
|
|
2022-03-27 17:37:29 +00:00
|
|
|
tr_sys_file_close(fd);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path1);
|
2020-08-11 18:11:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(FileTest, fileTruncate)
|
|
|
|
{
|
|
|
|
auto const test_dir = createTestDir(currentTestName());
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
auto const path1 = tr_pathbuf{ test_dir, "/a"sv };
|
|
|
|
auto fd = tr_sys_file_open(path1, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE, 0600);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
tr_error* err = nullptr;
|
|
|
|
EXPECT_TRUE(tr_sys_file_truncate(fd, 10, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
tr_sys_path_info info;
|
2022-03-27 17:37:29 +00:00
|
|
|
tr_sys_file_get_info(fd, &info);
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(10, info.size);
|
|
|
|
|
|
|
|
EXPECT_TRUE(tr_sys_file_truncate(fd, 20, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2022-03-27 17:37:29 +00:00
|
|
|
tr_sys_file_get_info(fd, &info);
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(20, info.size);
|
|
|
|
|
|
|
|
EXPECT_TRUE(tr_sys_file_truncate(fd, 0, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2022-03-27 17:37:29 +00:00
|
|
|
tr_sys_file_get_info(fd, &info);
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(0, info.size);
|
|
|
|
|
|
|
|
EXPECT_TRUE(tr_sys_file_truncate(fd, 50, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-03-27 17:37:29 +00:00
|
|
|
tr_sys_file_close(fd);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_get_info(path1, 0, &info);
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(50, info.size);
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
fd = tr_sys_file_open(path1, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE, 0600);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
EXPECT_TRUE(tr_sys_file_truncate(fd, 25, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-03-27 17:37:29 +00:00
|
|
|
tr_sys_file_close(fd);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_get_info(path1, 0, &info);
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(25, info.size);
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path1);
|
2020-08-11 18:11:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(FileTest, filePreallocate)
|
|
|
|
{
|
|
|
|
auto const test_dir = createTestDir(currentTestName());
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
auto const path1 = tr_pathbuf{ test_dir, "/a"sv };
|
|
|
|
auto fd = tr_sys_file_open(path1, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE, 0600);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
tr_error* err = nullptr;
|
|
|
|
auto prealloc_size = size_t{ 50 };
|
|
|
|
if (tr_sys_file_preallocate(fd, prealloc_size, 0, &err))
|
|
|
|
{
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
tr_sys_path_info info;
|
2022-03-27 17:37:29 +00:00
|
|
|
tr_sys_file_get_info(fd, &info);
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(prealloc_size, info.size);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
EXPECT_NE(nullptr, err);
|
|
|
|
fprintf(stderr, "WARNING: [%s] unable to preallocate file (full): %s (%d)\n", __FUNCTION__, err->message, err->code);
|
|
|
|
tr_error_clear(&err);
|
|
|
|
}
|
|
|
|
|
2022-03-27 17:37:29 +00:00
|
|
|
tr_sys_file_close(fd);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path1);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
fd = tr_sys_file_open(path1, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE, 0600);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
prealloc_size = 500 * 1024 * 1024;
|
|
|
|
if (tr_sys_file_preallocate(fd, prealloc_size, TR_SYS_FILE_PREALLOC_SPARSE, &err))
|
|
|
|
{
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
tr_sys_path_info info;
|
2022-03-27 17:37:29 +00:00
|
|
|
tr_sys_file_get_info(fd, &info);
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(prealloc_size, info.size);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_NE(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
fprintf(stderr, "WARNING: [%s] unable to preallocate file (sparse): %s (%d)\n", __FUNCTION__, err->message, err->code);
|
|
|
|
tr_error_clear(&err);
|
|
|
|
}
|
|
|
|
|
2022-03-27 17:37:29 +00:00
|
|
|
tr_sys_file_close(fd);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path1);
|
2020-08-11 18:11:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(FileTest, map)
|
|
|
|
{
|
|
|
|
auto const test_dir = createTestDir(currentTestName());
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
auto const path1 = tr_pathbuf{ test_dir, "/a"sv };
|
2021-08-15 09:41:48 +00:00
|
|
|
auto const contents = std::string{ "test" };
|
2020-08-11 18:11:55 +00:00
|
|
|
createFileWithContents(path1, contents.data());
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
auto fd = tr_sys_file_open(path1, TR_SYS_FILE_READ | TR_SYS_FILE_WRITE, 0600);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
tr_error* err = nullptr;
|
|
|
|
auto map_len = contents.size();
|
|
|
|
auto* view = static_cast<char*>(tr_sys_file_map_for_reading(fd, 0, map_len, &err));
|
|
|
|
EXPECT_NE(nullptr, view);
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(contents, std::string(view, map_len));
|
|
|
|
|
|
|
|
#ifdef HAVE_UNIFIED_BUFFER_CACHE
|
|
|
|
|
2021-08-15 09:41:48 +00:00
|
|
|
auto const contents_2 = std::string{ "more" };
|
|
|
|
auto n_written = uint64_t{};
|
2020-08-11 18:11:55 +00:00
|
|
|
tr_sys_file_write_at(fd, contents_2.data(), contents_2.size(), 0, &n_written, &err);
|
|
|
|
EXPECT_EQ(map_len, contents_2.size());
|
|
|
|
EXPECT_EQ(map_len, n_written);
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_EQ(contents_2, std::string(view, map_len));
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
EXPECT_TRUE(tr_sys_file_unmap(view, map_len, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-03-27 17:37:29 +00:00
|
|
|
tr_sys_file_close(fd);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path1);
|
2020-08-11 18:11:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(FileTest, fileUtilities)
|
|
|
|
{
|
|
|
|
auto const test_dir = createTestDir(currentTestName());
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
auto const path1 = tr_pathbuf{ test_dir, "/a"sv };
|
2021-08-15 09:41:48 +00:00
|
|
|
auto const contents = std::string{ "a\nbc\r\ndef\nghij\r\n\n\nklmno\r" };
|
2020-08-11 18:11:55 +00:00
|
|
|
createFileWithContents(path1, contents.data());
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
auto fd = tr_sys_file_open(path1, TR_SYS_FILE_READ, 0);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
tr_error* err = nullptr;
|
|
|
|
auto buffer = std::array<char, 16>{};
|
|
|
|
EXPECT_TRUE(tr_sys_file_read_line(fd, buffer.data(), buffer.size(), &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_STREQ("a", buffer.data());
|
|
|
|
EXPECT_TRUE(tr_sys_file_read_line(fd, buffer.data(), buffer.size(), &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_STREQ("bc", buffer.data());
|
|
|
|
EXPECT_TRUE(tr_sys_file_read_line(fd, buffer.data(), buffer.size(), &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_STREQ("def", buffer.data());
|
|
|
|
EXPECT_TRUE(tr_sys_file_read_line(fd, buffer.data(), buffer.size(), &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_STREQ("ghij", buffer.data());
|
|
|
|
EXPECT_TRUE(tr_sys_file_read_line(fd, buffer.data(), buffer.size(), &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_STREQ("", buffer.data());
|
|
|
|
EXPECT_TRUE(tr_sys_file_read_line(fd, buffer.data(), buffer.size(), &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_STREQ("", buffer.data());
|
|
|
|
EXPECT_TRUE(tr_sys_file_read_line(fd, buffer.data(), 4, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_STREQ("klmn", buffer.data());
|
|
|
|
EXPECT_TRUE(tr_sys_file_read_line(fd, buffer.data(), buffer.size(), &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_STREQ("o", buffer.data());
|
|
|
|
EXPECT_FALSE(tr_sys_file_read_line(fd, buffer.data(), buffer.size(), &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_STREQ("o", buffer.data()); // on EOF, buffer stays unchanged
|
|
|
|
|
2022-03-27 17:37:29 +00:00
|
|
|
tr_sys_file_close(fd);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
fd = tr_sys_file_open(path1, TR_SYS_FILE_READ | TR_SYS_FILE_WRITE | TR_SYS_FILE_TRUNCATE, 0);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
EXPECT_TRUE(tr_sys_file_write_line(fd, "p", &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_TRUE(tr_sys_file_write_line(fd, "", &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_TRUE(tr_sys_file_write_line(fd, "qr", &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2021-12-28 15:08:04 +00:00
|
|
|
EXPECT_TRUE(tr_sys_file_write_line(fd, "stu", &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_TRUE(tr_sys_file_write_line(fd, "", &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_TRUE(tr_sys_file_write_line(fd, "", &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2021-12-28 15:08:04 +00:00
|
|
|
EXPECT_TRUE(tr_sys_file_write_line(fd, "vwxy2", &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-03-27 17:37:29 +00:00
|
|
|
tr_sys_file_seek(fd, 0, TR_SEEK_SET, nullptr);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
EXPECT_TRUE(tr_sys_file_read_line(fd, buffer.data(), buffer.size(), &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_STREQ("p", buffer.data());
|
|
|
|
EXPECT_TRUE(tr_sys_file_read_line(fd, buffer.data(), buffer.size(), &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_STREQ("", buffer.data());
|
|
|
|
EXPECT_TRUE(tr_sys_file_read_line(fd, buffer.data(), buffer.size(), &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_STREQ("qr", buffer.data());
|
|
|
|
EXPECT_TRUE(tr_sys_file_read_line(fd, buffer.data(), buffer.size(), &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_STREQ("stu", buffer.data());
|
|
|
|
EXPECT_TRUE(tr_sys_file_read_line(fd, buffer.data(), buffer.size(), &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_STREQ("", buffer.data());
|
|
|
|
EXPECT_TRUE(tr_sys_file_read_line(fd, buffer.data(), buffer.size(), &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_STREQ("", buffer.data());
|
|
|
|
EXPECT_TRUE(tr_sys_file_read_line(fd, buffer.data(), buffer.size(), &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_STREQ("vwxy2", buffer.data());
|
|
|
|
EXPECT_FALSE(tr_sys_file_read_line(fd, buffer.data(), buffer.size(), &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_STREQ("vwxy2", buffer.data()); // on EOF, buffer stays unchanged
|
|
|
|
|
2022-03-27 17:37:29 +00:00
|
|
|
tr_sys_file_close(fd);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path1);
|
2020-08-11 18:11:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(FileTest, dirCreate)
|
|
|
|
{
|
|
|
|
auto const test_dir = createTestDir(currentTestName());
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
auto const path1 = tr_pathbuf{ test_dir, "/a"sv };
|
|
|
|
auto const path2 = tr_pathbuf{ path1, "/b"sv };
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
// Can create directory which has parent
|
|
|
|
tr_error* err = nullptr;
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_dir_create(path1, 0, 0700, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_path_exists(path1));
|
|
|
|
EXPECT_TRUE(validatePermissions(path1, 0700));
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path1);
|
2020-08-11 18:11:55 +00:00
|
|
|
createFileWithContents(path1, "test");
|
|
|
|
|
|
|
|
// Can't create directory where file already exists
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_dir_create(path1, 0, 0700, &err));
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_NE(nullptr, err);
|
|
|
|
tr_error_clear(&err);
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_dir_create(path1, TR_SYS_DIR_CREATE_PARENTS, 0700, &err));
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_NE(nullptr, err);
|
|
|
|
tr_error_clear(&err);
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path1);
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
// Can't create directory which has no parent
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_dir_create(path2, 0, 0700, &err));
|
2020-08-11 18:11:55 +00:00
|
|
|
EXPECT_NE(nullptr, err);
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_FALSE(tr_sys_path_exists(path2));
|
2020-08-11 18:11:55 +00:00
|
|
|
tr_error_clear(&err);
|
|
|
|
|
|
|
|
// Can create directory with parent directories
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_dir_create(path2, TR_SYS_DIR_CREATE_PARENTS, 0751, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_path_exists(path1));
|
|
|
|
EXPECT_TRUE(tr_sys_path_exists(path2));
|
|
|
|
EXPECT_TRUE(validatePermissions(path1, 0751));
|
|
|
|
EXPECT_TRUE(validatePermissions(path2, 0751));
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
// Can create existing directory (no-op)
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_dir_create(path1, 0, 0700, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2022-04-22 16:35:56 +00:00
|
|
|
EXPECT_TRUE(tr_sys_dir_create(path1, TR_SYS_DIR_CREATE_PARENTS, 0700, &err));
|
2022-03-21 20:22:50 +00:00
|
|
|
EXPECT_EQ(nullptr, err) << *err;
|
2020-08-11 18:11:55 +00:00
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path2);
|
|
|
|
tr_sys_path_remove(path1);
|
2020-08-11 18:11:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(FileTest, dirRead)
|
|
|
|
{
|
|
|
|
auto const test_dir = createTestDir(currentTestName());
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
auto const path1 = tr_pathbuf{ test_dir, "/a"sv };
|
|
|
|
auto const path2 = tr_pathbuf{ test_dir, "/b"sv };
|
2020-08-11 18:11:55 +00:00
|
|
|
|
|
|
|
bool have1;
|
|
|
|
bool have2;
|
|
|
|
testDirReadImpl(test_dir, &have1, &have2);
|
|
|
|
EXPECT_FALSE(have1);
|
|
|
|
EXPECT_FALSE(have2);
|
|
|
|
|
|
|
|
createFileWithContents(path1, "test");
|
|
|
|
testDirReadImpl(test_dir, &have1, &have2);
|
|
|
|
EXPECT_TRUE(have1);
|
|
|
|
EXPECT_FALSE(have2);
|
|
|
|
|
|
|
|
createFileWithContents(path2, "test");
|
|
|
|
testDirReadImpl(test_dir, &have1, &have2);
|
|
|
|
EXPECT_TRUE(have1);
|
|
|
|
EXPECT_TRUE(have2);
|
|
|
|
|
2022-04-22 16:35:56 +00:00
|
|
|
tr_sys_path_remove(path1);
|
2020-08-11 18:11:55 +00:00
|
|
|
testDirReadImpl(test_dir, &have1, &have2);
|
|
|
|
EXPECT_FALSE(have1);
|
|
|
|
EXPECT_TRUE(have2);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace test
|
|
|
|
|
|
|
|
} // namespace libtransmission
|