parent
b8c01a581e
commit
cedec74d26
|
@ -445,20 +445,6 @@ tr_sys_file_t tr_fdFileGetCached(tr_session* s, int torrent_id, tr_file_index_t
|
|||
return o->fd;
|
||||
}
|
||||
|
||||
bool tr_fdFileGetCachedMTime(tr_session* s, int torrent_id, tr_file_index_t i, time_t* mtime)
|
||||
{
|
||||
struct tr_cached_file const* o = fileset_lookup(get_fileset(s), torrent_id, i);
|
||||
auto info = tr_sys_path_info{};
|
||||
bool const success = o != nullptr && tr_sys_file_get_info(o->fd, &info, nullptr);
|
||||
|
||||
if (success)
|
||||
{
|
||||
*mtime = info.last_modified_at;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void tr_fdTorrentClose(tr_session* session, int torrent_id)
|
||||
{
|
||||
TR_ASSERT(tr_sessionIsLocked(session));
|
||||
|
|
|
@ -51,8 +51,6 @@ tr_sys_file_t tr_fdFileCheckout(
|
|||
|
||||
tr_sys_file_t tr_fdFileGetCached(tr_session* session, int torrent_id, tr_file_index_t file_num, bool doWrite);
|
||||
|
||||
bool tr_fdFileGetCachedMTime(tr_session* session, int torrent_id, tr_file_index_t file_num, time_t* mtime);
|
||||
|
||||
/**
|
||||
* Closes a file that's being held by our file repository.
|
||||
*
|
||||
|
|
|
@ -2116,20 +2116,20 @@ static void sessionLoadTorrents(void* vdata)
|
|||
if (odir != TR_BAD_SYS_DIR)
|
||||
{
|
||||
char const* name = nullptr;
|
||||
auto const dirname_sv = std::string_view{ dirname };
|
||||
auto path = std::string{};
|
||||
while ((name = tr_sys_dir_read_name(odir, nullptr)) != nullptr)
|
||||
{
|
||||
if (tr_str_has_suffix(name, ".torrent"))
|
||||
{
|
||||
char* const path = tr_buildPath(dirname, name, nullptr);
|
||||
tr_ctorSetMetainfoFromFile(data->ctor, path);
|
||||
tr_buildBuf(path, dirname_sv, "/", name);
|
||||
tr_ctorSetMetainfoFromFile(data->ctor, path.c_str());
|
||||
|
||||
tr_torrent* const tor = tr_torrentNew(data->ctor, nullptr, nullptr);
|
||||
if (tor != nullptr)
|
||||
{
|
||||
torrents.push_back(tor);
|
||||
}
|
||||
|
||||
tr_free(path);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -808,9 +808,11 @@ void tr_torrentGotNewInfoDict(tr_torrent* tor)
|
|||
|
||||
static bool hasAnyLocalData(tr_torrent const* tor)
|
||||
{
|
||||
auto filename = std::string{};
|
||||
|
||||
for (tr_file_index_t i = 0; i < tor->info.fileCount; ++i)
|
||||
{
|
||||
if (tr_torrentFindFile2(tor, i, nullptr, nullptr, nullptr))
|
||||
if (tor->findFile(filename, i))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -2584,18 +2586,6 @@ bool tr_torrent::checkPiece(tr_piece_index_t piece)
|
|||
return pass;
|
||||
}
|
||||
|
||||
time_t tr_torrentGetFileMTime(tr_torrent const* tor, tr_file_index_t i)
|
||||
{
|
||||
auto mtime = time_t{};
|
||||
|
||||
if (!tr_fdFileGetCachedMTime(tor->session, tor->uniqueId, i, &mtime))
|
||||
{
|
||||
tr_torrentFindFile2(tor, i, nullptr, nullptr, &mtime);
|
||||
}
|
||||
|
||||
return mtime;
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
@ -3305,96 +3295,84 @@ void tr_torrentGotBlock(tr_torrent* tor, tr_block_index_t block)
|
|||
****
|
||||
***/
|
||||
|
||||
static void find_file_in_dir(
|
||||
char const* name,
|
||||
char const* search_dir,
|
||||
char const** base,
|
||||
char const** subpath,
|
||||
tr_sys_path_info* file_info)
|
||||
std::optional<tr_torrent::tr_found_file_t> tr_torrent::findFile(std::string& filename, tr_file_index_t i) const
|
||||
{
|
||||
char* filename = tr_buildPath(search_dir, name, nullptr);
|
||||
|
||||
if (tr_sys_path_get_info(filename, 0, file_info, nullptr))
|
||||
{
|
||||
*base = search_dir;
|
||||
*subpath = name;
|
||||
}
|
||||
|
||||
tr_free(filename);
|
||||
}
|
||||
|
||||
bool tr_torrentFindFile2(tr_torrent const* tor, tr_file_index_t fileNum, char const** base, char** subpath, time_t* mtime)
|
||||
{
|
||||
TR_ASSERT(tr_isTorrent(tor));
|
||||
TR_ASSERT(fileNum < tor->info.fileCount);
|
||||
|
||||
char* part = nullptr;
|
||||
char const* s = nullptr;
|
||||
TR_ASSERT(i < this->info.fileCount);
|
||||
tr_file const& file = info.files[i];
|
||||
auto file_info = tr_sys_path_info{};
|
||||
|
||||
tr_file const* const file = &tor->info.files[fileNum];
|
||||
|
||||
/* look in the download dir... */
|
||||
char const* b = nullptr;
|
||||
find_file_in_dir(file->name, tor->downloadDir, &b, &s, &file_info);
|
||||
|
||||
/* look in the incomplete dir... */
|
||||
if (b == nullptr && tor->incompleteDir != nullptr)
|
||||
if (this->downloadDir != nullptr)
|
||||
{
|
||||
find_file_in_dir(file->name, tor->incompleteDir, &b, &s, &file_info);
|
||||
auto base = std::string_view{ this->downloadDir };
|
||||
|
||||
tr_buildBuf(filename, base, "/"sv, file.name);
|
||||
if (tr_sys_path_get_info(filename.c_str(), 0, &file_info, nullptr))
|
||||
{
|
||||
return tr_found_file_t{ file_info, filename, base };
|
||||
}
|
||||
|
||||
tr_buildBuf(filename, base, "/"sv, file.name, ".part"sv);
|
||||
if (tr_sys_path_get_info(filename.c_str(), 0, &file_info, nullptr))
|
||||
{
|
||||
return tr_found_file_t{ file_info, filename, base };
|
||||
}
|
||||
}
|
||||
|
||||
if (b == nullptr)
|
||||
if (this->incompleteDir != nullptr)
|
||||
{
|
||||
part = tr_torrentBuildPartial(tor, fileNum);
|
||||
auto const base = std::string_view{ this->incompleteDir };
|
||||
|
||||
tr_buildBuf(filename, base, "/"sv, file.name);
|
||||
if (tr_sys_path_get_info(filename.c_str(), 0, &file_info, nullptr))
|
||||
{
|
||||
return tr_found_file_t{ file_info, filename, base };
|
||||
}
|
||||
|
||||
tr_buildBuf(filename, base, "/"sv, file.name, ".part"sv);
|
||||
if (tr_sys_path_get_info(filename.c_str(), 0, &file_info, nullptr))
|
||||
{
|
||||
return tr_found_file_t{ file_info, filename, base };
|
||||
}
|
||||
}
|
||||
|
||||
/* look for a .part file in the incomplete dir... */
|
||||
if (b == nullptr && tor->incompleteDir != nullptr)
|
||||
return {};
|
||||
}
|
||||
|
||||
// TODO: clients that call this should call tr_torrent::findFile() instead
|
||||
bool tr_torrentFindFile2(tr_torrent const* tor, tr_file_index_t fileNum, char const** base, char** subpath, time_t* mtime)
|
||||
{
|
||||
auto filename = std::string{};
|
||||
auto const found = tor->findFile(filename, fileNum);
|
||||
|
||||
if (!found)
|
||||
{
|
||||
find_file_in_dir(part, tor->incompleteDir, &b, &s, &file_info);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* look for a .part file in the download dir... */
|
||||
if (b == nullptr)
|
||||
{
|
||||
find_file_in_dir(part, tor->downloadDir, &b, &s, &file_info);
|
||||
}
|
||||
|
||||
/* return the results */
|
||||
if (base != nullptr)
|
||||
{
|
||||
*base = b;
|
||||
*base = std::data(found->base);
|
||||
}
|
||||
|
||||
if (subpath != nullptr)
|
||||
{
|
||||
*subpath = tr_strdup(s);
|
||||
*subpath = tr_strndup(std::data(found->subpath), std::size(found->subpath));
|
||||
}
|
||||
|
||||
if (mtime != nullptr)
|
||||
{
|
||||
*mtime = file_info.last_modified_at;
|
||||
*mtime = found->last_modified_at;
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
tr_free(part);
|
||||
return b != nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: clients that call this should call tr_torrent::findFile() instead
|
||||
char* tr_torrentFindFile(tr_torrent const* tor, tr_file_index_t fileNum)
|
||||
{
|
||||
char* ret = nullptr;
|
||||
|
||||
char const* base = nullptr;
|
||||
char* subpath = nullptr;
|
||||
if (tr_torrentFindFile2(tor, fileNum, &base, &subpath, nullptr))
|
||||
{
|
||||
ret = tr_buildPath(base, subpath, nullptr);
|
||||
tr_free(subpath);
|
||||
}
|
||||
|
||||
return ret;
|
||||
auto filename = std::string{};
|
||||
auto const found = tor->findFile(filename, fileNum);
|
||||
return found ? tr_strdup(filename.c_str()) : nullptr;
|
||||
}
|
||||
|
||||
/* Decide whether we should be looking for files in downloadDir or incompleteDir. */
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "bandwidth.h" /* tr_bandwidth */
|
||||
#include "bitfield.h"
|
||||
#include "completion.h" /* tr_completion */
|
||||
#include "file.h"
|
||||
#include "session.h" /* tr_sessionLock(), tr_sessionUnlock() */
|
||||
#include "tr-assert.h"
|
||||
#include "tr-macros.h"
|
||||
|
@ -109,8 +110,6 @@ void tr_torrentSetDateActive(tr_torrent* torrent, time_t activityDate);
|
|||
|
||||
void tr_torrentSetDateDone(tr_torrent* torrent, time_t doneDate);
|
||||
|
||||
time_t tr_torrentGetFileMTime(tr_torrent const* tor, tr_file_index_t i);
|
||||
|
||||
/** Return the mime-type (e.g. "audio/x-flac") that matches more of the
|
||||
torrent's content than any other mime-type. */
|
||||
std::string_view tr_torrentPrimaryMimeType(tr_torrent const* tor);
|
||||
|
@ -214,20 +213,41 @@ struct tr_torrent
|
|||
TR_ASSERT(std::size(checked) == info.pieceCount);
|
||||
checked_pieces_ = checked;
|
||||
|
||||
auto filename = std::string{};
|
||||
for (size_t i = 0; i < info.fileCount; ++i)
|
||||
{
|
||||
auto const mtime = tr_torrentGetFileMTime(this, i);
|
||||
auto const found = this->findFile(filename, i);
|
||||
auto const mtime = found ? found->last_modified_at : 0;
|
||||
|
||||
info.files[i].mtime = mtime;
|
||||
|
||||
// if a file has changed, mark its pieces as unchecked
|
||||
if (mtime != mtimes[i])
|
||||
if (mtime == 0 || mtime != mtimes[i])
|
||||
{
|
||||
checked_pieces_.unsetRange(info.files[i].firstPiece, info.files[i].lastPiece);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// FINDING FILES
|
||||
|
||||
struct tr_found_file_t : public tr_sys_path_info
|
||||
{
|
||||
std::string& filename; // /home/foo/Downloads/torrent/01-file-one.txt
|
||||
std::string_view base; // /home/foo/Downloads
|
||||
std::string_view subpath; // /torrent/01-file-one.txt
|
||||
|
||||
tr_found_file_t(tr_sys_path_info info, std::string& f, std::string_view b)
|
||||
: tr_sys_path_info{ info }
|
||||
, filename{ f }
|
||||
, base{ b }
|
||||
, subpath{ f.c_str() + std::size(b) + 1 }
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
std::optional<tr_found_file_t> findFile(std::string& filename, tr_file_index_t i) const;
|
||||
|
||||
///
|
||||
|
||||
uint8_t obfuscatedHash[SHA_DIGEST_LENGTH];
|
||||
|
|
|
@ -11,8 +11,10 @@
|
|||
#include <inttypes.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h> /* size_t */
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <time.h> /* time_t */
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "tr-macros.h"
|
||||
|
@ -80,6 +82,19 @@ uint8_t* tr_loadFile(char const* filename, size_t* size, struct tr_error** error
|
|||
platform's correct directory separator. */
|
||||
char* tr_buildPath(char const* first_element, ...) TR_GNUC_NULL_TERMINATED TR_GNUC_MALLOC;
|
||||
|
||||
template<typename... T, typename std::enable_if_t<(std::is_convertible_v<T, std::string_view> && ...), bool> = true>
|
||||
std::string& tr_buildBuf(std::string& setme, T... args)
|
||||
{
|
||||
setme.clear();
|
||||
auto const n = (std::size(std::string_view{ args }) + ...);
|
||||
if (setme.capacity() < n)
|
||||
{
|
||||
setme.reserve(n);
|
||||
}
|
||||
((setme += args), ...);
|
||||
return setme;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get disk capacity and free disk space (in bytes) for the specified folder.
|
||||
* @return struct with free and total as zero or positive integer on success, -1 in case of error.
|
||||
|
|
Loading…
Reference in New Issue