refactor: tr_sys_path_get_info() now returns a tr_sys_path_info (#3566)

* refactor: tr_sys_path_get_info() now returns a tr_sys_path_info

* refactor: tr_sys_file_get_info() now returns a tr_sys_path_info
This commit is contained in:
Charles Kerr 2022-08-02 12:41:04 -05:00 committed by GitHub
parent 3982532d65
commit 5eb7f75010
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 275 additions and 290 deletions

View File

@ -42,14 +42,14 @@ void BlocklistFile::load()
{
close();
auto info = tr_sys_path_info{};
if (!tr_sys_path_get_info(getFilename(), 0, &info))
auto const info = tr_sys_path_get_info(getFilename());
if (!info)
{
return;
}
auto const byteCount = info.size;
if (byteCount == 0)
auto const byte_count = info->size;
if (byte_count == 0)
{
return;
}
@ -67,7 +67,7 @@ void BlocklistFile::load()
return;
}
rules_ = static_cast<struct IPv4Range*>(tr_sys_file_map_for_reading(fd, 0, byteCount, &error));
rules_ = static_cast<struct IPv4Range*>(tr_sys_file_map_for_reading(fd, 0, byte_count, &error));
if (rules_ == nullptr)
{
tr_logAddWarn(fmt::format(
@ -81,8 +81,8 @@ void BlocklistFile::load()
}
fd_ = fd;
byte_count_ = byteCount;
rule_count_ = byteCount / sizeof(IPv4Range);
byte_count_ = byte_count;
rule_count_ = byte_count / sizeof(IPv4Range);
tr_logAddInfo(fmt::format(
ngettext("Blocklist '{path}' has {count} entry", "Blocklist '{path}' has {count} entries", rule_count_),

View File

@ -123,7 +123,7 @@ public:
unsigned int hash_length = 0;
auto digest = DigestType{};
auto* const digest_as_uchar = reinterpret_cast<unsigned char*>(std::data(digest));
bool const ok = check_result(EVP_DigestFinal_ex(handle_.get(), digest_as_uchar, &hash_length));
[[maybe_unused]] bool const ok = check_result(EVP_DigestFinal_ex(handle_.get(), digest_as_uchar, &hash_length));
TR_ASSERT(!ok || hash_length == std::size(digest));
clear();

View File

@ -117,23 +117,27 @@ static void set_system_error_if_file_found(tr_error** error, int code)
}
}
static void stat_to_sys_path_info(struct stat const* sb, tr_sys_path_info* info)
static constexpr auto stat_to_sys_path_info(struct stat const& sb)
{
if (S_ISREG(sb->st_mode))
auto info = tr_sys_path_info{};
if (S_ISREG(sb.st_mode))
{
info->type = TR_SYS_PATH_IS_FILE;
info.type = TR_SYS_PATH_IS_FILE;
}
else if (S_ISDIR(sb->st_mode))
else if (S_ISDIR(sb.st_mode))
{
info->type = TR_SYS_PATH_IS_DIRECTORY;
info.type = TR_SYS_PATH_IS_DIRECTORY;
}
else
{
info->type = TR_SYS_PATH_IS_OTHER;
info.type = TR_SYS_PATH_IS_OTHER;
}
info->size = (uint64_t)sb->st_size;
info->last_modified_at = sb->st_mtime;
info.size = static_cast<uint64_t>(sb.st_size);
info.last_modified_at = sb.st_mtime;
return info;
}
static void set_file_for_single_pass(tr_sys_file_t handle)
@ -299,33 +303,29 @@ bool tr_sys_path_exists(char const* path, tr_error** error)
return ret;
}
bool tr_sys_path_get_info(char const* path, int flags, tr_sys_path_info* info, tr_error** error)
std::optional<tr_sys_path_info> tr_sys_path_get_info(std::string_view path, int flags, tr_error** error)
{
TR_ASSERT(path != nullptr);
TR_ASSERT(info != nullptr);
struct stat sb = {};
bool ret = false;
struct stat sb;
bool ok = false;
auto const szpath = tr_pathbuf{ path };
if ((flags & TR_SYS_PATH_NO_FOLLOW) == 0)
{
ret = stat(path, &sb) != -1;
ok = stat(szpath, &sb) != -1;
}
else
{
ret = lstat(path, &sb) != -1;
ok = lstat(szpath, &sb) != -1;
}
if (ret)
if (ok)
{
stat_to_sys_path_info(&sb, info);
}
else
{
set_system_error(error, errno);
return stat_to_sys_path_info(sb);
}
return ret;
set_system_error(error, errno);
return {};
}
bool tr_sys_path_is_relative(std::string_view path)
@ -486,8 +486,8 @@ bool tr_sys_path_copy(char const* src_path, char const* dst_path, tr_error** err
return false;
}
tr_sys_path_info info;
if (!tr_sys_file_get_info(in, &info, error))
auto const info = tr_sys_file_get_info(in, error);
if (!info)
{
tr_error_prefix(error, "Unable to get information on source file: ");
tr_sys_file_close(in);
@ -506,11 +506,11 @@ bool tr_sys_path_copy(char const* src_path, char const* dst_path, tr_error** err
return false;
}
uint64_t file_size = info.size;
uint64_t file_size = info->size;
#if defined(USE_COPY_FILE_RANGE) || defined(USE_SENDFILE64)
while (file_size > 0)
while (file_size > 0U)
{
size_t const chunk_size = std::min(file_size, uint64_t{ SSIZE_MAX });
ssize_t const copied =
@ -538,12 +538,12 @@ bool tr_sys_path_copy(char const* src_path, char const* dst_path, tr_error** err
/* Fallback to user-space copy. */
size_t const buflen = 1024 * 1024; /* 1024 KiB buffer */
auto* buf = static_cast<char*>(tr_malloc(buflen));
static auto constexpr Buflen = size_t{ 1024U * 1024U }; /* 1024 KiB buffer */
auto* buf = static_cast<char*>(tr_malloc(Buflen));
while (file_size > 0)
while (file_size > 0U)
{
uint64_t const chunk_size = std::min(file_size, uint64_t{ buflen });
uint64_t const chunk_size = std::min(file_size, uint64_t{ Buflen });
uint64_t bytes_read;
uint64_t bytes_written;
@ -707,24 +707,19 @@ bool tr_sys_file_close(tr_sys_file_t handle, tr_error** error)
return ret;
}
bool tr_sys_file_get_info(tr_sys_file_t handle, tr_sys_path_info* info, tr_error** error)
std::optional<tr_sys_path_info> tr_sys_file_get_info(tr_sys_file_t handle, tr_error** error)
{
TR_ASSERT(handle != TR_BAD_SYS_FILE);
TR_ASSERT(info != nullptr);
struct stat sb;
bool const ret = fstat(handle, &sb) != -1;
if (ret)
if (fstat(handle, &sb) != -1)
{
stat_to_sys_path_info(&sb, info);
}
else
{
set_system_error(error, errno);
return stat_to_sys_path_info(sb);
}
return ret;
set_system_error(error, errno);
return {};
}
bool tr_sys_file_seek(tr_sys_file_t handle, int64_t offset, tr_seek_origin_t origin, uint64_t* new_offset, tr_error** error)

View File

@ -72,48 +72,42 @@ static void set_system_error_if_file_found(tr_error** error, DWORD code)
}
}
static time_t filetime_to_unix_time(FILETIME const* t)
static constexpr time_t filetime_to_unix_time(FILETIME const& t)
{
TR_ASSERT(t != nullptr);
uint64_t tmp = 0;
tmp |= t->dwHighDateTime;
tmp |= t.dwHighDateTime;
tmp <<= 32;
tmp |= t->dwLowDateTime;
tmp |= t.dwLowDateTime;
tmp /= 10; /* to microseconds */
tmp -= DELTA_EPOCH_IN_MICROSECS;
return tmp / 1000000UL;
}
static void stat_to_sys_path_info(
DWORD attributes,
DWORD size_low,
DWORD size_high,
FILETIME const* mtime,
tr_sys_path_info* info)
static constexpr auto stat_to_sys_path_info(DWORD attributes, DWORD size_low, DWORD size_high, FILETIME const& mtime)
{
TR_ASSERT(mtime != nullptr);
TR_ASSERT(info != nullptr);
auto info = tr_sys_path_info{};
if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
{
info->type = TR_SYS_PATH_IS_DIRECTORY;
info.type = TR_SYS_PATH_IS_DIRECTORY;
}
else if ((attributes & (FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_VIRTUAL)) == 0)
{
info->type = TR_SYS_PATH_IS_FILE;
info.type = TR_SYS_PATH_IS_FILE;
}
else
{
info->type = TR_SYS_PATH_IS_OTHER;
info.type = TR_SYS_PATH_IS_OTHER;
}
info->size = size_high;
info->size <<= 32;
info->size |= size_low;
info.size = size_high;
info.size <<= 32;
info.size |= size_low;
info->last_modified_at = filetime_to_unix_time(mtime);
info.last_modified_at = filetime_to_unix_time(mtime);
return info;
}
static constexpr bool is_slash(char c)
@ -235,6 +229,18 @@ static wchar_t* path_to_native_path(char const* path)
return path_to_native_path_ex(path, 0, nullptr);
}
static std::wstring path_to_native_path_wstr(std::string_view path)
{
if (auto* const rawptr = path_to_native_path(tr_pathbuf{ path }); rawptr != nullptr)
{
auto ret = std::wstring{ rawptr };
tr_free(rawptr);
return ret;
}
return {};
}
static char* native_path_to_path(wchar_t const* wide_path)
{
if (wide_path == nullptr)
@ -423,67 +429,35 @@ bool tr_sys_path_exists(char const* path, tr_error** error)
return ret;
}
bool tr_sys_path_get_info(char const* path, int flags, tr_sys_path_info* info, tr_error** error)
std::optional<tr_sys_path_info> tr_sys_path_get_info(std::string_view path, int flags, tr_error** error)
{
TR_ASSERT(path != nullptr);
TR_ASSERT(info != nullptr);
bool ret = false;
wchar_t* wide_path = path_to_native_path(path);
if ((flags & TR_SYS_PATH_NO_FOLLOW) == 0)
if (auto const wide_path = path_to_native_path_wstr(path); std::empty(wide_path))
{
HANDLE handle = INVALID_HANDLE_VALUE;
if (wide_path != nullptr)
{
handle = CreateFileW(wide_path, 0, 0, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
}
if (handle != INVALID_HANDLE_VALUE)
{
tr_error* my_error = nullptr;
ret = tr_sys_file_get_info(handle, info, &my_error);
if (!ret)
{
tr_error_propagate(error, &my_error);
}
CloseHandle(handle);
}
else
{
set_system_error(error, GetLastError());
}
// do nothing
}
else
else if ((flags & TR_SYS_PATH_NO_FOLLOW) != 0)
{
WIN32_FILE_ATTRIBUTE_DATA attributes;
if (wide_path != nullptr)
auto attributes = WIN32_FILE_ATTRIBUTE_DATA{};
if (GetFileAttributesExW(wide_path.c_str(), GetFileExInfoStandard, &attributes))
{
ret = GetFileAttributesExW(wide_path, GetFileExInfoStandard, &attributes);
}
if (ret)
{
stat_to_sys_path_info(
return stat_to_sys_path_info(
attributes.dwFileAttributes,
attributes.nFileSizeLow,
attributes.nFileSizeHigh,
&attributes.ftLastWriteTime,
info);
}
else
{
set_system_error(error, GetLastError());
attributes.ftLastWriteTime);
}
}
else if (auto const
handle = CreateFileW(wide_path.c_str(), 0, 0, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
handle != INVALID_HANDLE_VALUE)
{
auto ret = tr_sys_file_get_info(handle, error);
CloseHandle(handle);
return ret;
}
tr_free(wide_path);
return ret;
set_system_error(error, GetLastError());
return {};
}
bool tr_sys_path_is_relative(std::string_view path)
@ -1071,29 +1045,22 @@ bool tr_sys_file_close(tr_sys_file_t handle, tr_error** error)
return ret;
}
bool tr_sys_file_get_info(tr_sys_file_t handle, tr_sys_path_info* info, tr_error** error)
std::optional<tr_sys_path_info> tr_sys_file_get_info(tr_sys_file_t handle, tr_error** error)
{
TR_ASSERT(handle != TR_BAD_SYS_FILE);
TR_ASSERT(info != nullptr);
BY_HANDLE_FILE_INFORMATION attributes;
bool ret = GetFileInformationByHandle(handle, &attributes);
if (ret)
auto attributes = BY_HANDLE_FILE_INFORMATION{};
if (GetFileInformationByHandle(handle, &attributes))
{
stat_to_sys_path_info(
return stat_to_sys_path_info(
attributes.dwFileAttributes,
attributes.nFileSizeLow,
attributes.nFileSizeHigh,
&attributes.ftLastWriteTime,
info);
}
else
{
set_system_error(error, GetLastError());
attributes.ftLastWriteTime);
}
return ret;
set_system_error(error, GetLastError());
return {};
}
bool tr_sys_file_seek(tr_sys_file_t handle, int64_t offset, tr_seek_origin_t origin, uint64_t* new_offset, tr_error** error)

View File

@ -8,9 +8,9 @@
#include <cstddef> // size_t
#include <cstdint> // uint64_t
#include <ctime> // time_t
#include <optional>
#include <string>
#include <string_view>
#include <type_traits>
#ifdef _WIN32
#include <windows.h>
@ -117,8 +117,18 @@ enum tr_sys_path_type_t
struct tr_sys_path_info
{
tr_sys_path_type_t type = {};
uint64_t size = 0;
time_t last_modified_at = 0;
uint64_t size = {};
time_t last_modified_at = {};
[[nodiscard]] constexpr auto isFile() const noexcept
{
return type == TR_SYS_PATH_IS_FILE;
}
[[nodiscard]] constexpr auto isFolder() const noexcept
{
return type == TR_SYS_PATH_IS_DIRECTORY;
}
};
/**
@ -153,13 +163,15 @@ bool tr_sys_path_copy(char const* src_path, char const* dst_path, struct tr_erro
*
* @param[in] path Path to file or directory.
* @param[in] flags Combination of @ref tr_sys_path_get_info_flags_t values.
* @param[out] info Result buffer.
* @param[out] error Pointer to error object. Optional, pass `nullptr` if you
* are not interested in error details.
*
* @return `True` on success, `false` otherwise (with `error` set accordingly).
* @return info on success, or nullopt with `error` set accordingly.
*/
bool tr_sys_path_get_info(char const* path, int flags, tr_sys_path_info* info, struct tr_error** error = nullptr);
[[nodiscard]] std::optional<tr_sys_path_info> tr_sys_path_get_info(
std::string_view path,
int flags = 0,
tr_error** error = nullptr);
/**
* @brief Portability wrapper for `access()`.
@ -369,13 +381,12 @@ bool tr_sys_file_close(tr_sys_file_t handle, struct tr_error** error = nullptr);
* @brief Portability wrapper for `fstat()`.
*
* @param[in] handle Valid file descriptor.
* @param[out] info Result buffer.
* @param[out] error Pointer to error object. Optional, pass `nullptr` if you
* are not interested in error details.
*
* @return `True` on success, `false` otherwise (with `error` set accordingly).
* @return info on success, or nullopt with `error` set accordingly.
*/
bool tr_sys_file_get_info(tr_sys_file_t handle, tr_sys_path_info* info, struct tr_error** error = nullptr);
[[nodiscard]] std::optional<tr_sys_path_info> tr_sys_file_get_info(tr_sys_file_t handle, struct tr_error** error = nullptr);
/**
* @brief Portability wrapper for `lseek()`.

View File

@ -54,8 +54,9 @@ static struct FileList* getFiles(std::string_view dir, std::string_view base, st
auto buf = tr_pathbuf{ dir, '/', base };
tr_sys_path_native_separators(std::data(buf));
tr_sys_path_info info;
if (tr_error* error = nullptr; !tr_sys_path_get_info(buf, 0, &info, &error))
tr_error* error = nullptr;
auto const info = tr_sys_path_get_info(buf, 0, &error);
if (!info)
{
tr_logAddWarn(fmt::format(
_("Skipping '{path}': {error} ({error_code})"),
@ -66,27 +67,36 @@ static struct FileList* getFiles(std::string_view dir, std::string_view base, st
return list;
}
if (tr_sys_dir_t odir = info.type == TR_SYS_PATH_IS_DIRECTORY ? tr_sys_dir_open(buf.c_str()) : TR_BAD_SYS_DIR;
odir != TR_BAD_SYS_DIR)
switch (info->type)
{
char const* name = nullptr;
while ((name = tr_sys_dir_read_name(odir)) != nullptr)
case TR_SYS_PATH_IS_DIRECTORY:
if (auto const odir = tr_sys_dir_open(buf.c_str()); odir != TR_BAD_SYS_DIR)
{
if (name[0] != '.') /* skip dotfiles */
char const* name = nullptr;
while ((name = tr_sys_dir_read_name(odir)) != nullptr)
{
list = getFiles(buf.c_str(), name, list);
if (name[0] != '.') /* skip dotfiles */
{
list = getFiles(buf.c_str(), name, list);
}
}
}
tr_sys_dir_close(odir);
}
else if (info.type == TR_SYS_PATH_IS_FILE)
{
auto* const node = tr_new0(FileList, 1);
node->size = info.size;
node->filename = tr_strvDup(buf);
node->next = list;
list = node;
tr_sys_dir_close(odir);
}
break;
case TR_SYS_PATH_IS_FILE:
{
auto* const node = tr_new0(FileList, 1);
node->size = info->size;
node->filename = tr_strvDup(buf);
node->next = list;
list = node;
}
break;
default:
break;
}
return list;
@ -145,10 +155,8 @@ tr_metainfo_builder* tr_metaInfoBuilderCreate(char const* topFileArg)
ret->top = real_top;
{
tr_sys_path_info info;
ret->isFolder = tr_sys_path_get_info(ret->top, 0, &info) && info.type == TR_SYS_PATH_IS_DIRECTORY;
}
auto const info = tr_sys_path_get_info(ret->top);
ret->isFolder = info && info->isFolder();
/* build a list of files containing top file and,
if it's a directory, all of its children */

View File

@ -167,11 +167,11 @@ std::optional<tr_sys_file_t> tr_open_files::get(
}
}
auto info = tr_sys_path_info{};
bool const already_existed = tr_sys_path_get_info(filename, 0, &info) && info.type == TR_SYS_PATH_IS_FILE;
auto const info = tr_sys_path_get_info(filename);
bool const already_existed = info && info->isFile();
// we need write permissions to resize the file
bool const resize_needed = already_existed && (file_size < info.size);
bool const resize_needed = already_existed && (file_size < info->size);
writable |= resize_needed;
// open the file

View File

@ -2045,11 +2045,9 @@ static void sessionLoadTorrents(struct sessionLoadTorrentsData* const data)
{
TR_ASSERT(tr_isSession(data->session));
tr_sys_path_info info;
auto const& dirname = data->session->torrentDir();
tr_sys_dir_t odir = (tr_sys_path_get_info(dirname.c_str(), 0, &info) && info.type == TR_SYS_PATH_IS_DIRECTORY) ?
tr_sys_dir_open(dirname.c_str()) :
TR_BAD_SYS_DIR;
auto const info = tr_sys_path_get_info(dirname);
auto const odir = info && info->isFolder() ? tr_sys_dir_open(dirname.c_str()) : TR_BAD_SYS_DIR;
auto torrents = std::list<tr_torrent*>{};
if (odir != TR_BAD_SYS_DIR)
@ -2342,7 +2340,7 @@ bool tr_sessionIsPortForwardingEnabled(tr_session const* session)
static void loadBlocklists(tr_session* session)
{
auto loadme = std::unordered_set<std::string>{};
auto const isEnabled = session->useBlocklist();
auto const is_enabled = session->useBlocklist();
/* walk the blocklist directory... */
auto const dirname = tr_pathbuf{ session->configDir(), "/blocklists"sv };
@ -2369,28 +2367,26 @@ static void loadBlocklists(tr_session* session)
}
else
{
tr_sys_path_info path_info;
tr_sys_path_info binname_info;
auto const binname = tr_pathbuf{ dirname, '/', name, ".bin"sv };
if (!tr_sys_path_get_info(binname, 0, &binname_info)) /* create it */
if (auto const bininfo = tr_sys_path_get_info(binname); !bininfo)
{
BlocklistFile b(binname, isEnabled);
// create it
auto b = BlocklistFile{ binname, is_enabled };
if (auto const n = b.setContent(path); n > 0)
{
load = binname;
}
}
else if (
tr_sys_path_get_info(path, 0, &path_info) &&
path_info.last_modified_at >= binname_info.last_modified_at) /* update it */
else if (auto const pathinfo = tr_sys_path_get_info(path);
path && pathinfo->last_modified_at >= bininfo->last_modified_at)
{
// update it
auto const old = tr_pathbuf{ binname, ".old"sv };
tr_sys_path_remove(old);
tr_sys_path_rename(binname, old);
BlocklistFile b(binname, isEnabled);
BlocklistFile b(binname, is_enabled);
if (b.setContent(path) > 0)
{
@ -2415,7 +2411,7 @@ static void loadBlocklists(tr_session* session)
std::begin(loadme),
std::end(loadme),
std::back_inserter(session->blocklists),
[&isEnabled](auto const& path) { return std::make_unique<BlocklistFile>(path.c_str(), isEnabled); });
[&is_enabled](auto const& path) { return std::make_unique<BlocklistFile>(path.c_str(), is_enabled); });
/* cleanup */
tr_sys_dir_close(odir);

View File

@ -27,15 +27,15 @@ namespace
using file_func_t = std::function<void(char const* filename)>;
bool isDirectory(char const* path)
bool isFolder(std::string_view path)
{
auto info = tr_sys_path_info{};
return tr_sys_path_get_info(path, 0, &info) && (info.type == TR_SYS_PATH_IS_DIRECTORY);
auto const info = tr_sys_path_get_info(path);
return info && info->isFolder();
}
bool isEmptyDirectory(char const* path)
bool isEmptyFolder(char const* path)
{
if (!isDirectory(path))
if (!isFolder(path))
{
return false;
}
@ -60,7 +60,7 @@ bool isEmptyDirectory(char const* path)
void depthFirstWalk(char const* path, file_func_t const& func, std::optional<int> max_depth = {})
{
if (isDirectory(path) && (!max_depth || *max_depth > 0))
if (isFolder(path) && (!max_depth || *max_depth > 0))
{
if (auto const odir = tr_sys_dir_open(path); odir != TR_BAD_SYS_DIR)
{
@ -114,7 +114,6 @@ std::optional<tr_torrent_files::FoundFile> tr_torrent_files::find(
size_t n_paths) const
{
auto filename = tr_pathbuf{};
auto file_info = tr_sys_path_info{};
auto const& subpath = path(file_index);
for (size_t path_idx = 0; path_idx < n_paths; ++path_idx)
@ -122,15 +121,15 @@ std::optional<tr_torrent_files::FoundFile> tr_torrent_files::find(
auto const base = search_paths[path_idx];
filename.assign(base, '/', subpath);
if (tr_sys_path_get_info(filename, 0, &file_info))
if (auto const info = tr_sys_path_get_info(filename); info)
{
return FoundFile{ file_info, std::move(filename), std::size(base) };
return FoundFile{ *info, std::move(filename), std::size(base) };
}
filename.assign(filename, base, '/', subpath, PartialFileSuffix);
if (tr_sys_path_get_info(filename, 0, &file_info))
filename.assign(base, '/', subpath, PartialFileSuffix);
if (auto const info = tr_sys_path_get_info(filename); info)
{
return FoundFile{ file_info, std::move(filename), std::size(base) };
return FoundFile{ *info, std::move(filename), std::size(base) };
}
}
@ -220,7 +219,7 @@ bool tr_torrent_files::move(
{
auto const remove_empty_directories = [](char const* filename)
{
if (isEmptyDirectory(filename))
if (isEmptyFolder(filename))
{
tr_sys_path_remove(filename, nullptr);
}
@ -304,7 +303,7 @@ void tr_torrent_files::remove(std::string_view parent_in, std::string_view tmpdi
// Remove the first two categories and leave the third alone.
auto const remove_junk = [](char const* filename)
{
if (isEmptyDirectory(filename) || isJunkFile(filename))
if (isEmptyFolder(filename) || isJunkFile(filename))
{
tr_sys_path_remove(filename);
}

View File

@ -142,9 +142,9 @@ bool tr_loadFile(std::string_view path_in, std::vector<char>& setme, tr_error**
auto const path = tr_pathbuf{ path_in };
/* try to stat the file */
auto info = tr_sys_path_info{};
tr_error* my_error = nullptr;
if (!tr_sys_path_get_info(path, 0, &info, &my_error))
auto const info = tr_sys_path_get_info(path, 0, &my_error);
if (!info)
{
tr_logAddError(fmt::format(
_("Couldn't read '{path}': {error} ({error_code})"),
@ -155,7 +155,7 @@ bool tr_loadFile(std::string_view path_in, std::vector<char>& setme, tr_error**
return false;
}
if (info.type != TR_SYS_PATH_IS_FILE)
if (!info->isFile())
{
tr_logAddError(fmt::format(_("Couldn't read '{path}': Not a regular file"), fmt::arg("path", path)));
tr_error_set(error, TR_ERROR_EISDIR, "Not a regular file"sv);
@ -175,8 +175,8 @@ bool tr_loadFile(std::string_view path_in, std::vector<char>& setme, tr_error**
return false;
}
setme.resize(info.size);
if (!tr_sys_file_read(fd, std::data(setme), info.size, nullptr, &my_error))
setme.resize(info->size);
if (!tr_sys_file_read(fd, std::data(setme), info->size, nullptr, &my_error))
{
tr_logAddError(fmt::format(
_("Couldn't read '{path}': {error} ({error_code})"),
@ -851,13 +851,13 @@ bool tr_moveFile(std::string_view oldpath_in, std::string_view newpath_in, tr_er
auto const newpath = tr_pathbuf{ newpath_in };
// make sure the old file exists
auto info = tr_sys_path_info{};
if (!tr_sys_path_get_info(oldpath, 0, &info, error))
auto const info = tr_sys_path_get_info(oldpath, 0, error);
if (!info)
{
tr_error_prefix(error, "Unable to get information on old file: ");
return false;
}
if (info.type != TR_SYS_PATH_IS_FILE)
if (!info->isFile())
{
tr_error_set(error, TR_ERROR_EINVAL, "Old path does not point to a file."sv);
return false;

View File

@ -265,10 +265,8 @@ private:
{
auto const path = tr_pathbuf{ dir, '/', name };
auto path_info = tr_sys_path_info{};
tr_error* error = nullptr;
bool const ret = tr_sys_path_get_info(path, 0, &path_info, &error) && (path_info.type == TR_SYS_PATH_IS_FILE);
auto const info = tr_sys_path_get_info(path, 0, &error);
if (error != nullptr)
{
if (!TR_ERROR_IS_ENOENT(error->code))
@ -283,7 +281,7 @@ private:
tr_error_free(error);
}
return ret;
return info && info->isFile();
}
static constexpr std::string_view statusToString(tr_watchdir_status status)

View File

@ -81,14 +81,14 @@ private:
EXPECT_NE(fd1, TR_BAD_SYS_FILE);
EXPECT_NE(fd2, TR_BAD_SYS_FILE);
tr_sys_path_info info1;
tr_sys_path_info info2;
tr_sys_file_get_info(fd1, &info1);
tr_sys_file_get_info(fd2, &info2);
EXPECT_EQ(info1.size, info2.size);
auto const info1 = tr_sys_file_get_info(fd1);
auto const info2 = tr_sys_file_get_info(fd2);
EXPECT_TRUE(info1);
EXPECT_TRUE(info2);
EXPECT_EQ(info1->size, info2->size);
uint64_t bytes_left1 = info1.size;
uint64_t bytes_left2 = info2.size;
auto bytes_left1 = info1->size;
auto bytes_left2 = info2->size;
size_t const buflen = 2 * 1024 * 1024; /* 2 MiB buffer */
auto* readbuf1 = static_cast<char*>(tr_malloc(buflen));

View File

@ -107,7 +107,6 @@ protected:
while (*p != '\0')
{
tr_sys_path_info info;
char const* slash_pos = strchr(p, '/');
#ifdef _WIN32
@ -127,9 +126,8 @@ protected:
}
auto const path_part = std::string{ path, size_t(slash_pos - path + 1) };
if (!tr_sys_path_get_info(path_part.c_str(), TR_SYS_PATH_NO_FOLLOW, &info) ||
(info.type != TR_SYS_PATH_IS_FILE && info.type != TR_SYS_PATH_IS_DIRECTORY))
auto const info = tr_sys_path_get_info(path_part, TR_SYS_PATH_NO_FOLLOW);
if (!info || (!info->isFile() && !info->isFolder()))
{
return false;
}
@ -226,14 +224,14 @@ protected:
TEST_F(FileTest, getInfo)
{
auto const test_dir = createTestDir(currentTestName());
tr_sys_path_info info;
auto const path1 = tr_pathbuf{ test_dir, "/a"sv };
auto const path2 = tr_pathbuf{ test_dir, "/b"sv };
// Can't get info of non-existent file/directory
tr_error* err = nullptr;
EXPECT_FALSE(tr_sys_path_get_info(path1, 0, &info, &err));
auto info = tr_sys_path_get_info(path1, 0, &err);
EXPECT_FALSE(info);
EXPECT_NE(nullptr, err);
tr_error_clear(&err);
@ -241,23 +239,23 @@ TEST_F(FileTest, getInfo)
createFileWithContents(path1, "test");
// Good file info
clearPathInfo(&info);
EXPECT_TRUE(tr_sys_path_get_info(path1, 0, &info, &err));
info = tr_sys_path_get_info(path1, 0, &err);
EXPECT_TRUE(info);
EXPECT_EQ(nullptr, err) << *err;
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);
EXPECT_EQ(TR_SYS_PATH_IS_FILE, info->type);
EXPECT_EQ(4U, info->size);
EXPECT_GE(info->last_modified_at, t - 1);
EXPECT_LE(info->last_modified_at, time(nullptr) + 1);
// Good file info (by handle)
auto fd = tr_sys_file_open(path1, TR_SYS_FILE_READ, 0);
clearPathInfo(&info);
EXPECT_TRUE(tr_sys_file_get_info(fd, &info, &err));
info = tr_sys_file_get_info(fd, &err);
EXPECT_TRUE(info);
EXPECT_EQ(nullptr, err) << *err;
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);
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);
tr_sys_file_close(fd);
tr_sys_path_remove(path1);
@ -265,19 +263,20 @@ TEST_F(FileTest, getInfo)
// Good directory info
t = time(nullptr);
tr_sys_dir_create(path1, 0, 0777);
clearPathInfo(&info);
EXPECT_TRUE(tr_sys_path_get_info(path1, 0, &info, &err));
info = tr_sys_path_get_info(path1, 0, &err);
EXPECT_TRUE(info);
EXPECT_EQ(nullptr, err) << *err;
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);
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);
tr_sys_path_remove(path1);
if (createSymlink(path1, path2, false))
{
// Can't get info of non-existent file/directory
EXPECT_FALSE(tr_sys_path_get_info(path1, 0, &info, &err));
info = tr_sys_path_get_info(path1, 0, &err);
EXPECT_FALSE(info);
EXPECT_NE(nullptr, err);
tr_error_clear(&err);
@ -285,23 +284,23 @@ TEST_F(FileTest, getInfo)
createFileWithContents(path2, "test");
// Good file info
clearPathInfo(&info);
EXPECT_TRUE(tr_sys_path_get_info(path1, 0, &info, &err));
info = tr_sys_path_get_info(path1, 0, &err);
EXPECT_TRUE(info);
EXPECT_EQ(nullptr, err) << *err;
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);
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)
fd = tr_sys_file_open(path1, TR_SYS_FILE_READ, 0);
clearPathInfo(&info);
EXPECT_TRUE(tr_sys_file_get_info(fd, &info, &err));
info = tr_sys_file_get_info(fd, &err);
EXPECT_TRUE(info);
EXPECT_EQ(nullptr, err) << *err;
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);
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);
tr_sys_file_close(fd);
tr_sys_path_remove(path2);
@ -311,13 +310,13 @@ TEST_F(FileTest, getInfo)
t = time(nullptr);
tr_sys_dir_create(path2, 0, 0777);
EXPECT_TRUE(createSymlink(path1, path2, true)); /* Win32: directory and file symlinks differ :( */
clearPathInfo(&info);
EXPECT_TRUE(tr_sys_path_get_info(path1, 0, &info, &err));
info = tr_sys_path_get_info(path1, 0, &err);
EXPECT_TRUE(info);
EXPECT_EQ(nullptr, err) << *err;
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);
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);
tr_sys_path_remove(path2);
tr_sys_path_remove(path1);
@ -1088,13 +1087,14 @@ TEST_F(FileTest, fileOpen)
EXPECT_EQ(TR_BAD_SYS_FILE, fd);
EXPECT_NE(nullptr, err);
tr_error_clear(&err);
tr_sys_path_info info;
tr_sys_path_get_info(path1, TR_SYS_PATH_NO_FOLLOW, &info);
EXPECT_EQ(4, info.size);
auto info = tr_sys_path_get_info(path1, TR_SYS_PATH_NO_FOLLOW);
EXPECT_TRUE(info);
EXPECT_EQ(4U, info->size);
/* Pointer is at the end of file */
tr_sys_path_get_info(path1, TR_SYS_PATH_NO_FOLLOW, &info);
EXPECT_EQ(4, info.size);
info = tr_sys_path_get_info(path1, TR_SYS_PATH_NO_FOLLOW);
EXPECT_TRUE(info);
EXPECT_EQ(4U, info->size);
fd = tr_sys_file_open(path1, TR_SYS_FILE_WRITE | TR_SYS_FILE_APPEND, 0600, &err);
EXPECT_NE(TR_BAD_SYS_FILE, fd);
EXPECT_EQ(nullptr, err) << *err;
@ -1105,16 +1105,19 @@ TEST_F(FileTest, fileOpen)
tr_sys_file_close(fd);
/* File gets truncated */
tr_sys_path_get_info(path1, TR_SYS_PATH_NO_FOLLOW, &info);
EXPECT_EQ(5, info.size);
info = tr_sys_path_get_info(path1, TR_SYS_PATH_NO_FOLLOW);
EXPECT_TRUE(info);
EXPECT_EQ(5U, info->size);
fd = tr_sys_file_open(path1, TR_SYS_FILE_WRITE | TR_SYS_FILE_TRUNCATE, 0600, &err);
EXPECT_NE(TR_BAD_SYS_FILE, fd);
EXPECT_EQ(nullptr, err) << *err;
tr_sys_file_get_info(fd, &info);
EXPECT_EQ(0, info.size);
info = tr_sys_file_get_info(fd);
EXPECT_TRUE(info);
EXPECT_EQ(0U, info->size);
tr_sys_file_close(fd);
tr_sys_path_get_info(path1, TR_SYS_PATH_NO_FOLLOW, &info);
EXPECT_EQ(0, info.size);
info = tr_sys_path_get_info(path1, TR_SYS_PATH_NO_FOLLOW);
EXPECT_TRUE(info);
EXPECT_EQ(0U, info->size);
/* TODO: symlink and hardlink tests */
@ -1214,27 +1217,30 @@ TEST_F(FileTest, fileTruncate)
tr_error* err = nullptr;
EXPECT_TRUE(tr_sys_file_truncate(fd, 10, &err));
EXPECT_EQ(nullptr, err) << *err;
tr_sys_path_info info;
tr_sys_file_get_info(fd, &info);
EXPECT_EQ(10, info.size);
auto info = tr_sys_file_get_info(fd);
EXPECT_TRUE(info);
EXPECT_EQ(10U, info->size);
EXPECT_TRUE(tr_sys_file_truncate(fd, 20, &err));
EXPECT_EQ(nullptr, err) << *err;
tr_sys_file_get_info(fd, &info);
EXPECT_EQ(20, info.size);
info = tr_sys_file_get_info(fd);
EXPECT_TRUE(info);
EXPECT_EQ(20U, info->size);
EXPECT_TRUE(tr_sys_file_truncate(fd, 0, &err));
EXPECT_EQ(nullptr, err) << *err;
tr_sys_file_get_info(fd, &info);
EXPECT_EQ(0, info.size);
info = tr_sys_file_get_info(fd);
EXPECT_TRUE(info);
EXPECT_EQ(0U, info->size);
EXPECT_TRUE(tr_sys_file_truncate(fd, 50, &err));
EXPECT_EQ(nullptr, err) << *err;
tr_sys_file_close(fd);
tr_sys_path_get_info(path1, 0, &info);
EXPECT_EQ(50, info.size);
info = tr_sys_path_get_info(path1);
EXPECT_TRUE(info);
EXPECT_EQ(50U, info->size);
fd = tr_sys_file_open(path1, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE, 0600);
@ -1243,8 +1249,9 @@ TEST_F(FileTest, fileTruncate)
tr_sys_file_close(fd);
tr_sys_path_get_info(path1, 0, &info);
EXPECT_EQ(25, info.size);
info = tr_sys_path_get_info(path1);
EXPECT_TRUE(info);
EXPECT_EQ(25U, info->size);
tr_sys_path_remove(path1);
}
@ -1261,9 +1268,9 @@ TEST_F(FileTest, filePreallocate)
if (tr_sys_file_preallocate(fd, prealloc_size, 0, &err))
{
EXPECT_EQ(nullptr, err) << *err;
tr_sys_path_info info;
tr_sys_file_get_info(fd, &info);
EXPECT_EQ(prealloc_size, info.size);
auto info = tr_sys_file_get_info(fd);
EXPECT_TRUE(info);
EXPECT_EQ(prealloc_size, info->size);
}
else
{
@ -1282,9 +1289,9 @@ TEST_F(FileTest, filePreallocate)
if (tr_sys_file_preallocate(fd, prealloc_size, TR_SYS_FILE_PREALLOC_SPARSE, &err))
{
EXPECT_EQ(nullptr, err) << *err;
tr_sys_path_info info;
tr_sys_file_get_info(fd, &info);
EXPECT_EQ(prealloc_size, info.size);
auto info = tr_sys_file_get_info(fd);
EXPECT_TRUE(info);
EXPECT_EQ(prealloc_size, info->size);
}
else
{

View File

@ -45,15 +45,19 @@ using file_func_t = std::function<void(char const* filename)>;
static void depthFirstWalk(char const* path, file_func_t func)
{
auto info = tr_sys_path_info{};
if (tr_sys_path_get_info(path, 0, &info) && (info.type == TR_SYS_PATH_IS_DIRECTORY))
if (auto const info = tr_sys_path_get_info(path); info && info->isFolder())
{
if (auto const odir = tr_sys_dir_open(path); odir != TR_BAD_SYS_DIR)
{
char const* name;
while ((name = tr_sys_dir_read_name(odir)) != nullptr)
for (;;)
{
if (strcmp(name, ".") != 0 && strcmp(name, "..") != 0)
char const* const name = tr_sys_dir_read_name(odir);
if (name == nullptr)
{
break;
}
if ("."sv != name && ".."sv != name)
{
auto const child = fmt::format("{:s}/{:s}"sv, path, name);
depthFirstWalk(child.c_str(), func);