refactor: make parts of tr file private (#2241)

* refactor: make parts of tr_file private
This commit is contained in:
Charles Kerr 2021-11-27 21:17:47 -06:00 committed by GitHub
parent f6f0db75e1
commit 34881f6295
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 237 additions and 200 deletions

View File

@ -151,12 +151,12 @@ bool refreshFilesForeach(
if (is_file)
{
auto const* tor = refresh_data.tor;
auto const* inf = tr_torrentInfo(tor);
int const enabled = inf->files[index].dnd ? 0 : 1;
int const priority = inf->files[index].priority;
auto const progress = tr_torrentFileProgress(tor, index);
uint64_t const have = progress.bytes_completed;
int const prog = std::clamp(int(100 * progress.progress), 0, 100);
auto const file = tr_torrentFile(tor, index);
int const enabled = file.wanted;
int const priority = file.priority;
auto const progress = file.progress;
uint64_t const have = file.have;
int const prog = std::clamp(int(100 * progress), 0, 100);
if (priority != old_priority || enabled != old_enabled || have != old_have || prog != old_prog)
{
@ -425,9 +425,9 @@ void buildTree(FileRowNode& node, build_data& build)
auto const mime_type = isLeaf ? gtr_get_mime_type_from_filename(child_data.name) : DIRECTORY_MIME_TYPE;
auto const icon = gtr_get_mime_type_icon(mime_type, Gtk::ICON_SIZE_MENU, *build.w);
auto const* inf = tr_torrentInfo(build.tor);
int const priority = isLeaf ? inf->files[child_data.index].priority : 0;
bool const enabled = isLeaf ? !inf->files[child_data.index].dnd : true;
auto const file = tr_torrentFile(build.tor, child_data.index);
int const priority = isLeaf ? file.priority : 0;
bool const enabled = isLeaf ? file.wanted : true;
auto name_esc = Glib::Markup::escape_text(child_data.name);
auto const child_iter = build.store->append(build.iter->children());
@ -490,13 +490,12 @@ void FileList::Impl::set_torrent(int torrentId)
root_data.index = -1;
root_data.length = 0;
auto const* inf = tr_torrentInfo(tor);
for (tr_file_index_t i = 0; i < inf->fileCount; ++i)
for (tr_file_index_t i = 0, n_files = tr_torrentFileCount(tor); i < n_files; ++i)
{
auto* parent = &root;
auto const* const file = &inf->files[i];
auto const file = tr_torrentFile(tor, i);
for (char const *last = file->name, *next = strchr(last, '/'); last != nullptr;
for (char const *last = file.name, *next = strchr(last, '/'); last != nullptr;
last = next != nullptr ? next + 1 : nullptr, next = last != nullptr ? strchr(last, '/') : nullptr)
{
bool const isLeaf = next == nullptr;
@ -509,7 +508,7 @@ void FileList::Impl::set_torrent(int torrentId)
auto& row = node->data();
row.name = std::move(name);
row.index = isLeaf ? (int)i : -1;
row.length = isLeaf ? file->length : 0;
row.length = isLeaf ? file.length : 0;
parent->append(*node);
}

View File

@ -623,15 +623,13 @@ bool testText(tr_torrent const* tor, Glib::ustring const* key)
}
else
{
tr_info const* inf = tr_torrentInfo(tor);
/* test the torrent name... */
ret = Glib::ustring(tr_torrentName(tor)).casefold().find(*key) != Glib::ustring::npos;
/* test the files... */
for (tr_file_index_t i = 0; i < inf->fileCount && !ret; ++i)
for (tr_file_index_t i = 0, n = tr_torrentFileCount(tor); i < n && !ret; ++i)
{
ret = Glib::ustring(inf->files[i].name).casefold().find(*key) != Glib::ustring::npos;
ret = Glib::ustring(tr_torrentFile(tor, i).name).casefold().find(*key) != Glib::ustring::npos;
}
}

View File

@ -105,9 +105,8 @@ void g_signal_callback(
}
else if (action == "file")
{
auto const* inf = tr_torrentInfo(tor);
char const* dir = tr_torrentGetDownloadDir(tor);
auto const path = Glib::build_filename(dir, inf->files[0].name);
auto const path = Glib::build_filename(dir, tr_torrentFile(tor, 0).name);
gtr_open_file(path);
}
else if (action == "start-now")
@ -193,9 +192,7 @@ void gtr_notify_torrent_completed(Glib::RefPtr<Session> const& core, int torrent
std::vector<Glib::ustring> actions;
if (server_supports_actions)
{
auto const* inf = tr_torrentInfo(tor);
if (inf->fileCount == 1)
if (tr_torrentFileCount(tor) == 1)
{
actions.push_back("file");
actions.push_back(_("Open File"));

View File

@ -1827,7 +1827,7 @@ void Session::open_folder(int torrent_id)
if (tor != nullptr)
{
bool const single = tr_torrentInfo(tor)->fileCount == 1;
bool const single = tr_torrentFileCount(tor) == 1;
char const* currentDir = tr_torrentGetCurrentDir(tor);
if (single)

View File

@ -383,23 +383,21 @@ namespace
Glib::RefPtr<Gdk::Pixbuf> get_icon(tr_torrent const* tor, Gtk::IconSize icon_size, Gtk::Widget& for_widget)
{
Glib::ustring mime_type;
auto const* const info = tr_torrentInfo(tor);
auto const n_files = tr_torrentFileCount(tor);
if (info->fileCount == 0)
if (n_files == 0)
{
mime_type = UNKNOWN_MIME_TYPE;
}
else if (info->fileCount > 1)
{
mime_type = DIRECTORY_MIME_TYPE;
}
else if (strchr(info->files[0].name, '/') != nullptr)
else if (n_files > 1)
{
mime_type = DIRECTORY_MIME_TYPE;
}
else
{
mime_type = gtr_get_mime_type_from_filename(info->files[0].name);
auto const* const name = tr_torrentFile(tor, 0).name;
mime_type = strchr(name, '/') != nullptr ? DIRECTORY_MIME_TYPE : gtr_get_mime_type_from_filename(name);
}
return gtr_get_mime_type_icon(mime_type, icon_size, for_widget);

View File

@ -51,14 +51,13 @@ static int readOrWriteBytes(
{
int err = 0;
bool const doWrite = ioMode >= TR_IO_WRITE;
tr_info const* const info = &tor->info;
tr_file const* const file = &info->files[fileIndex];
TR_ASSERT(fileIndex < info->fileCount);
TR_ASSERT(file->length == 0 || fileOffset < file->length);
TR_ASSERT(fileOffset + buflen <= file->length);
TR_ASSERT(fileIndex < tr_torrentFileCount(tor));
auto const file = tr_torrentFile(tor, fileIndex);
TR_ASSERT(file.length == 0 || fileOffset < file.length);
TR_ASSERT(fileOffset + buflen <= file.length);
if (file->length == 0)
if (file.length == 0)
{
return 0;
}
@ -85,17 +84,17 @@ static int readOrWriteBytes(
/* figure out where the file should go, so we can create it */
base = tr_torrentGetCurrentDir(tor);
subpath = tr_sessionIsIncompleteFileNamingEnabled(tor->session) ? tr_torrentBuildPartial(tor, fileIndex) :
tr_strdup(file->name);
tr_strdup(file.name);
}
if (err == 0)
{
/* open (and maybe create) the file */
auto const filename = tr_strvPath(base, subpath);
tr_preallocation_mode const prealloc = (file->dnd || !doWrite) ? TR_PREALLOCATE_NONE :
tor->session->preallocationMode;
tr_preallocation_mode const prealloc = (!file.wanted || !doWrite) ? TR_PREALLOCATE_NONE :
tor->session->preallocationMode;
fd = tr_fdFileCheckout(session, tor->uniqueId, fileIndex, filename.c_str(), doWrite, prealloc, file->length);
fd = tr_fdFileCheckout(session, tor->uniqueId, fileIndex, filename.c_str(), doWrite, prealloc, file.length);
if (fd == TR_BAD_SYS_FILE)
{
err = errno;
@ -124,7 +123,7 @@ static int readOrWriteBytes(
if (!tr_sys_file_read_at(fd, buf, buflen, fileOffset, nullptr, &error))
{
err = error->code;
tr_logAddTorErr(tor, "read failed for \"%s\": %s", file->name, error->message);
tr_logAddTorErr(tor, "read failed for \"%s\": %s", file.name, error->message);
tr_error_free(error);
}
}
@ -133,7 +132,7 @@ static int readOrWriteBytes(
if (!tr_sys_file_write_at(fd, buf, buflen, fileOffset, nullptr, &error))
{
err = error->code;
tr_logAddTorErr(tor, "write failed for \"%s\": %s", file->name, error->message);
tr_logAddTorErr(tor, "write failed for \"%s\": %s", file.name, error->message);
tr_error_free(error);
}
}
@ -155,12 +154,12 @@ static int compareOffsetToFile(void const* a, void const* b)
auto const offset = *static_cast<uint64_t const*>(a);
auto const* file = static_cast<tr_file const*>(b);
if (offset < file->offset)
if (offset < file->priv.offset)
{
return -1;
}
if (offset >= file->offset + file->length)
if (offset >= file->priv.offset + file->length)
{
return 1;
}
@ -187,10 +186,10 @@ void tr_ioFindFileLocation(
if (file != nullptr)
{
*fileIndex = file - tor->info.files;
*fileOffset = offset - file->offset;
*fileOffset = offset - file->priv.offset;
TR_ASSERT(*fileIndex < tor->info.fileCount);
TR_ASSERT(*fileOffset < file->length);
TR_ASSERT(tor->info.files[*fileIndex].offset + *fileOffset == offset);
TR_ASSERT(tor->info.files[*fileIndex].priv.offset + *fileOffset == offset);
}
}

View File

@ -23,6 +23,7 @@
#include "metainfo.h"
#include "platform.h" /* tr_getTorrentDir() */
#include "session.h"
#include "torrent.h"
#include "tr-assert.h"
#include "utils.h"
#include "variant.h"
@ -213,7 +214,7 @@ static char const* parseFiles(tr_info* inf, tr_variant* files, tr_variant const*
}
inf->files[i].length = len;
inf->files[i].is_renamed = is_root_adjusted || is_file_adjusted;
inf->files[i].priv.is_renamed = is_root_adjusted || is_file_adjusted;
inf->totalSize += len;
}
}
@ -224,7 +225,7 @@ static char const* parseFiles(tr_info* inf, tr_variant* files, tr_variant const*
inf->files = tr_new0(tr_file, 1);
inf->files[0].name = tr_strndup(root_name.c_str(), std::size(root_name));
inf->files[0].length = len;
inf->files[0].is_renamed = is_root_adjusted;
inf->files[0].priv.is_renamed = is_root_adjusted;
inf->totalSize += len;
}
else

View File

@ -139,14 +139,12 @@ static uint64_t loadLabels(tr_variant* dict, tr_torrent* tor)
static void saveDND(tr_variant* dict, tr_torrent const* tor)
{
tr_info const* const inf = tr_torrentInfo(tor);
tr_file_index_t const n = inf->fileCount;
auto const n = tr_torrentFileCount(tor);
tr_variant* const list = tr_variantDictAddList(dict, TR_KEY_dnd, n);
for (tr_file_index_t i = 0; i < n; ++i)
{
tr_variantListAddBool(list, inf->files[i].dnd);
tr_variantListAddBool(list, !tr_torrentFile(tor, i).wanted);
}
}
@ -212,13 +210,12 @@ static uint64_t loadDND(tr_variant* dict, tr_torrent* tor)
static void saveFilePriorities(tr_variant* dict, tr_torrent const* tor)
{
tr_info const* const inf = tr_torrentInfo(tor);
tr_file_index_t const n = inf->fileCount;
auto const n = tr_torrentFileCount(tor);
tr_variant* const list = tr_variantDictAddList(dict, TR_KEY_priority, n);
for (tr_file_index_t i = 0; i < n; ++i)
{
tr_variantListAddInt(list, inf->files[i].priority);
tr_variantListAddInt(list, tr_torrentFile(tor, i).priority);
}
}
@ -411,7 +408,7 @@ static void saveFilenames(tr_variant* dict, tr_torrent const* tor)
for (tr_file_index_t i = 0; !any_renamed && i < n; ++i)
{
any_renamed = files[i].is_renamed;
any_renamed = files[i].priv.is_renamed;
}
if (any_renamed)
@ -420,7 +417,7 @@ static void saveFilenames(tr_variant* dict, tr_torrent const* tor)
for (tr_file_index_t i = 0; i < n; ++i)
{
tr_variantListAddStrView(list, files[i].is_renamed ? files[i].name : "");
tr_variantListAddStrView(list, files[i].priv.is_renamed ? files[i].name : "");
}
}
}
@ -442,7 +439,7 @@ static uint64_t loadFilenames(tr_variant* dict, tr_torrent* tor)
{
tr_free(files[i].name);
files[i].name = tr_strvDup(sv);
files[i].is_renamed = true;
files[i].priv.is_renamed = true;
}
}
@ -493,11 +490,11 @@ static void saveProgress(tr_variant* dict, tr_torrent* tor)
tr_variant* const prog = tr_variantDictAddDict(dict, TR_KEY_progress, 4);
// add the mtimes
size_t const n = inf->fileCount;
size_t const n = tr_torrentFileCount(tor);
tr_variant* const l = tr_variantDictAddList(prog, TR_KEY_mtimes, n);
for (auto const *file = inf->files, *end = file + inf->fileCount; file != end; ++file)
for (auto const *file = inf->files, *end = file + n; file != end; ++file)
{
tr_variantListAddInt(l, file->mtime);
tr_variantListAddInt(l, file->priv.mtime);
}
// add the 'checked pieces' bitfield
@ -538,14 +535,14 @@ static uint64_t loadProgress(tr_variant* dict, tr_torrent* tor)
auto ret = uint64_t{};
tr_info const* inf = tr_torrentInfo(tor);
tr_variant* prog = nullptr;
if (tr_variantDictFindDict(dict, TR_KEY_progress, &prog))
if (tr_variant* prog = nullptr; tr_variantDictFindDict(dict, TR_KEY_progress, &prog))
{
/// CHECKED PIECES
auto checked = tr_bitfield(inf->pieceCount);
auto mtimes = std::vector<time_t>{};
mtimes.reserve(inf->fileCount);
auto const n_files = tr_torrentFileCount(tor);
mtimes.reserve(n_files);
// try to load mtimes
tr_variant* l = nullptr;
@ -570,7 +567,7 @@ static uint64_t loadProgress(tr_variant* dict, tr_torrent* tor)
// maybe it's a .resume file from [2.20 - 3.00] with the per-piece mtimes
if (tr_variantDictFindList(prog, TR_KEY_time_checked, &l))
{
for (tr_file_index_t fi = 0; fi < inf->fileCount; ++fi)
for (tr_file_index_t fi = 0; fi < n_files; ++fi)
{
tr_variant* const b = tr_variantListChild(l, fi);
tr_file* const f = &inf->files[fi];
@ -588,7 +585,7 @@ static uint64_t loadProgress(tr_variant* dict, tr_torrent* tor)
tr_variantGetInt(tr_variantListChild(b, 0), &offset);
time_checked = tr_time();
size_t const pieces = f->lastPiece + 1 - f->firstPiece;
size_t const pieces = f->priv.lastPiece + 1 - f->priv.firstPiece;
for (size_t i = 0; i < pieces; ++i)
{
int64_t piece_time = 0;

View File

@ -382,27 +382,25 @@ static void addLabels(tr_torrent const* tor, tr_variant* list)
static void addFileStats(tr_torrent const* tor, tr_variant* list)
{
auto const* const info = tr_torrentInfo(tor);
for (tr_file_index_t i = 0; i < info->fileCount; ++i)
for (tr_file_index_t i = 0, n = tr_torrentFileCount(tor); i < n; ++i)
{
auto const* const file = &info->files[i];
tr_variant* const d = tr_variantListAddDict(list, 3);
tr_variantDictAddInt(d, TR_KEY_bytesCompleted, tr_torrentFileProgress(tor, i).bytes_completed);
tr_variantDictAddInt(d, TR_KEY_priority, file->priority);
tr_variantDictAddBool(d, TR_KEY_wanted, !file->dnd);
auto const file = tr_torrentFile(tor, i);
tr_variant* d = tr_variantListAddDict(list, 3);
tr_variantDictAddInt(d, TR_KEY_bytesCompleted, file.length);
tr_variantDictAddInt(d, TR_KEY_priority, file.priority);
tr_variantDictAddBool(d, TR_KEY_wanted, file.wanted);
}
}
static void addFiles(tr_torrent const* tor, tr_variant* list)
{
auto const* const info = tr_torrentInfo(tor);
for (tr_file_index_t i = 0; i < info->fileCount; ++i)
for (tr_file_index_t i = 0, n = tr_torrentFileCount(tor); i < n; ++i)
{
tr_file const* file = &info->files[i];
auto const file = tr_torrentFile(tor, i);
tr_variant* d = tr_variantListAddDict(list, 3);
tr_variantDictAddInt(d, TR_KEY_bytesCompleted, tr_torrentFileProgress(tor, i).bytes_completed);
tr_variantDictAddInt(d, TR_KEY_length, file->length);
tr_variantDictAddStr(d, TR_KEY_name, file->name);
tr_variantDictAddInt(d, TR_KEY_bytesCompleted, file.have);
tr_variantDictAddInt(d, TR_KEY_length, file.length);
tr_variantDictAddStr(d, TR_KEY_name, file.name);
}
}
@ -570,16 +568,16 @@ static void initField(
break;
case TR_KEY_file_count:
tr_variantInitInt(initme, inf->fileCount);
tr_variantInitInt(initme, tr_torrentFileCount(tor));
break;
case TR_KEY_files:
tr_variantInitList(initme, inf->fileCount);
tr_variantInitList(initme, tr_torrentFileCount(tor));
addFiles(tor, initme);
break;
case TR_KEY_fileStats:
tr_variantInitList(initme, inf->fileCount);
tr_variantInitList(initme, tr_torrentFileCount(tor));
addFileStats(tor, initme);
break;
@ -715,12 +713,14 @@ static void initField(
break;
case TR_KEY_priorities:
tr_variantInitList(initme, inf->fileCount);
for (tr_file_index_t i = 0; i < inf->fileCount; ++i)
{
tr_variantListAddInt(initme, inf->files[i].priority);
auto const n = tr_torrentFileCount(tor);
tr_variantInitList(initme, n);
for (tr_file_index_t i = 0; i < n; ++i)
{
tr_variantListAddInt(initme, tr_torrentFile(tor, i).priority);
}
}
break;
case TR_KEY_queuePosition:
@ -823,13 +823,14 @@ static void initField(
break;
case TR_KEY_wanted:
tr_variantInitList(initme, inf->fileCount);
for (tr_file_index_t i = 0; i < inf->fileCount; ++i)
{
tr_variantListAddInt(initme, inf->files[i].dnd ? 0 : 1);
auto const n = tr_torrentFileCount(tor);
tr_variantInitList(initme, n);
for (tr_file_index_t i = 0; i < n; ++i)
{
tr_variantListAddInt(initme, tr_torrentFile(tor, i).wanted);
}
}
break;
case TR_KEY_webseeds:

View File

@ -584,17 +584,17 @@ static constexpr void initFilePieces(tr_torrent* tor, tr_file_index_t fileIndex)
TR_ASSERT(tor != nullptr);
TR_ASSERT(fileIndex < tor->info.fileCount);
tr_file* file = &tor->info.files[fileIndex];
uint64_t first_byte = file->offset;
uint64_t last_byte = first_byte + (file->length != 0 ? file->length - 1 : 0);
tr_file& file = tor->info.files[fileIndex];
uint64_t first_byte = file.priv.offset;
uint64_t last_byte = first_byte + (file.length != 0 ? file.length - 1 : 0);
file->firstPiece = tor->pieceOf(first_byte);
file->lastPiece = tor->pieceOf(last_byte);
file.priv.firstPiece = tor->pieceOf(first_byte);
file.priv.lastPiece = tor->pieceOf(last_byte);
}
static constexpr bool pieceHasFile(tr_piece_index_t piece, tr_file const* file)
{
return file->firstPiece <= piece && piece <= file->lastPiece;
return file->priv.firstPiece <= piece && piece <= file->priv.lastPiece;
}
static tr_priority_t calculatePiecePriority(tr_info const& info, tr_piece_index_t piece, tr_file_index_t file_hint)
@ -620,12 +620,12 @@ static tr_priority_t calculatePiecePriority(tr_info const& info, tr_piece_index_
break;
}
priority = std::max(priority, file->priority);
priority = std::max(priority, file->priv.priority);
/* When dealing with multimedia files, getting the first and
last pieces can sometimes allow you to preview it a bit
before it's fully downloaded... */
if ((file->priority >= TR_PRI_NORMAL) && (file->firstPiece == piece || file->lastPiece == piece))
if ((file->priv.priority >= TR_PRI_NORMAL) && (file->priv.firstPiece == piece || file->priv.lastPiece == piece))
{
priority = TR_PRI_HIGH;
}
@ -642,7 +642,7 @@ static void tr_torrentInitFilePieces(tr_torrent* tor)
/* assign the file offsets */
for (tr_file_index_t f = 0; f < inf->fileCount; ++f)
{
inf->files[f].offset = offset;
inf->files[f].priv.offset = offset;
offset += inf->files[f].length;
initFilePieces(tor, f);
}
@ -666,7 +666,7 @@ static void tr_torrentInitPiecePriorities(tr_torrent* tor)
for (tr_piece_index_t p = 0; p < inf->pieceCount; ++p)
{
while (inf->files[f].lastPiece < p)
while (inf->files[f].priv.lastPiece < p)
{
++f;
}
@ -1288,7 +1288,7 @@ static uint64_t countFileBytesCompleted(tr_torrent const* tor, tr_file_index_t i
// the first block
if (tor->hasBlock(begin))
{
total += tor->block_size - f.offset % tor->block_size;
total += tor->block_size - f.priv.offset % tor->block_size;
}
// the middle blocks
@ -1302,26 +1302,37 @@ static uint64_t countFileBytesCompleted(tr_torrent const* tor, tr_file_index_t i
// the last block
if (tor->hasBlock(end - 1))
{
total += f.offset + f.length - (uint64_t)tor->block_size * (end - 1);
total += f.priv.offset + f.length - (uint64_t)tor->block_size * (end - 1);
}
return total;
}
tr_file_progress tr_torrentFileProgress(tr_torrent const* torrent, tr_file_index_t file)
tr_file_view tr_torrentFile(tr_torrent const* torrent, tr_file_index_t i)
{
TR_ASSERT(tr_isTorrent(torrent));
TR_ASSERT(file < torrent->info.fileCount);
TR_ASSERT(i < torrent->info.fileCount);
tr_file_index_t const total = torrent->info.files[file].length;
auto const& file = torrent->info.files[i];
auto const* const name = file.name;
auto const priority = file.priv.priority;
auto const wanted = !file.priv.dnd;
auto const length = file.length;
if (torrent->completeness == TR_SEED || total == 0)
if (torrent->completeness == TR_SEED || length == 0)
{
return { total, total, 1.0 };
return { name, length, length, 1.0, priority, wanted };
}
auto const have = countFileBytesCompleted(torrent, file);
return { have, total, have >= total ? 1.0 : have / double(total) };
auto const have = countFileBytesCompleted(torrent, i);
return { name, have, length, have >= length ? 1.0 : have / double(length), priority, wanted };
}
size_t tr_torrentFileCount(tr_torrent const* torrent)
{
TR_ASSERT(tr_isTorrent(torrent));
return torrent->info.fileCount;
}
/***
@ -2060,9 +2071,9 @@ void tr_torrentInitFilePriority(tr_torrent* tor, tr_file_index_t fileIndex, tr_p
auto& info = tor->info;
tr_file* file = &info.files[fileIndex];
file->priority = priority;
file->priv.priority = priority;
for (tr_piece_index_t i = file->firstPiece; i <= file->lastPiece; ++i)
for (tr_piece_index_t i = file->priv.firstPiece; i <= file->priv.lastPiece; ++i)
{
tor->setPiecePriority(i, calculatePiecePriority(info, i, fileIndex));
}
@ -2096,7 +2107,7 @@ tr_priority_t* tr_torrentGetFilePriorities(tr_torrent const* tor)
for (tr_file_index_t i = 0; i < tor->info.fileCount; ++i)
{
p[i] = tor->info.files[i].priority;
p[i] = tor->info.files[i].priv.priority;
}
return p;
@ -2111,9 +2122,9 @@ static void setFileDND(tr_torrent* tor, tr_file_index_t fileIndex, bool doDownlo
bool const dnd = !doDownload;
tr_file* file = &tor->info.files[fileIndex];
file->dnd = dnd;
auto const firstPiece = file->firstPiece;
auto const lastPiece = file->lastPiece;
file->priv.dnd = dnd;
auto const firstPiece = file->priv.firstPiece;
auto const lastPiece = file->priv.lastPiece;
/* can't set the first piece to DND unless
every file using that piece is DND */
@ -2123,12 +2134,12 @@ static void setFileDND(tr_torrent* tor, tr_file_index_t fileIndex, bool doDownlo
{
for (tr_file_index_t i = fileIndex - 1; firstPieceDND; --i)
{
if (tor->info.files[i].lastPiece != firstPiece)
if (tor->info.files[i].priv.lastPiece != firstPiece)
{
break;
}
firstPieceDND = tor->info.files[i].dnd;
firstPieceDND = tor->info.files[i].priv.dnd;
if (i == 0)
{
@ -2143,12 +2154,12 @@ static void setFileDND(tr_torrent* tor, tr_file_index_t fileIndex, bool doDownlo
for (tr_file_index_t i = fileIndex + 1; lastPieceDND && i < tor->info.fileCount; ++i)
{
if (tor->info.files[i].firstPiece != lastPiece)
if (tor->info.files[i].priv.firstPiece != lastPiece)
{
break;
}
lastPieceDND = tor->info.files[i].dnd;
lastPieceDND = tor->info.files[i].priv.dnd;
}
// update dnd_pieces_
@ -2331,7 +2342,7 @@ tr_block_span_t tr_torGetFileBlockSpan(tr_torrent const* tor, tr_file_index_t co
{
tr_file const* f = &tor->info.files[file];
uint64_t offset = f->offset;
uint64_t offset = f->priv.offset;
tr_block_index_t const begin = offset / tor->block_size;
if (f->length == 0)
{
@ -2519,7 +2530,7 @@ uint64_t tr_torrentGetBytesLeftToAllocate(tr_torrent const* tor)
for (tr_file_index_t i = 0; i < tor->info.fileCount; ++i)
{
if (!tor->info.files[i].dnd)
if (!tor->info.files[i].priv.dnd)
{
tr_sys_path_info info;
uint64_t const length = tor->info.files[i].length;
@ -2967,7 +2978,7 @@ static void tr_torrentFileCompleted(tr_torrent* tor, tr_file_index_t fileIndex)
/* now that the file is complete and closed, we can start watching its
* mtime timestamp for changes to know if we need to reverify pieces */
f->mtime = now;
f->priv.mtime = now;
/* if the torrent's current filename isn't the same as the one in the
* metadata -- for example, if it had the ".part" suffix appended to
@ -3002,7 +3013,7 @@ static void tr_torrentPieceCompleted(tr_torrent* tor, tr_piece_index_t pieceInde
{
tr_file const* file = &tor->info.files[i];
if ((file->firstPiece <= pieceIndex) && (pieceIndex <= file->lastPiece) &&
if ((file->priv.firstPiece <= pieceIndex) && (pieceIndex <= file->priv.lastPiece) &&
tor->completion.hasBlocks(tr_torGetFileBlockSpan(tor, i)))
{
tr_torrentFileCompleted(tor, i);
@ -3435,7 +3446,7 @@ static void renameTorrentFileString(tr_torrent* tor, char const* oldpath, char c
{
tr_free(file->name);
file->name = name;
file->is_renamed = true;
file->priv.is_renamed = true;
}
}

View File

@ -305,13 +305,13 @@ public:
auto const found = this->findFile(filename, i);
auto const mtime = found ? found->last_modified_at : 0;
info.files[i].mtime = mtime;
info.files[i].priv.mtime = mtime;
// if a file has changed, mark its pieces as unchecked
if (mtime == 0 || mtime != mtimes[i])
{
auto const begin = info.files[i].firstPiece;
auto const end = info.files[i].lastPiece + 1;
auto const begin = info.files[i].priv.firstPiece;
auto const end = info.files[i].priv.lastPiece + 1;
checked_pieces_.unsetSpan(begin, end);
}
}

View File

@ -42,6 +42,7 @@ struct tr_block_span_t
};
struct tr_ctor;
struct tr_file;
struct tr_error;
struct tr_info;
struct tr_session;
@ -1530,14 +1531,37 @@ void tr_torrentTrackersFree(tr_tracker_stat* trackerStats, int trackerCount);
*/
double* tr_torrentWebSpeeds_KBps(tr_torrent const* torrent);
struct tr_file_progress
struct tr_file_view
{
uint64_t bytes_completed;
uint64_t bytes_total;
// This file's name. Includes the full subpath in the torrent.
char const* name;
// the current size of the file, i.e. how much we've downloaded
uint64_t have;
// the total size of the file
uint64_t length;
// have / length
double progress;
// the file's priority
tr_priority_t priority;
// do we want to download this file?
bool wanted;
};
tr_file_progress tr_torrentFileProgress(tr_torrent const* torrent, tr_file_index_t file);
/**
* Returns a tr_file_view containing information about a file.
*
* This view structure is intended for short-term use. Pointers in it are
* owned and managed by the torrent. Callers who want to keep this info
* must make their own copy.
*/
tr_file_view tr_torrentFile(tr_torrent const* torrent, tr_file_index_t file);
size_t tr_torrentFileCount(tr_torrent const* torrent);
/***********************************************************************
* tr_torrentAvailability
@ -1575,18 +1599,25 @@ void tr_torrentVerify(tr_torrent* torrent, tr_verify_done_func callback_func_or_
* tr_info
**********************************************************************/
struct tr_file_priv
{
uint64_t offset; // file begins at the torrent's nth byte
time_t mtime;
tr_piece_index_t firstPiece; // We need pieces [firstPiece...
tr_piece_index_t lastPiece; // ...lastPiece] to dl this file
int8_t priority; // TR_PRI_HIGH, _NORMAL, or _LOW
bool dnd; // "do not download" flag
bool is_renamed; // true if we're using a different path from the one in the metainfo; ie, if the user has renamed it */
};
/** @brief a part of tr_info that represents a single file of the torrent's content */
struct tr_file
{
time_t mtime;
uint64_t length; /* Length of the file, in bytes */
uint64_t offset; /* file begins at the torrent's nth byte */
// public
char* name; /* Path to the file */
tr_piece_index_t firstPiece; /* We need pieces [firstPiece... */
tr_piece_index_t lastPiece; /* ...lastPiece] to dl this file */
int8_t priority; /* TR_PRI_HIGH, _NORMAL, or _LOW */
bool dnd; /* "do not download" flag */
bool is_renamed; /* true if we're using a different path from the one in the metainfo; ie, if the user has renamed it */
uint64_t length; /* Length of the file, in bytes */
// libtransmission implementation; do not use
tr_file_priv priv;
};
/** @brief information about a torrent that comes from its metainfo file */
@ -1613,6 +1644,8 @@ struct tr_info
/* torrent's source. empty if not set. */
char* source;
// Private.
// Use tr_torrentFile() and tr_torrentFileCount() instead.
tr_file* files;
/* these trackers are sorted by tier */

View File

@ -51,7 +51,7 @@ static bool verifyTorrent(tr_torrent* tor, bool* stopFlag)
while (!*stopFlag && piece < tor->info.pieceCount)
{
tr_file const* file = &tor->info.files[fileIndex];
auto const file_length = tor->info.files[fileIndex].length;
/* if we're starting a new piece... */
if (piecePos == 0)
@ -71,7 +71,7 @@ static bool verifyTorrent(tr_torrent* tor, bool* stopFlag)
/* figure out how much we can read this pass */
uint64_t leftInPiece = tor->pieceSize(piece) - piecePos;
uint64_t leftInFile = file->length - filePos;
uint64_t leftInFile = file_length - filePos;
uint64_t bytesThisPass = std::min(leftInFile, leftInPiece);
bytesThisPass = std::min(bytesThisPass, uint64_t{ buflen });

View File

@ -481,16 +481,16 @@ static void web_response_func(
}
}
static std::string make_url(tr_webseed* w, tr_file const* file)
static std::string make_url(tr_webseed* w, char const* name)
{
struct evbuffer* buf = evbuffer_new();
evbuffer_add(buf, std::data(w->base_url), std::size(w->base_url));
/* if url ends with a '/', add the torrent name */
if (*std::rbegin(w->base_url) == '/' && file->name != nullptr)
if (*std::rbegin(w->base_url) == '/' && name != nullptr)
{
tr_http_escape(buf, file->name, false);
tr_http_escape(buf, name, false);
}
auto url = std::string{ (char const*)evbuffer_pullup(buf, -1), evbuffer_get_length(buf) };
@ -518,12 +518,12 @@ static void task_request_next_chunk(struct tr_webseed_task* t)
auto file_offset = uint64_t{};
tr_ioFindFileLocation(tor, step_piece, step_piece_offset, &file_index, &file_offset);
tr_file const* const file = &inf->files[file_index];
uint64_t this_pass = std::min(remain, file->length - file_offset);
auto const& file = inf->files[file_index];
uint64_t this_pass = std::min(remain, file.length - file_offset);
if (std::empty(urls[file_index]))
{
urls[file_index] = make_url(t->webseed, file);
urls[file_index] = make_url(t->webseed, file.name);
}
char range[64];

View File

@ -1570,7 +1570,7 @@ bool trashDataFile(char const* filename, tr_error** error)
NSIndexSet* indexSet = node.indexes;
for (NSInteger index = indexSet.firstIndex; index != NSNotFound; index = [indexSet indexGreaterThanIndex:index])
{
have += tr_torrentFileProgress(fHandle, index).bytes_completed;
have += tr_torrentFile(fHandle, index).have;
}
return (CGFloat)have / node.size;
@ -1592,8 +1592,8 @@ bool trashDataFile(char const* filename, tr_error** error)
__block BOOL canChange = NO;
[indexSet enumerateIndexesWithOptions:NSEnumerationConcurrent usingBlock:^(NSUInteger index, BOOL* stop) {
auto const progress = tr_torrentFileProgress(fHandle, index);
if (progress.bytes_completed < progress.bytes_total)
auto const file = tr_torrentFile(fHandle, index);
if (file.have < file.length)
{
canChange = YES;
*stop = YES;
@ -1607,7 +1607,8 @@ bool trashDataFile(char const* filename, tr_error** error)
BOOL onState = NO, offState = NO;
for (NSUInteger index = indexSet.firstIndex; index != NSNotFound; index = [indexSet indexGreaterThanIndex:index])
{
if (!fInfo->files[index].dnd || ![self canChangeDownloadCheckForFile:index])
auto const file = tr_torrentFile(fHandle, index);
if (file.wanted || ![self canChangeDownloadCheckForFile:index])
{
onState = YES;
}
@ -1657,7 +1658,7 @@ bool trashDataFile(char const* filename, tr_error** error)
{
for (NSUInteger index = indexSet.firstIndex; index != NSNotFound; index = [indexSet indexGreaterThanIndex:index])
{
if (priority == fInfo->files[index].priority && [self canChangeDownloadCheckForFile:index])
if (priority == tr_torrentFile(fHandle, index).priority && [self canChangeDownloadCheckForFile:index])
{
return YES;
}
@ -1677,7 +1678,7 @@ bool trashDataFile(char const* filename, tr_error** error)
continue;
}
tr_priority_t const priority = fInfo->files[index].priority;
auto const priority = tr_torrentFile(fHandle, index).priority;
switch (priority)
{
case TR_PRI_LOW:
@ -1943,9 +1944,9 @@ bool trashDataFile(char const* filename, tr_error** error)
for (NSInteger i = 0; i < count; i++)
{
tr_file* file = &fInfo->files[i];
auto const file = tr_torrentFile(fHandle, i);
NSString* fullPath = @(file->name);
NSString* fullPath = @(file.name);
NSArray* pathComponents = fullPath.pathComponents;
if (!tempNode)
@ -1956,7 +1957,7 @@ bool trashDataFile(char const* filename, tr_error** error)
[self insertPathForComponents:pathComponents
withComponentIndex:1
forParent:tempNode
fileSize:file->length
fileSize:file.length
index:i
flatList:flatFileList];
}

View File

@ -51,9 +51,9 @@ TEST_P(IncompleteDirTest, incompleteDir)
auto* tor = zeroTorrentInit();
zeroTorrentPopulate(tor, false);
EXPECT_EQ(
makeString(tr_strdup_printf("%s/%s.part", incomplete_dir, tor->info.files[0].name)),
makeString(tr_strdup_printf("%s/%s.part", incomplete_dir, tr_torrentFile(tor, 0).name)),
makeString(tr_torrentFindFile(tor, 0)));
EXPECT_EQ(tr_strvPath(incomplete_dir, tor->info.files[1].name), makeString(tr_torrentFindFile(tor, 1)));
EXPECT_EQ(tr_strvPath(incomplete_dir, tr_torrentFile(tor, 1).name), makeString(tr_torrentFindFile(tor, 1)));
EXPECT_EQ(tor->info.pieceSize, tr_torrentStat(tor)->leftUntilDone);
// auto constexpr completeness_unset = tr_completeness { -1 };
@ -125,9 +125,10 @@ TEST_P(IncompleteDirTest, incompleteDir)
EXPECT_TRUE(waitFor(test, 300));
EXPECT_EQ(TR_SEED, completeness);
for (tr_file_index_t file_index = 0; file_index < tor->info.fileCount; ++file_index)
auto const n = tr_torrentFileCount(tor);
for (tr_file_index_t i = 0; i < n; ++i)
{
EXPECT_EQ(tr_strvPath(download_dir, tor->info.files[file_index].name), makeString(tr_torrentFindFile(tor, file_index)));
EXPECT_EQ(tr_strvPath(download_dir, tr_torrentFile(tor, i).name), makeString(tr_torrentFindFile(tor, i)));
}
// cleanup
@ -178,11 +179,10 @@ TEST_F(MoveTest, setLocation)
// confirm the files really got moved
sync();
for (tr_file_index_t file_index = 0; file_index < tor->info.fileCount; ++file_index)
auto const n = tr_torrentFileCount(tor);
for (tr_file_index_t i = 0; i < n; ++i)
{
EXPECT_EQ(
tr_strvPath(target_dir.data(), tor->info.files[file_index].name),
makeString(tr_torrentFindFile(tor, file_index)));
EXPECT_EQ(tr_strvPath(target_dir.data(), tr_torrentFile(tor, i).name), makeString(tr_torrentFindFile(tor, i)));
}
// cleanup

View File

@ -152,11 +152,12 @@ TEST_F(RenameTest, singleFilenameTorrent)
"OmhlbGxvLXdvcmxkLnR4dDEyOnBpZWNlIGxlbmd0aGkzMjc2OGU2OnBpZWNlczIwOukboJcrkFUY"
"f6LvqLXBVvSHqCk6Nzpwcml2YXRlaTBlZWU=");
EXPECT_TRUE(tr_isTorrent(tor));
auto const& files = tor->info.files;
// sanity check the info
EXPECT_EQ(tr_file_index_t{ 1 }, tor->info.fileCount);
EXPECT_STREQ("hello-world.txt", tor->info.files[0].name);
EXPECT_FALSE(tor->info.files[0].is_renamed);
EXPECT_STREQ("hello-world.txt", files[0].name);
EXPECT_FALSE(files[0].priv.is_renamed);
// sanity check the (empty) stats
blockingTorrentVerify(tor);
@ -189,8 +190,8 @@ TEST_F(RenameTest, singleFilenameTorrent)
EXPECT_EQ(0, torrentRenameAndWait(tor, "hello-world.txt", "hello-world.txt"));
EXPECT_EQ(EINVAL, torrentRenameAndWait(tor, "hello-world.txt", "hello/world.txt"));
EXPECT_FALSE(tor->info.files[0].is_renamed);
EXPECT_STREQ("hello-world.txt", tor->info.files[0].name);
EXPECT_FALSE(files[0].priv.is_renamed);
EXPECT_STREQ("hello-world.txt", files[0].name);
/***
**** Now try a rename that should succeed
@ -201,9 +202,9 @@ TEST_F(RenameTest, singleFilenameTorrent)
EXPECT_STREQ("hello-world.txt", tr_torrentName(tor));
EXPECT_EQ(0, torrentRenameAndWait(tor, tor->info.name, "foobar"));
EXPECT_FALSE(tr_sys_path_exists(tmpstr.c_str(), nullptr)); // confirm the old filename can't be found
EXPECT_TRUE(tor->info.files[0].is_renamed); // confirm the file's 'renamed' flag is set
EXPECT_TRUE(files[0].priv.is_renamed); // confirm the file's 'renamed' flag is set
EXPECT_STREQ("foobar", tr_torrentName(tor)); // confirm the torrent's name is now 'foobar'
EXPECT_STREQ("foobar", tor->info.files[0].name); // confirm the file's name is now 'foobar' in our struct
EXPECT_STREQ("foobar", files[0].name); // confirm the file's name is now 'foobar' in our struct
EXPECT_STREQ(nullptr, strstr(tor->info.torrent, "foobar")); // confirm the name in the .torrent file hasn't changed
tmpstr = tr_strvPath(tor->currentDir, "foobar");
EXPECT_TRUE(tr_sys_path_exists(tmpstr.c_str(), nullptr)); // confirm the file's name is now 'foobar' on the disk
@ -224,8 +225,8 @@ TEST_F(RenameTest, singleFilenameTorrent)
EXPECT_TRUE(tr_sys_path_exists(tmpstr.c_str(), nullptr));
EXPECT_EQ(0, torrentRenameAndWait(tor, "foobar", "hello-world.txt"));
EXPECT_FALSE(tr_sys_path_exists(tmpstr.c_str(), nullptr));
EXPECT_TRUE(tor->info.files[0].is_renamed);
EXPECT_STREQ("hello-world.txt", tor->info.files[0].name);
EXPECT_TRUE(files[0].priv.is_renamed);
EXPECT_STREQ("hello-world.txt", files[0].name);
EXPECT_STREQ("hello-world.txt", tr_torrentName(tor));
EXPECT_TRUE(testFileExistsAndConsistsOfThisString(tor, 0, "hello, world!\n"));
@ -269,7 +270,7 @@ TEST_F(RenameTest, multifileTorrent)
"MjpwaWVjZSBsZW5ndGhpMzI3NjhlNjpwaWVjZXMyMDp27buFkmy8ICfNX4nsJmt0Ckm2Ljc6cHJp"
"dmF0ZWkwZWVl");
EXPECT_TRUE(tr_isTorrent(tor));
auto const* files = tor->info.files;
auto* files = tor->info.files;
// sanity check the info
EXPECT_STREQ("Felidae", tor->info.name);
@ -321,16 +322,16 @@ TEST_F(RenameTest, multifileTorrent)
EXPECT_EQ(expected_files[3], files[3].name);
EXPECT_TRUE(testFileExistsAndConsistsOfThisString(tor, 1, expected_contents[1]));
EXPECT_TRUE(testFileExistsAndConsistsOfThisString(tor, 2, expected_contents[2]));
EXPECT_FALSE(files[0].is_renamed);
EXPECT_TRUE(files[1].is_renamed);
EXPECT_TRUE(files[2].is_renamed);
EXPECT_FALSE(files[3].is_renamed);
EXPECT_FALSE(files[0].priv.is_renamed);
EXPECT_TRUE(files[1].priv.is_renamed);
EXPECT_TRUE(files[2].priv.is_renamed);
EXPECT_FALSE(files[3].priv.is_renamed);
// (while the branch is renamed: confirm that the .resume file remembers the changes)
tr_torrentSaveResume(tor);
// this is a bit dodgy code-wise, but let's make sure the .resume file got the name
tr_free(files[1].name);
tor->info.files[1].name = tr_strdup("gabba gabba hey");
files[1].name = tr_strdup("gabba gabba hey");
auto const loaded = tr_torrentLoadResume(tor, ~0ULL, ctor, nullptr);
EXPECT_NE(decltype(loaded){ 0 }, (loaded & TR_FR_FILENAMES));
EXPECT_EQ(expected_files[0], files[0].name);
@ -347,10 +348,10 @@ TEST_F(RenameTest, multifileTorrent)
EXPECT_TRUE(testFileExistsAndConsistsOfThisString(tor, i, expected_contents[i]));
}
EXPECT_FALSE(files[0].is_renamed);
EXPECT_TRUE(files[1].is_renamed);
EXPECT_TRUE(files[2].is_renamed);
EXPECT_FALSE(files[3].is_renamed);
EXPECT_FALSE(files[0].priv.is_renamed);
EXPECT_TRUE(files[1].priv.is_renamed);
EXPECT_TRUE(files[2].priv.is_renamed);
EXPECT_FALSE(files[3].priv.is_renamed);
/***
**** Test it an incomplete torrent...
@ -448,18 +449,18 @@ TEST_F(RenameTest, multifileTorrent)
// rename prefix of top
EXPECT_EQ(EINVAL, torrentRenameAndWait(tor, "Feli", "FelidaeX"));
EXPECT_STREQ("Felidae", tor->info.name);
EXPECT_FALSE(files[0].is_renamed);
EXPECT_FALSE(files[1].is_renamed);
EXPECT_FALSE(files[2].is_renamed);
EXPECT_FALSE(files[3].is_renamed);
EXPECT_FALSE(files[0].priv.is_renamed);
EXPECT_FALSE(files[1].priv.is_renamed);
EXPECT_FALSE(files[2].priv.is_renamed);
EXPECT_FALSE(files[3].priv.is_renamed);
// rename false path
EXPECT_EQ(EINVAL, torrentRenameAndWait(tor, "Felidae/FelinaeX", "Genus Felinae"));
EXPECT_STREQ("Felidae", tor->info.name);
EXPECT_FALSE(files[0].is_renamed);
EXPECT_FALSE(files[1].is_renamed);
EXPECT_FALSE(files[2].is_renamed);
EXPECT_FALSE(files[3].is_renamed);
EXPECT_FALSE(files[0].priv.is_renamed);
EXPECT_FALSE(files[1].priv.is_renamed);
EXPECT_FALSE(files[2].priv.is_renamed);
EXPECT_FALSE(files[3].priv.is_renamed);
/***
****
@ -486,17 +487,18 @@ TEST_F(RenameTest, partialFile)
***/
auto* tor = zeroTorrentInit();
auto const& files = tor->info.files;
EXPECT_EQ(TotalSize, tor->info.totalSize);
EXPECT_EQ(PieceSize, tor->info.pieceSize);
EXPECT_EQ(PieceCount, tor->info.pieceCount);
EXPECT_STREQ("files-filled-with-zeroes/1048576", tor->info.files[0].name);
EXPECT_STREQ("files-filled-with-zeroes/4096", tor->info.files[1].name);
EXPECT_STREQ("files-filled-with-zeroes/512", tor->info.files[2].name);
EXPECT_STREQ("files-filled-with-zeroes/1048576", files[0].name);
EXPECT_STREQ("files-filled-with-zeroes/4096", files[1].name);
EXPECT_STREQ("files-filled-with-zeroes/512", files[2].name);
zeroTorrentPopulate(tor, false);
EXPECT_EQ(Length[0], tr_torrentFileProgress(tor, 0).bytes_completed + PieceSize);
EXPECT_EQ(Length[1], tr_torrentFileProgress(tor, 1).bytes_completed);
EXPECT_EQ(Length[2], tr_torrentFileProgress(tor, 2).bytes_completed);
EXPECT_EQ(Length[0], tr_torrentFile(tor, 0).have + PieceSize);
EXPECT_EQ(Length[1], tr_torrentFile(tor, 1).have);
EXPECT_EQ(Length[2], tr_torrentFile(tor, 2).have);
auto const* st = tr_torrentStat(tor);
EXPECT_EQ(TotalSize, st->sizeWhenDone);
EXPECT_EQ(PieceSize, st->leftUntilDone);
@ -514,7 +516,7 @@ TEST_F(RenameTest, partialFile)
for (tr_file_index_t i = 0; i < 3; ++i)
{
EXPECT_STREQ(strings[i], tor->info.files[i].name);
EXPECT_STREQ(strings[i], files[i].name);
}
strings[0] = "foo/bar.part";