use std::filesystem::path for file pathes

This commit is contained in:
orignal
2026-08-13 10:09:03 -04:00
parent 7aa2060bad
commit dae730250f
2 changed files with 89 additions and 57 deletions
+75 -45
View File
@@ -17,7 +17,6 @@
#include <set>
#include <boost/algorithm/string.hpp>
#include "Log.h"
#include "FS.h"
#include "I2PEndian.h"
#include "ClientContext.h"
#include "Timestamp.h"
@@ -564,7 +563,7 @@ namespace torrents
m_IsComplete = true;
}
void Torrent::SaveTorrentResumeFile (const std::string& fullPath)
void Torrent::SaveTorrentResumeFile (const std::filesystem::path& fullPath)
{
auto [bitfield, empty] = CreateBitfield ();
if (empty) return;
@@ -595,8 +594,11 @@ namespace torrents
{
if (index < 0 || index >= (int)m_Pieces.size ()) return {};
if (m_Files.empty ())
return { { IsComplete () ? m_FullPath : (m_FullPath + ".part"),
index*m_PieceLength, 0, m_Pieces[index].GetSize () } };
{
auto fullPath = m_FullPath;
if (!IsComplete ()) fullPath += ".part";
return { { fullPath, index*m_PieceLength, 0, m_Pieces[index].GetSize () } };
}
else
{
std::vector<PieceFileFragment> ret;
@@ -615,16 +617,18 @@ namespace torrents
size_t size = m_Pieces[index].GetSize (), fragmentOffset = 0;
while (size > 0)
{
auto filePath = it->first;
if (!IsComplete ()) filePath += ".part";
if (offset + size <= it->second)
{
// last fragment
ret.emplace_back (IsComplete () ? it->first : (it->first + ".part"), offset, fragmentOffset, size);
ret.emplace_back (filePath, offset, fragmentOffset, size);
size = 0;
}
else
{
size_t l = it->second - offset;
ret.emplace_back (IsComplete () ? it->first : (it->first + ".part"), offset, fragmentOffset, l);
ret.emplace_back (filePath, offset, fragmentOffset, l);
size -= l; fragmentOffset += l;
offset = 0; it++;
if (it == m_Files.end ()) break;
@@ -1069,7 +1073,8 @@ namespace torrents
Piece& piece = torrent->GetPiece (index);
for (auto& it: fragments)
piece.Dump (std::move (it));
torrent->SaveTorrentResumeFile (torrent->GetFullPath () + ".resume");
auto resumeFilePath = torrent->GetFullPath (); resumeFilePath += ".resume";
torrent->SaveTorrentResumeFile (resumeFilePath);
});
// send have
auto conns = GetTorrentsTunnel ()->GetTorrentConnections (m_Torrent);
@@ -1299,8 +1304,8 @@ namespace torrents
TorrentsTunnel::TorrentsTunnel (std::string_view name, std::shared_ptr<i2p::client::ClientDestination> localDestination,
std::string_view torrentsDir, std::string_view trackers):
i2p::client::I2PService (localDestination), m_Name (name), m_TorrentsDir (torrentsDir),
m_PeerID ("-I2PD-"), m_TrackerRequestsCheckTimer (GetService ()),
i2p::client::I2PService (localDestination), m_Name (name), m_PeerID ("-I2PD-"),
m_TorrentsDir (torrentsDir), m_TrackerRequestsCheckTimer (GetService ()),
m_KeepAliveCheckTimer (GetService ()), m_ReconnectCheckTimer (GetService ()),
m_TorrentsStatusUpdateTimer (GetService ())
{
@@ -1350,7 +1355,7 @@ namespace torrents
m_Torrents.clear ();
for (auto it: m_Torrents)
{
auto fullPath = it.second->GetFullPath () + ".resume";
auto fullPath = it.second->GetFullPath (); fullPath += ".resume";
boost::asio::post (m_DiskIOService.GetService (), [torrent = it.second, fullPath]()
{
torrent->SaveTorrentResumeFile (fullPath);
@@ -1374,17 +1379,17 @@ namespace torrents
s.read(buf, len);
auto torrent = std::make_shared<Torrent>(std::string_view{buf, len});
delete[] buf;
torrent->SetFullPath (GetTorrentFilePath (torrent->GetName ()));
torrent->SetFullPath (m_TorrentsDir / std::filesystem::path (torrent->GetName ()));
m_Torrents.emplace (torrent->GetInfoHash (), torrent);
if (torrent->GetFiles ().empty ())
{
if (i2p::fs::Exists (torrent->GetFullPath ()))
if (std::filesystem::exists (torrent->GetFullPath ()))
torrent->SetComplete ();
else
{
auto partFilePath = torrent->GetFullPath () + ".part";
if (!i2p::fs::Exists (partFilePath))
i2p::fs::CreateAndReserveFile (partFilePath, torrent->GetLength ());
auto partFilePath = torrent->GetFullPath (); partFilePath += ".part";
if (!std::filesystem::exists (partFilePath))
CreateAndReserveFile (partFilePath, torrent->GetLength ());
}
}
else
@@ -1392,19 +1397,19 @@ namespace torrents
bool completed = true;
for (auto& [filePath, fileLength]: torrent->GetFiles ())
{
filePath = GetTorrentFilePath (torrent->GetName (), filePath);
if (!i2p::fs::Exists (filePath))
filePath = std::filesystem::path (torrent->GetName ())/filePath;
if (!std::filesystem::exists (filePath))
{
auto partFilePath = filePath + ".part";
if (!i2p::fs::Exists (partFilePath))
i2p::fs::CreateAndReserveFile (partFilePath, fileLength);
auto partFilePath = filePath; partFilePath += ".part";
if (!std::filesystem::exists (partFilePath))
CreateAndReserveFile (partFilePath, fileLength);
completed = false;
}
}
if (completed) torrent->SetComplete ();
}
auto resumeFilePath = torrent->GetFullPath () + ".resume";
if (i2p::fs::Exists (resumeFilePath ))
auto resumeFilePath = torrent->GetFullPath (); resumeFilePath += ".resume";
if (std::filesystem::exists (resumeFilePath ))
{
if (!torrent->IsComplete ())
{
@@ -1424,7 +1429,7 @@ namespace torrents
}
}
else
i2p::fs::Remove (resumeFilePath);
std::filesystem::remove (resumeFilePath);
}
}
else
@@ -1434,6 +1439,43 @@ namespace torrents
LogPrint (eLogError, "Torrents: Can't open file ", path);
}
bool TorrentsTunnel::CreateAndReserveFile (const std::filesystem::path& filePath, size_t reserve)
{
if (std::filesystem::exists (filePath)) return false;
auto subdirs = filePath.parent_path ();
if (!subdirs.empty ())
{
// try to create all subdirs
try
{
std::filesystem::create_directories (subdirs);
}
catch (std::exception& ex)
{
LogPrint (eLogError, "FS: Can't create subdirs ", subdirs, " : ", ex.what());
return false;
}
}
// create file
std::ofstream f(filePath, std::ios::binary);
if (!f) return false;
f.close ();
if (reserve > 0)
{
// resize
try
{
std::filesystem::resize_file (filePath, reserve);
}
catch (std::exception& ex)
{
LogPrint (eLogError, "FS: Can't resize file ", filePath, " to ", reserve, " : ", ex.what());
return false;
}
}
return true;
}
void TorrentsTunnel::CompleteTorrent (std::shared_ptr<Torrent> torrent)
{
boost::asio::post (GetDiskIOService (), [this, torrent]()
@@ -1441,8 +1483,10 @@ namespace torrents
bool completed = false;
if (torrent->GetFiles ().empty ())
{
auto partFilePath = torrent->GetFullPath () + ".part";
if (i2p::fs::Rename (partFilePath, torrent->GetFullPath ()))
auto partFilePath = torrent->GetFullPath (); partFilePath += ".part";
std::error_code ec;
std::filesystem::rename (partFilePath, torrent->GetFullPath (), ec);
if (!ec)
completed = true;
else
LogPrint (eLogError, "Torrents: Can't rename ", partFilePath);
@@ -1452,8 +1496,10 @@ namespace torrents
completed = true;
for (const auto& [filePath, fileSize]: torrent->GetFiles ())
{
auto partFilePath = filePath + ".part";
if (!i2p::fs::Rename (partFilePath, filePath))
auto partFilePath = filePath; partFilePath += ".part";
std::error_code ec;
std::filesystem::rename (partFilePath, filePath, ec);
if (ec)
{
completed = false;
LogPrint (eLogError, "Torrents: Can't rename ", partFilePath);
@@ -1464,8 +1510,8 @@ namespace torrents
{
torrent->SetComplete ();
RequestTracker (torrent, "completed");
auto resumeFilePath = torrent->GetFullPath () + ".resume";
if (!i2p::fs::Remove (resumeFilePath))
auto resumeFilePath = torrent->GetFullPath (); resumeFilePath += ".resume";
if (!std::filesystem::remove (resumeFilePath))
LogPrint (eLogError, "Torrents: Can't delete resume file ", resumeFilePath);
LogPrint (eLogInfo, "Torrents: Download complete ", torrent->GetFullPath ());
// close connections with seeds
@@ -1610,22 +1656,6 @@ namespace torrents
return peersToConnect.size ();
}
std::string TorrentsTunnel::GetTorrentFilePath (std::string_view filename) const
{
std::stringstream s("");
s << m_TorrentsDir;
i2p::fs::_ExpandPath(s, filename);
return s.str ();
}
std::string TorrentsTunnel::GetTorrentFilePath (std::string_view subdir, std::string_view filename) const
{
std::stringstream s("");
s << m_TorrentsDir;
i2p::fs::_ExpandPath(s, subdir, filename);
return s.str ();
}
void TorrentsTunnel::ScheduleTrackerRequestsCheck ()
{
m_TrackerRequestsCheckTimer.expires_after (std::chrono::milliseconds(TRACKER_REQUESTS_CHECK_TIMEOUT));
+14 -12
View File
@@ -23,6 +23,7 @@
#include <string_view>
#include <random>
#include <tuple>
#include <filesystem>
#include "util.h"
#include "Streaming.h"
#include "HTTP.h"
@@ -76,12 +77,12 @@ namespace torrents
struct PieceFileFragment // fragment to save to/load from file
{
std::string fullFilePath;
std::filesystem::path fullFilePath;
size_t fileOffset;
size_t fragmentOffset; // from start of piece
size_t fragmentSize;
PieceFileFragment (const std::string& fullFilePath1, size_t fileOffset1, size_t fragmentOffset1, size_t fragmentSize1):
PieceFileFragment (const std::filesystem::path& fullFilePath1, size_t fileOffset1, size_t fragmentOffset1, size_t fragmentSize1):
fullFilePath (fullFilePath1), fileOffset (fileOffset1), fragmentOffset (fragmentOffset1), fragmentSize (fragmentSize1) {};
PieceFileFragment (PieceFileFragment&& ) = default;
PieceFileFragment (const PieceFileFragment& ) = default;
@@ -152,10 +153,10 @@ namespace torrents
std::string_view GetAnnounce () const { return m_Announce; }
std::string_view GetName () const { return m_Name; }
const std::string& GetFullPath () const { return m_FullPath; }
void SetFullPath (std::string_view fullPath) { m_FullPath = fullPath; }
const std::list<std::pair<std::string, size_t> >& GetFiles () const { return m_Files; }
std::list<std::pair<std::string, size_t> >& GetFiles () { return m_Files; }
const std::filesystem::path& GetFullPath () const { return m_FullPath; }
void SetFullPath (const std::filesystem::path& fullPath) { m_FullPath = fullPath; }
const std::list<std::pair<std::filesystem::path, size_t> >& GetFiles () const { return m_Files; }
std::list<std::pair<std::filesystem::path, size_t> >& GetFiles () { return m_Files; }
size_t GetLength () const { return m_Length; }
size_t GetPieceLength () const { return m_PieceLength; }
int GetInterval () const { return m_Interval; }
@@ -176,7 +177,7 @@ namespace torrents
size_t GetUploaded () const { return m_Uploaded; }
void AddUploaded (size_t add) { m_Uploaded += add; }
void SaveTorrentResumeFile (const std::string& fullPath);
void SaveTorrentResumeFile (const std::filesystem::path& fullPath);
void StartCountingPeers ();
void ApplyPeerRemoteBitfield (const boost::dynamic_bitset<>& peerRemoteBitfield);
@@ -190,7 +191,8 @@ namespace torrents
private:
std::string m_Name, m_FullPath, m_Announce;
std::string m_Name, m_Announce;
std::filesystem::path m_FullPath;
size_t m_Length, m_PieceLength;
int m_Interval; // in miiliseconds
uint64_t m_NextTrackerRequestTime; // monotonic millicesonds
@@ -198,7 +200,7 @@ namespace torrents
std::vector<Piece> m_Pieces;
std::unordered_set<i2p::data::IdentHash> m_Peers;
bool m_IsComplete;
std::list<std::pair<std::string, size_t> > m_Files; // list of (path, length)
std::list<std::pair<std::filesystem::path, size_t> > m_Files; // list of (path, length)
size_t m_Uploaded;
};
@@ -314,11 +316,10 @@ namespace torrents
private:
std::string GetTorrentFilePath (std::string_view filename) const;
std::string GetTorrentFilePath (std::string_view subdir, std::string_view filename) const;
void Accept ();
void ReadTorrentFile (const std::string& path);
bool CreateAndReserveFile (const std::filesystem::path& filePath, size_t reserve);
void CompleteTorrent (std::shared_ptr<Torrent> torrent);
void RequestTracker (std::shared_ptr<Torrent> torrent, std::string_view event = "");
void TrackerRequestSent (const boost::beast::error_code& ecode, size_t bytes_transferred,
@@ -344,7 +345,8 @@ namespace torrents
private:
std::string m_Name, m_TorrentsDir, m_PeerID; // 20 characters
std::string m_Name, m_PeerID; // 20 characters
std::filesystem::path m_TorrentsDir;
std::vector<std::string> m_Trackers;
std::map<Torrent::InfoHash, std::shared_ptr<Torrent> > m_Torrents;
boost::asio::steady_timer m_TrackerRequestsCheckTimer, m_KeepAliveCheckTimer,