diff --git a/Transmission.xcodeproj/project.pbxproj b/Transmission.xcodeproj/project.pbxproj index c5c231094..80f952707 100644 --- a/Transmission.xcodeproj/project.pbxproj +++ b/Transmission.xcodeproj/project.pbxproj @@ -367,6 +367,7 @@ ED8A16422735A8AA000D61F9 /* peer-mgr-wishlist.cc in Sources */ = {isa = PBXBuildFile; fileRef = ED8A163E2735A8AA000D61F9 /* peer-mgr-wishlist.cc */; }; EDBDFA9E25AFCCA60093D9C1 /* evutil_time.c in Sources */ = {isa = PBXBuildFile; fileRef = EDBDFA9D25AFCCA60093D9C1 /* evutil_time.c */; }; F11545ACA7C4D7A464F703AB /* block-info.h in Headers */ = {isa = PBXBuildFile; fileRef = 6A044CBD8C049AFCBD4DB411 /* block-info.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E23B55A5FC3B557F7746D510 /* interned-string.h in Headers */ = {isa = PBXBuildFile; fileRef = E23B55A5FC3B557F7746D511 /* interned-string.h */; settings = {ATTRIBUTES = (Project, ); }; }; F63480631E1D7274005B9E09 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F63480621E1D7274005B9E09 /* Images.xcassets */; }; /* End PBXBuildFile section */ @@ -544,6 +545,7 @@ 4DFBC2DE09C0970D00D5C571 /* Torrent.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = Torrent.mm; sourceTree = ""; }; 55869925257074EC00F77A43 /* libcurl.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libcurl.tbd; path = usr/lib/libcurl.tbd; sourceTree = SDKROOT; }; 6A044CBD8C049AFCBD4DB411 /* block-info.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "block-info.h"; path = "block-info.h"; sourceTree = SOURCE_ROOT; }; + E23B55A5FC3B557F7746D511 /* interned-string.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "interned-string.h"; path = "interned-string.h"; sourceTree = SOURCE_ROOT; }; 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 8D1107320486CEB800E47090 /* Transmission.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Transmission.app; sourceTree = BUILT_PRODUCTS_DIR; }; A200B8390A2263BA007BBB1E /* InfoWindowController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InfoWindowController.h; sourceTree = ""; }; @@ -1375,6 +1377,7 @@ children = ( A54D44C6A7AAF131D9AE29F5 /* block-info.cc */, 6A044CBD8C049AFCBD4DB411 /* block-info.h */, + E23B55A5FC3B557F7746D511 /* interned-string.h */, C17740D3273A002C00E455D2 /* web-utils.cc */, C17740D4273A002C00E455D2 /* web-utils.h */, CAB35C62252F6F5E00552A55 /* mime-types.h */, @@ -1897,6 +1900,7 @@ A2AF23C916B44FA0003BC59E /* log.h in Headers */, A23FAE55178BC2950053DC5B /* platform-quota.h in Headers */, F11545ACA7C4D7A464F703AB /* block-info.h in Headers */, + E23B55A5FC3B557F7746D510 /* interned-string.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/libtransmission/announce-list.cc b/libtransmission/announce-list.cc index 6d667dd59..8615b70ca 100644 --- a/libtransmission/announce-list.cc +++ b/libtransmission/announce-list.cc @@ -82,20 +82,20 @@ bool tr_announce_list::add(tr_tracker_tier_t tier, std::string_view announce_url } auto tracker = tracker_info{}; - tracker.announce_interned = tr_quark_new(announce_url_sv); - tracker.announce = *tr_urlParseTracker(tr_quark_get_string_view(tracker.announce_interned)); + tracker.announce_str = announce_url_sv; + tracker.announce = *tr_urlParseTracker(tracker.announce_str.sv()); tracker.tier = getTier(tier, *announce); tracker.id = nextUniqueId(); auto host = std::string{ tracker.announce.host }; host += ':'; host += tracker.announce.portstr; - tracker.host = tr_quark_new(host); + tracker.host = host; auto const scrape_str = announceToScrape(announce_url_sv); if (scrape_str) { - tracker.scrape_interned = tr_quark_new(*scrape_str); - tracker.scrape = *tr_urlParseTracker(tr_quark_get_string_view(tracker.scrape_interned)); + tracker.scrape_str = *scrape_str; + tracker.scrape = *tr_urlParseTracker(tracker.scrape_str.sv()); } auto const it = std::lower_bound(std::begin(trackers_), std::end(trackers_), tracker); @@ -221,7 +221,7 @@ bool tr_announce_list::save(char const* torrent_file, tr_error** error) const // add the new fields if (this->size() == 1) { - tr_variantDictAddQuark(&metainfo, TR_KEY_announce, at(0).announce_interned); + tr_variantDictAddQuark(&metainfo, TR_KEY_announce, at(0).announce_str.quark()); } else if (this->size() > 1) { @@ -238,7 +238,7 @@ bool tr_announce_list::save(char const* torrent_file, tr_error** error) const current_tier = tracker.tier; } - tr_variantListAddQuark(tracker_list, tracker.announce_interned); + tr_variantListAddQuark(tracker_list, tracker.announce_str.quark()); } } diff --git a/libtransmission/announce-list.h b/libtransmission/announce-list.h index ca153dab7..1469aea50 100644 --- a/libtransmission/announce-list.h +++ b/libtransmission/announce-list.h @@ -23,7 +23,7 @@ #include "transmission.h" -#include "quark.h" +#include "interned-string.h" #include "web-utils.h" struct tr_error; @@ -33,11 +33,11 @@ class tr_announce_list public: struct tracker_info { - tr_quark host; tr_url_parsed_t announce; tr_url_parsed_t scrape; - tr_quark announce_interned = TR_KEY_NONE; - tr_quark scrape_interned = TR_KEY_NONE; + tr_interned_string announce_str; + tr_interned_string scrape_str; + tr_interned_string host; tr_tracker_tier_t tier = 0; tr_tracker_id_t id = 0; diff --git a/libtransmission/announcer-common.h b/libtransmission/announcer-common.h index 8a9063054..72cb9ecab 100644 --- a/libtransmission/announcer-common.h +++ b/libtransmission/announcer-common.h @@ -19,7 +19,7 @@ #include "transmission.h" -#include "quark.h" +#include "interned-string.h" #include "web-utils.h" /*** @@ -40,7 +40,7 @@ auto inline constexpr TR_MULTISCRAPE_MAX = 60; struct tr_scrape_request { /* the scrape URL */ - tr_quark scrape_url; + tr_interned_string scrape_url; /* the name to use when deep logging is enabled */ char log_name[128]; @@ -87,7 +87,7 @@ struct tr_scrape_response struct tr_scrape_response_row rows[TR_MULTISCRAPE_MAX]; /* the raw scrape url */ - tr_quark scrape_url; + tr_interned_string scrape_url; /* human-readable error string on failure, or nullptr */ std::string errmsg; @@ -155,7 +155,7 @@ struct tr_announce_request uint64_t leftUntilComplete; /* the tracker's announce URL */ - tr_quark announce_url; + tr_interned_string announce_url; /* key generated by and returned from an http tracker. * see tr_announce_response.tracker_id_str */ @@ -215,10 +215,10 @@ struct tr_announce_response struct tr_pex* pex6; /* human-readable error string on failure, or nullptr */ - char* errmsg; + std::string errmsg; /* human-readable warning string or nullptr */ - char* warning; + std::string warning; /* key generated by and returned from an http tracker. * if this is provided, subsequent http announces must include this. */ @@ -241,20 +241,4 @@ void tr_tracker_udp_announce( void tr_tracker_udp_start_shutdown(tr_session* session); -tr_quark tr_announcerGetKey(tr_url_parsed_t const& parsed); - -inline tr_quark tr_announcerGetKey(std::string_view url) -{ - auto const parsed = tr_urlParseTracker(url); - if (!parsed) - { - return TR_KEY_NONE; - } - - return tr_announcerGetKey(*parsed); -} - -inline tr_quark tr_announcerGetKey(tr_quark url) -{ - return tr_announcerGetKey(tr_quark_get_string_view(url)); -} +tr_interned_string tr_announcerGetKey(tr_url_parsed_t const& parsed); diff --git a/libtransmission/announcer-http.cc b/libtransmission/announcer-http.cc index 9ea1f65c2..4fbdedf17 100644 --- a/libtransmission/announcer-http.cc +++ b/libtransmission/announcer-http.cc @@ -43,7 +43,7 @@ static char const* get_event_string(tr_announce_request const* req) static char* announce_url_new(tr_session const* session, tr_announce_request const* req) { - auto const announce_sv = tr_quark_get_string_view(req->announce_url); + auto const announce_sv = req->announce_url.sv(); char escaped_info_hash[SHA_DIGEST_LENGTH * 3 + 1]; tr_http_escape_sha1(escaped_info_hash, req->info_hash); @@ -190,8 +190,6 @@ static void on_announce_done_eventthread(void* vdata) tr_free(data->response.pex6); tr_free(data->response.pex); tr_free(data->response.tracker_id_str); - tr_free(data->response.warning); - tr_free(data->response.errmsg); tr_free(data); } @@ -251,12 +249,12 @@ static void on_announce_done( if (tr_variantDictFindStrView(&benc, TR_KEY_failure_reason, &sv)) { - response->errmsg = tr_strvDup(sv); + response->errmsg = sv; } if (tr_variantDictFindStrView(&benc, TR_KEY_warning_message, &sv)) { - response->warning = tr_strvDup(sv); + response->warning = sv; } if (tr_variantDictFindInt(&benc, TR_KEY_interval, &i)) @@ -377,7 +375,7 @@ static void on_scrape_done( response->did_connect = did_connect; response->did_timeout = did_timeout; - auto const scrape_url_sv = tr_quark_get_string_view(response->scrape_url); + auto const scrape_url_sv = response->scrape_url.sv(); dbgmsg(data->log_name, "Got scrape response for \"%" TR_PRIsv "\"", TR_PRIsv_ARG(scrape_url_sv)); if (response_code != HTTP_OK) @@ -485,12 +483,12 @@ static void on_scrape_done( static char* scrape_url_new(tr_scrape_request const* req) { - auto const sv = tr_quark_get_string_view(req->scrape_url); + auto const sv = req->scrape_url.sv(); auto* const buf = evbuffer_new(); evbuffer_add(buf, std::data(sv), std::size(sv)); - char delimiter = sv.find('?') == sv.npos ? '?' : '&'; + char delimiter = sv.find('?') == std::string_view::npos ? '?' : '&'; for (int i = 0; i < req->info_hash_count; ++i) { char str[SHA_DIGEST_LENGTH * 3 + 1]; diff --git a/libtransmission/announcer-udp.cc b/libtransmission/announcer-udp.cc index a81a31bee..7964cc8dd 100644 --- a/libtransmission/announcer-udp.cc +++ b/libtransmission/announcer-udp.cc @@ -30,7 +30,7 @@ #include "tr-udp.h" #include "utils.h" -#define dbgmsg(key, ...) tr_logAddDeepNamed(tr_quark_get_string(key), __VA_ARGS__) +#define dbgmsg(key, ...) tr_logAddDeepNamed(key.c_str(), __VA_ARGS__) using namespace std::literals; @@ -356,8 +356,6 @@ static struct tau_announce_request* tau_announce_request_new( static void tau_announce_request_free(struct tau_announce_request* req) { tr_free(req->response.tracker_id_str); - tr_free(req->response.warning); - tr_free(req->response.errmsg); tr_free(req->response.pex6); tr_free(req->response.pex); delete req; @@ -423,8 +421,8 @@ struct tau_tracker { tr_session* const session; - tr_quark const key; - tr_quark const host; + tr_interned_string const key; + tr_interned_string const host; int const port; struct evdns_getaddrinfo_request* dns_request = nullptr; @@ -441,7 +439,7 @@ struct tau_tracker tr_ptrArray announces = {}; tr_ptrArray scrapes = {}; - tau_tracker(tr_session* session_in, tr_quark key_in, tr_quark host_in, int port_in) + tau_tracker(tr_session* session_in, tr_interned_string key_in, tr_interned_string host_in, int port_in) : session{ session_in } , key{ key_in } , host{ host_in } @@ -687,7 +685,7 @@ static void tau_tracker_upkeep_ex(struct tau_tracker* tracker, bool timeout_reqs dbgmsg(tracker->host, "Trying a new DNS lookup"); tracker->dns_request = evdns_getaddrinfo( tracker->session->evdns_base, - tr_quark_get_string(tracker->host), + tracker->host.c_str(), nullptr, &hints, tau_tracker_on_dns, @@ -765,10 +763,10 @@ static struct tr_announcer_udp* announcer_udp_get(tr_session* session) /* Finds the tau_tracker struct that corresponds to this url. If it doesn't exist yet, create one. */ -static tau_tracker* tau_session_get_tracker(tr_announcer_udp* tau, tr_quark announce_url) +static tau_tracker* tau_session_get_tracker(tr_announcer_udp* tau, tr_interned_string announce_url) { // build a lookup key for this tracker - auto const announce_sv = tr_quark_get_string_view(announce_url); + auto const announce_sv = announce_url.sv(); auto parsed = tr_urlParseTracker(announce_sv); TR_ASSERT(parsed); if (!parsed) @@ -789,7 +787,7 @@ static tau_tracker* tau_session_get_tracker(tr_announcer_udp* tau, tr_quark anno } // we don't have it -- build a new one - auto* const tracker = new tau_tracker{ tau->session, key, tr_quark_new(parsed->host), parsed->port }; + auto* const tracker = new tau_tracker{ tau->session, key, tr_interned_string(parsed->host), parsed->port }; tr_ptrArrayAppend(&tau->trackers, tracker); dbgmsg(tracker->key, "New tau_tracker created"); return tracker; diff --git a/libtransmission/announcer.cc b/libtransmission/announcer.cc index 5291d265a..b261077e1 100644 --- a/libtransmission/announcer.cc +++ b/libtransmission/announcer.cc @@ -12,9 +12,9 @@ #include #include #include +#include #include #include -#include #include #include @@ -151,11 +151,11 @@ struct StopsCompare struct tr_scrape_info { - tr_quark const scrape_url; + tr_interned_string scrape_url; int multiscrape_max; - tr_scrape_info(tr_quark scrape_url_in, int const multiscrape_max_in) + tr_scrape_info(tr_interned_string scrape_url_in, int const multiscrape_max_in) : scrape_url{ scrape_url_in } , multiscrape_max{ multiscrape_max_in } { @@ -168,7 +168,7 @@ struct tr_scrape_info struct tr_announcer { std::set stops; - std::unordered_map scrape_info; + std::map scrape_info; tr_session* session; struct event* upkeepTimer; @@ -176,9 +176,9 @@ struct tr_announcer time_t tauUpkeepAt; }; -static tr_scrape_info* tr_announcerGetScrapeInfo(tr_announcer* announcer, tr_quark url) +static tr_scrape_info* tr_announcerGetScrapeInfo(tr_announcer* announcer, tr_interned_string url) { - if (url == TR_KEY_NONE) + if (std::empty(url)) { return nullptr; } @@ -227,8 +227,8 @@ void tr_announcerClose(tr_session* session) /* a row in tr_tier's list of trackers */ struct tr_tracker { - tr_quark key; - tr_quark announce_url; + tr_interned_string key; + tr_interned_string announce_url; struct tr_scrape_info* scrape_info; char* tracker_id_str; @@ -244,20 +244,19 @@ struct tr_tracker }; // format: `${host}:${port}` -tr_quark tr_announcerGetKey(tr_url_parsed_t const& parsed) +tr_interned_string tr_announcerGetKey(tr_url_parsed_t const& parsed) { std::string buf; tr_buildBuf(buf, parsed.host, ":"sv, parsed.portstr); - return tr_quark_new(buf); + return tr_interned_string{ buf }; } static void trackerConstruct(tr_announcer* announcer, tr_tracker* tracker, tr_announce_list::tracker_info const& info) { memset(tracker, 0, sizeof(tr_tracker)); tracker->key = info.host; - tracker->announce_url = info.announce_interned; - tracker->scrape_info = info.scrape_interned == TR_KEY_NONE ? nullptr : - tr_announcerGetScrapeInfo(announcer, info.scrape_interned); + tracker->announce_url = info.announce_str; + tracker->scrape_info = std::empty(info.scrape_str) ? nullptr : tr_announcerGetScrapeInfo(announcer, info.scrape_str); tracker->id = info.id; tracker->seederCount = -1; tracker->leecherCount = -1; @@ -369,9 +368,7 @@ static void tierDestruct(tr_tier* tier) static void tier_build_log_name(tr_tier const* tier, char* buf, size_t buflen) { auto const* const name = tier != nullptr && tier->tor != nullptr ? tr_torrentName(tier->tor) : "?"; - auto const key_sv = tier != nullptr && tier->currentTracker != nullptr ? - tr_quark_get_string_view(tier->currentTracker->key) : - "?"sv; + auto const key_sv = tier != nullptr && tier->currentTracker != nullptr ? tier->currentTracker->key.sv() : "?"sv; tr_snprintf(buf, buflen, "[%s---%" TR_PRIsv "]", name, TR_PRIsv_ARG(key_sv)); } @@ -470,7 +467,7 @@ static tr_tier* getTier(tr_announcer* announcer, tr_sha1_digest_t const& info_ha **** PUBLISH ***/ -static void publishMessage(tr_tier* tier, char const* msg, TrackerEventType type) +static void publishMessage(tr_tier* tier, std::string_view msg, TrackerEventType type) { if (tier != nullptr && tier->tor != nullptr && tier->tor->announcer_tiers != nullptr && tier->tor->announcer_tiers->callback != nullptr) @@ -491,15 +488,15 @@ static void publishMessage(tr_tier* tier, char const* msg, TrackerEventType type static void publishErrorClear(tr_tier* tier) { - publishMessage(tier, nullptr, TR_TRACKER_ERROR_CLEAR); + publishMessage(tier, ""sv, TR_TRACKER_ERROR_CLEAR); } -static void publishWarning(tr_tier* tier, char const* msg) +static void publishWarning(tr_tier* tier, std::string_view msg) { publishMessage(tier, msg, TR_TRACKER_WARNING); } -static void publishError(tr_tier* tier, char const* msg) +static void publishError(tr_tier* tier, std::string_view msg) { publishMessage(tier, msg, TR_TRACKER_ERROR); } @@ -913,7 +910,7 @@ static void on_announce_error(tr_tier* tier, char const* err, tr_announce_event /* schedule a reannounce */ int const interval = getRetryInterval(tier->currentTracker); - auto const* const key_cstr = tr_quark_get_string(tier->currentTracker->key); + auto const* const key_cstr = tier->currentTracker->key.c_str(); dbgmsg(tier, "Tracker '%s' announce error: %s (Retrying in %d seconds)", key_cstr, err, interval); tr_logAddTorInfo(tier->tor, "Tracker '%s' announce error: %s (Retrying in %d seconds)", key_cstr, err, interval); tier_announce_event_push(tier, e, tr_time() + interval); @@ -954,8 +951,8 @@ static void on_announce_done(tr_announce_response const* response, void* vdata) response->tracker_id_str != nullptr ? response->tracker_id_str : "none", response->pex_count, response->pex6_count, - response->errmsg != nullptr ? response->errmsg : "none", - response->warning != nullptr ? response->warning : "none"); + (!std::empty(response->errmsg) ? response->errmsg.c_str() : "none"), + (!std::empty(response->warning) ? response->warning.c_str() : "none")); tier->lastAnnounceTime = now; tier->lastAnnounceTimedOut = response->did_timeout; @@ -971,7 +968,7 @@ static void on_announce_done(tr_announce_response const* response, void* vdata) { on_announce_error(tier, _("Tracker did not respond"), event); } - else if (response->errmsg != nullptr) + else if (!std::empty(response->errmsg)) { /* If the torrent's only tracker returned an error, publish it. Don't bother publishing if there are other trackers -- it's @@ -982,7 +979,7 @@ static void on_announce_done(tr_announce_response const* response, void* vdata) publishError(tier, response->errmsg); } - on_announce_error(tier, response->errmsg, event); + on_announce_error(tier, response->errmsg.c_str(), event); } else { @@ -1023,12 +1020,12 @@ static void on_announce_done(tr_announce_response const* response, void* vdata) } } - char const* const str = response->warning; - if (str != nullptr) + auto const& warning = response->warning; + if (!std::empty(warning)) { - tr_strlcpy(tier->lastAnnounceStr, str, sizeof(tier->lastAnnounceStr)); - dbgmsg(tier, "tracker gave \"%s\"", str); - publishWarning(tier, str); + tr_strlcpy(tier->lastAnnounceStr, warning.c_str(), sizeof(tier->lastAnnounceStr)); + dbgmsg(tier, "tracker gave \"%s\"", warning.c_str()); + publishWarning(tier, warning); } else { @@ -1127,7 +1124,7 @@ static void announce_request_delegate( #endif - if (auto const announce_sv = tr_quark_get_string_view(request->announce_url); + if (auto const announce_sv = request->announce_url.sv(); tr_strvStartsWith(announce_sv, "http://"sv) || tr_strvStartsWith(announce_sv, "https://"sv)) { tr_tracker_http_announce(session, request, callback, callback_data); @@ -1211,14 +1208,14 @@ static void on_scrape_error(tr_session const* session, tr_tier* tier, char const /* schedule a rescrape */ int const interval = getRetryInterval(tier->currentTracker); - auto const* const key_cstr = tr_quark_get_string(tier->currentTracker->key); + auto const* const key_cstr = tier->currentTracker->key.c_str(); dbgmsg(tier, "Tracker '%s' scrape error: %s (Retrying in %zu seconds)", key_cstr, errmsg, (size_t)interval); tr_logAddTorInfo(tier->tor, "Tracker '%s' error: %s (Retrying in %zu seconds)", key_cstr, errmsg, (size_t)interval); tier->lastScrapeSucceeded = false; tier->scrapeAt = get_next_scrape_time(session, tier, interval); } -static tr_tier* find_tier(tr_torrent* tor, tr_quark scrape_url) +static tr_tier* find_tier(tr_torrent* tor, tr_interned_string scrape_url) { struct tr_announcer_tiers* tt = tor->announcer_tiers; @@ -1263,7 +1260,7 @@ static void checkMultiscrapeMax(tr_announcer* announcer, tr_scrape_response cons { // don't log the full URL, since that might have a personal announce id // (note: we know 'parsed' will be successful since this url has a scrape_info) - auto const parsed = *tr_urlParse(tr_quark_get_string_view(url)); + auto const parsed = *tr_urlParse(url.sv()); auto clean_url = std::string{}; tr_buildBuf(clean_url, parsed.scheme, "://"sv, parsed.host, ":"sv, parsed.portstr); tr_logAddNamedInfo(clean_url.c_str(), "Reducing multiscrape max to %d", n); @@ -1288,7 +1285,7 @@ static void on_scrape_done(tr_scrape_response const* response, void* vsession) if (tier != nullptr) { - auto const scrape_url_sv = tr_quark_get_string_view(response->scrape_url); + auto const scrape_url_sv = response->scrape_url.sv(); dbgmsg( tier, @@ -1378,7 +1375,7 @@ static void scrape_request_delegate( { tr_session* session = announcer->session; - auto const scrape_sv = tr_quark_get_string_view(request->scrape_url); + auto const scrape_sv = request->scrape_url.sv(); if (tr_strvStartsWith(scrape_sv, "http://"sv) || tr_strvStartsWith(scrape_sv, "https://"sv)) { @@ -1609,9 +1606,9 @@ static tr_tracker_view trackerView(tr_torrent const& tor, int tier_index, tr_tie auto const now = tr_time(); auto view = tr_tracker_view{}; - view.host = tr_quark_get_string(tracker.key); - view.announce = tr_quark_get_string(tracker.announce_url); - view.scrape = tracker.scrape_info == nullptr ? "" : tr_quark_get_string(tracker.scrape_info->scrape_url); + view.host = tracker.key.c_str(); + view.announce = tracker.announce_url.c_str(); + view.scrape = tracker.scrape_info == nullptr ? "" : tracker.scrape_info->scrape_url.c_str(); view.id = tracker.id; view.tier = tier_index; diff --git a/libtransmission/announcer.h b/libtransmission/announcer.h index f5bd5ff4f..2853a8e89 100644 --- a/libtransmission/announcer.h +++ b/libtransmission/announcer.h @@ -43,8 +43,8 @@ struct tr_tracker_event TrackerEventType messageType; /* for TR_TRACKER_WARNING and TR_TRACKER_ERROR */ - char const* text; - tr_quark announce_url; + std::string_view text; + tr_interned_string announce_url; /* for TR_TRACKER_PEERS */ struct tr_pex const* pex; diff --git a/libtransmission/foo b/libtransmission/foo new file mode 100644 index 000000000..9daeafb98 --- /dev/null +++ b/libtransmission/foo @@ -0,0 +1 @@ +test diff --git a/libtransmission/inout.cc b/libtransmission/inout.cc index b9d3033c5..cd453560c 100644 --- a/libtransmission/inout.cc +++ b/libtransmission/inout.cc @@ -26,6 +26,8 @@ #include "tr-assert.h" #include "utils.h" +using namespace std::literals; + /**** ***** Low-level IO functions ****/ @@ -227,8 +229,8 @@ static int readOrWritePiece( if (err != 0 && ioMode == TR_IO_WRITE && tor->error != TR_STAT_LOCAL_ERROR) { - auto const path = tr_strvPath(tor->downloadDir, file.name); - tr_torrentSetLocalError(tor, "%s (%s)", tr_strerror(err), path.c_str()); + auto const path = tr_strvPath(tor->downloadDir().sv(), file.name); + tor->setLocalError(tr_strvJoin(tr_strerror(err), " ("sv, path, ")"sv)); } } diff --git a/libtransmission/interned-string.h b/libtransmission/interned-string.h new file mode 100644 index 000000000..7f801eb48 --- /dev/null +++ b/libtransmission/interned-string.h @@ -0,0 +1,142 @@ +/* + * This file Copyright (C) Mnemosyne LLC + * + * It may be used under the GNU GPL versions 2 or 3 + * or any future license endorsed by Mnemosyne LLC. + */ + +#pragma once + +#include + +#include "transmission.h" + +#include "quark.h" + +/** + * Helper functions wrapped around tr_quark + */ +class tr_interned_string +{ +public: + tr_interned_string() = default; + + explicit tr_interned_string(tr_quark quark) + : quark_{ quark } + { + } + explicit tr_interned_string(std::string_view sv) + : tr_interned_string{ tr_quark_new(sv) } + { + } + explicit tr_interned_string(char const* c_str) + : tr_interned_string{ std::string_view{ c_str ? c_str : "" } } + { + } + + tr_interned_string& operator=(tr_quark quark) + { + quark_ = quark; + return *this; + } + tr_interned_string& operator=(std::string_view sv) + { + return *this = tr_quark_new(sv); + } + tr_interned_string& operator=(char const* c_str) + { + return *this = std::string_view{ c_str != nullptr ? c_str : "" }; + } + + [[nodiscard]] tr_quark quark() const + { + return quark_; + } + [[nodiscard]] char const* c_str() const + { + return tr_quark_get_string(quark_); + } + [[nodiscard]] std::string_view sv() const + { + return tr_quark_get_string_view(quark_); + } + + [[nodiscard]] auto data() const + { + return std::data(this->sv()); + } + [[nodiscard]] auto empty() const + { + return quark_ == TR_KEY_NONE; + } + [[nodiscard]] auto size() const + { + return std::size(this->sv()); + } + void clear() + { + *this = TR_KEY_NONE; + } + + [[nodiscard]] auto begin() const + { + return std::begin(this->sv()); + } + [[nodiscard]] auto end() const + { + return std::end(this->sv()); + } + + [[nodiscard]] auto rbegin() const + { + return std::rbegin(this->sv()); + } + [[nodiscard]] auto rend() const + { + return std::rend(this->sv()); + } + + [[nodiscard]] int compare(tr_interned_string const& that) const // <=> + { + return this->quark() - that.quark(); + } + + [[nodiscard]] bool operator<(tr_interned_string const& that) const + { + return this->compare(that) < 0; + } + + [[nodiscard]] bool operator>(tr_interned_string const& that) const + { + return this->compare(that) > 0; + } + + [[nodiscard]] bool operator==(tr_interned_string const& that) const + { + return this->compare(that) == 0; + } + [[nodiscard]] bool operator!=(tr_interned_string const& that) const + { + return this->compare(that) != 0; + } + + [[nodiscard]] bool operator==(std::string_view that) const + { + return this->sv() == that; + } + [[nodiscard]] bool operator!=(std::string_view that) const + { + return this->sv() != that; + } + [[nodiscard]] bool operator==(char const* that) const + { + return *this == std::string_view{ that != nullptr ? that : "" }; + } + [[nodiscard]] bool operator!=(char const* that) const + { + return *this != std::string_view{ that != nullptr ? that : "" }; + } + +private: + tr_quark quark_ = TR_KEY_NONE; +}; diff --git a/libtransmission/magnet-metainfo.cc b/libtransmission/magnet-metainfo.cc index df800c10b..0e3b99f35 100644 --- a/libtransmission/magnet-metainfo.cc +++ b/libtransmission/magnet-metainfo.cc @@ -208,7 +208,7 @@ void tr_magnet_metainfo::toVariant(tr_variant* top) const auto n = std::size(this->announce_list); if (n == 1) { - tr_variantDictAddQuark(top, TR_KEY_announce, this->announce_list.at(0).announce_interned); + tr_variantDictAddQuark(top, TR_KEY_announce, this->announce_list.at(0).announce_str.quark()); } else { @@ -224,7 +224,7 @@ void tr_magnet_metainfo::toVariant(tr_variant* top) const current_tier = tracker.tier; } - tr_variantListAddQuark(tracker_list, tracker.announce_interned); + tr_variantListAddQuark(tracker_list, tracker.announce_str.quark()); } } diff --git a/libtransmission/peer-common.h b/libtransmission/peer-common.h index 09be594d6..cdae9d6ef 100644 --- a/libtransmission/peer-common.h +++ b/libtransmission/peer-common.h @@ -105,7 +105,7 @@ public: /* the client name. For BitTorrent peers, this is the app name derived from the `v' string in LTEP's handshake dictionary */ - tr_quark client = TR_KEY_NONE; + tr_interned_string client; tr_recentHistory blocksSentToClient; tr_recentHistory blocksSentToPeer; diff --git a/libtransmission/peer-mgr.cc b/libtransmission/peer-mgr.cc index ca2032c75..1f993f088 100644 --- a/libtransmission/peer-mgr.cc +++ b/libtransmission/peer-mgr.cc @@ -1722,7 +1722,7 @@ static auto getPeerStats(tr_peerMsgs const* peer, time_t now, uint64_t now_msec) auto const* const atom = peer->atom; tr_address_to_string_with_buf(&atom->addr, stats.addr, sizeof(stats.addr)); - tr_strlcpy(stats.client, tr_quark_get_string(peer->client), sizeof(stats.client)); + stats.client = peer->client.c_str(); stats.port = ntohs(peer->atom->port); stats.from = atom->fromFirst; stats.progress = peer->progress; diff --git a/libtransmission/peer-msgs.cc b/libtransmission/peer-msgs.cc index 19f2b0504..ac22e079f 100644 --- a/libtransmission/peer-msgs.cc +++ b/libtransmission/peer-msgs.cc @@ -676,7 +676,7 @@ static void myDebug(char const* file, int line, tr_peerMsgsImpl const* msgs, cha tr_logGetTimeStr(timestr, sizeof(timestr)), tr_torrentName(msgs->torrent), tr_peerIoGetAddrStr(msgs->io, addrstr, sizeof(addrstr)), - tr_quark_get_string(msgs->client)); + msgs->client.c_str()); va_start(args, fmt); evbuffer_add_vprintf(buf, fmt, args); va_end(args); @@ -2231,10 +2231,11 @@ static size_t fillOutputBuffer(tr_peerMsgsImpl* msgs, time_t now) err = !msgs->torrent->ensurePieceIsChecked(req.index); if (err) { - tr_torrentSetLocalError( - msgs->torrent, - _("Please Verify Local Data! Piece #%zu is corrupt."), - (size_t)req.index); + auto const errmsg = tr_strvJoin( + "Please Verify Local Data! Piece #", + std::to_string(req.index), + " is corrupt."); + msgs->torrent->setLocalError(errmsg); } } diff --git a/libtransmission/quark.h b/libtransmission/quark.h index 17d7fdaee..8e4abff89 100644 --- a/libtransmission/quark.h +++ b/libtransmission/quark.h @@ -1,9 +1,8 @@ /* - * This file Copyright (C) 2013-2014 Mnemosyne LLC + * This file Copyright (C) Mnemosyne LLC * * It may be used under the GNU GPL versions 2 or 3 * or any future license endorsed by Mnemosyne LLC. - * */ #pragma once diff --git a/libtransmission/resume.cc b/libtransmission/resume.cc index 3172934db..b784c06b3 100644 --- a/libtransmission/resume.cc +++ b/libtransmission/resume.cc @@ -678,11 +678,11 @@ void tr_torrentSaveResume(tr_torrent* tor) tr_variantDictAddInt(&top, TR_KEY_added_date, tor->addedDate); tr_variantDictAddInt(&top, TR_KEY_corrupt, tor->corruptPrev + tor->corruptCur); tr_variantDictAddInt(&top, TR_KEY_done_date, tor->doneDate); - tr_variantDictAddStrView(&top, TR_KEY_destination, tor->downloadDir); + tr_variantDictAddQuark(&top, TR_KEY_destination, tor->downloadDir().quark()); - if (tor->incompleteDir != nullptr) + if (!std::empty(tor->incompleteDir())) { - tr_variantDictAddStr(&top, TR_KEY_incomplete_dir, tor->incompleteDir); + tr_variantDictAddQuark(&top, TR_KEY_incomplete_dir, tor->incompleteDir().quark()); } tr_variantDictAddInt(&top, TR_KEY_downloaded, tor->downloadedPrev + tor->downloadedCur); @@ -710,7 +710,7 @@ void tr_torrentSaveResume(tr_torrent* tor) int const err = tr_variantToFile(&top, TR_VARIANT_FMT_BENC, filename.c_str()); if (err != 0) { - tr_torrentSetLocalError(tor, "Unable to save resume file: %s", tr_strerror(err)); + tor->setLocalError(tr_strvJoin("Unable to save resume file: ", tr_strerror(err))); } tr_variantFree(&top); @@ -778,13 +778,11 @@ static uint64_t loadFromFile(tr_torrent* tor, uint64_t fieldsToLoad, bool* didRe if ((fieldsToLoad & (TR_FR_PROGRESS | TR_FR_DOWNLOAD_DIR)) != 0 && tr_variantDictFindStrView(&top, TR_KEY_destination, &sv) && !std::empty(sv)) { - bool const is_current_dir = tor->currentDir == tor->downloadDir; - tr_free(tor->downloadDir); - tor->downloadDir = tr_strvDup(sv); - + bool const is_current_dir = tor->current_dir == tor->download_dir; + tor->download_dir = sv; if (is_current_dir) { - tor->currentDir = tor->downloadDir; + tor->current_dir = sv; } fieldsLoaded |= TR_FR_DOWNLOAD_DIR; @@ -793,13 +791,11 @@ static uint64_t loadFromFile(tr_torrent* tor, uint64_t fieldsToLoad, bool* didRe if ((fieldsToLoad & (TR_FR_PROGRESS | TR_FR_INCOMPLETE_DIR)) != 0 && tr_variantDictFindStrView(&top, TR_KEY_incomplete_dir, &sv) && !std::empty(sv)) { - bool const is_current_dir = tor->currentDir == tor->incompleteDir; - tr_free(tor->incompleteDir); - tor->incompleteDir = tr_strvDup(sv); - + bool const is_current_dir = tor->current_dir == tor->incomplete_dir; + tor->incomplete_dir = sv; if (is_current_dir) { - tor->currentDir = tor->incompleteDir; + tor->current_dir = sv; } fieldsLoaded |= TR_FR_INCOMPLETE_DIR; @@ -953,8 +949,7 @@ static uint64_t setFromCtor(tr_torrent* tor, uint64_t fields, tr_ctor const* cto if (tr_ctorGetDownloadDir(ctor, mode, &path) && !tr_str_is_empty(path)) { ret |= TR_FR_DOWNLOAD_DIR; - tr_free(tor->downloadDir); - tor->downloadDir = tr_strdup(path); + tor->download_dir = path; } } diff --git a/libtransmission/rpcimpl.cc b/libtransmission/rpcimpl.cc index e3734048d..96a5836de 100644 --- a/libtransmission/rpcimpl.cc +++ b/libtransmission/rpcimpl.cc @@ -414,9 +414,9 @@ static void addTrackers(tr_torrent const* tor, tr_variant* trackers) for (auto const& tracker : tor->announceList()) { tr_variant* d = tr_variantListAddDict(trackers, 4); - tr_variantDictAddQuark(d, TR_KEY_announce, tracker.announce_interned); + tr_variantDictAddQuark(d, TR_KEY_announce, tracker.announce_str.quark()); tr_variantDictAddInt(d, TR_KEY_id, tracker.id); - tr_variantDictAddQuark(d, TR_KEY_scrape, tracker.scrape_interned); + tr_variantDictAddQuark(d, TR_KEY_scrape, tracker.scrape_str.quark()); tr_variantDictAddInt(d, TR_KEY_tier, tracker.tier); } } diff --git a/libtransmission/torrent-magnet.cc b/libtransmission/torrent-magnet.cc index ccbb3bc77..af5025066 100644 --- a/libtransmission/torrent-magnet.cc +++ b/libtransmission/torrent-magnet.cc @@ -299,7 +299,7 @@ void tr_torrentSetMetadataPiece(tr_torrent* tor, int piece, void const* data, in success = !!info; if (info && tr_block_info::bestBlockSize(info->info.pieceSize) == 0) { - tr_torrentSetLocalError(tor, "%s", _("Magnet torrent's metadata is not usable")); + tor->setLocalError(_("Magnet torrent's metadata is not usable")); success = false; } diff --git a/libtransmission/torrent.cc b/libtransmission/torrent.cc index a6d554387..38a101f90 100644 --- a/libtransmission/torrent.cc +++ b/libtransmission/torrent.cc @@ -12,7 +12,6 @@ #include /* INT_MAX */ #include #include /* signal() */ -#include #include /* qsort */ #include /* memcmp */ #include @@ -492,31 +491,11 @@ void tr_torrentCheckSeedLimit(tr_torrent* tor) **** ***/ -void tr_torrentSetLocalError(tr_torrent* tor, char const* fmt, ...) -{ - TR_ASSERT(tr_isTorrent(tor)); - - va_list ap; - - va_start(ap, fmt); - tor->error = TR_STAT_LOCAL_ERROR; - tor->error_announce_url = TR_KEY_NONE; - evutil_vsnprintf(tor->errorString, sizeof(tor->errorString), fmt, ap); - va_end(ap); - - tr_logAddTorErr(tor, "%s", tor->errorString); - - if (tor->isRunning) - { - tor->isStopping = true; - } -} - -static constexpr void tr_torrentClearError(tr_torrent* tor) +static void tr_torrentClearError(tr_torrent* tor) { tor->error = TR_STAT_OK; - tor->error_announce_url = TR_KEY_NONE; - tor->errorString[0] = '\0'; + tor->error_announce_url.clear(); + tor->error_string.clear(); } static void onTrackerResponse(tr_torrent* tor, tr_tracker_event const* event, void* /*user_data*/) @@ -537,16 +516,16 @@ static void onTrackerResponse(tr_torrent* tor, tr_tracker_event const* event, vo break; case TR_TRACKER_WARNING: - tr_logAddTorErr(tor, _("Tracker warning: \"%s\""), event->text); + tr_logAddTorErr(tor, _("Tracker warning: \"%" TR_PRIsv "\""), TR_PRIsv_ARG(event->text)); tor->error = TR_STAT_TRACKER_WARNING; tor->error_announce_url = event->announce_url; - tr_strlcpy(tor->errorString, event->text, sizeof(tor->errorString)); + tor->error_string = event->text; break; case TR_TRACKER_ERROR: tor->error = TR_STAT_TRACKER_ERROR; tor->error_announce_url = event->announce_url; - tr_strlcpy(tor->errorString, event->text, sizeof(tor->errorString)); + tor->error_string = event->text; break; case TR_TRACKER_ERROR_CLEAR: @@ -630,11 +609,8 @@ static bool setLocalErrorIfFilesDisappeared(tr_torrent* tor) if (disappeared) { tr_deeplog_tor(tor, "%s", "[LAZY] uh oh, the files disappeared"); - tr_torrentSetLocalError( - tor, - "%s", - _("No data found! Ensure your drives are connected or use \"Set Location\". " - "To re-download, remove the torrent and re-add it.")); + tor->setLocalError(_( + "No data found! Ensure your drives are connected or use \"Set Location\". To re-download, remove the torrent and re-add it.")); } return disappeared; @@ -671,7 +647,7 @@ static void torrentInit(tr_torrent* tor, tr_ctor const* ctor) char const* dir = nullptr; if (tr_ctorGetDownloadDir(ctor, TR_FORCE, &dir) || tr_ctorGetDownloadDir(ctor, TR_FALLBACK, &dir)) { - tor->downloadDir = tr_strdup(dir); + tor->download_dir = dir; } if (!tr_ctorGetIncompleteDir(ctor, &dir)) @@ -681,7 +657,7 @@ static void torrentInit(tr_torrent* tor, tr_ctor const* ctor) if (tr_sessionIsIncompleteDirEnabled(session)) { - tor->incompleteDir = tr_strdup(dir); + tor->incomplete_dir = dir; } tor->bandwidth = new Bandwidth(session->bandwidth); @@ -757,7 +733,8 @@ static void torrentInit(tr_torrent* tor, tr_ctor const* ctor) tr_error* error = nullptr; if (!tr_ctorSaveContents(ctor, tor->torrentFile(), &error)) { - tr_torrentSetLocalError(tor, "Unable to save torrent file: %s (%d)", error->message, error->code); + tor->setLocalError( + tr_strvJoin("Unable to save torrent file: ", error->message, " ("sv, std::to_string(error->code), ")"sv)); } tr_error_clear(&error); } @@ -860,11 +837,9 @@ void tr_torrentSetDownloadDir(tr_torrent* tor, char const* path) { TR_ASSERT(tr_isTorrent(tor)); - if (path == nullptr || tor->downloadDir == nullptr || strcmp(path, tor->downloadDir) != 0) + if (tor->download_dir != path) { - tr_free(tor->downloadDir); - tor->downloadDir = tr_strdup(path); - + tor->download_dir = path; tor->markEdited(); tor->setDirty(); } @@ -876,14 +851,14 @@ char const* tr_torrentGetDownloadDir(tr_torrent const* tor) { TR_ASSERT(tr_isTorrent(tor)); - return tor->downloadDir; + return tor->downloadDir().c_str(); } char const* tr_torrentGetCurrentDir(tr_torrent const* tor) { TR_ASSERT(tr_isTorrent(tor)); - return tor->currentDir; + return tor->currentDir().c_str(); } void tr_torrentChangeMyPort(tr_torrent* tor) @@ -1007,7 +982,7 @@ tr_stat const* tr_torrentStat(tr_torrent* tor) s->queuePosition = tor->queuePosition; s->idleSecs = torrentGetIdleSecs(tor, s->activity); s->isStalled = tr_torrentIsStalled(tor, s->idleSecs); - s->errorString = tor->errorString; + s->errorString = tor->error_string.c_str(); s->manualAnnounceTime = tr_announcerNextManualAnnounce(tor); s->peersConnected = swarm_stats.peerCount; @@ -1336,9 +1311,6 @@ static void freeTorrent(tr_torrent* tor) tr_announcerRemoveTorrent(session->announcer, tor); - tr_free(tor->downloadDir); - tr_free(tor->incompleteDir); - tr_sessionRemoveTorrent(session, tor); if (!session->isClosing()) @@ -1830,7 +1802,8 @@ static void torrentCallScript(tr_torrent const* tor, char const* script) tr_localtime_r(&now, &tm); strftime(ctime_str, sizeof(ctime_str), "%a %b %d %T %Y%n", &tm); /* ctime equiv */ - char* const torrent_dir = tr_sys_path_native_separators(tr_strdup(tor->currentDir)); + auto torrent_dir = std::string{ tor->currentDir().sv() }; + tr_sys_path_native_separators(std::data(torrent_dir)); auto const cmd = std::array{ script, @@ -1844,7 +1817,7 @@ static void torrentCallScript(tr_torrent const* tor, char const* script) auto const env = std::map{ { "TR_APP_VERSION"sv, SHORT_VERSION_STRING }, { "TR_TIME_LOCALTIME"sv, ctime_str }, - { "TR_TORRENT_DIR"sv, torrent_dir }, + { "TR_TORRENT_DIR"sv, torrent_dir.c_str() }, { "TR_TORRENT_HASH"sv, tor->hashString() }, { "TR_TORRENT_ID"sv, id_str }, { "TR_TORRENT_LABELS"sv, labels_str }, @@ -1861,8 +1834,6 @@ static void torrentCallScript(tr_torrent const* tor, char const* script) tr_logAddTorErr(tor, "Error executing script \"%s\" (%d): %s", script, error->code, error->message); tr_error_free(error); } - - tr_free(torrent_dir); } void tr_torrent::recheckCompleteness() @@ -1904,9 +1875,9 @@ void tr_torrent::recheckCompleteness() tr_peerMgrClearInterest(this); } - if (this->currentDir == this->incompleteDir) + if (this->currentDir() == this->incompleteDir()) { - this->setLocation(this->downloadDir, true, nullptr, nullptr); + this->setLocation(this->downloadDir().sv(), true, nullptr, nullptr); } } @@ -2153,7 +2124,7 @@ bool tr_torrentSetAnnounceList(tr_torrent* tor, char const* const* announce_urls if (std::any_of( std::begin(tor->announceList()), std::end(tor->announceList()), - [error_url](auto const& tracker) { return tracker.announce_interned == error_url; })) + [error_url](auto const& tracker) { return tracker.announce_str == error_url; })) { tr_torrentClearError(tor); } @@ -2276,7 +2247,7 @@ static void deleteLocalData(tr_torrent* tor, tr_fileFunc func) { auto files = std::vector{}; auto folders = std::set{}; - char const* const top = tor->currentDir; + char const* const top = tor->currentDir().c_str(); /* don't try to delete local data if the directory's gone missing */ if (!tr_sys_path_exists(top, nullptr)) @@ -2457,12 +2428,12 @@ static void setLocationImpl(void* vdata) tr_logAddDebug( "Moving \"%s\" location from currentDir \"%s\" to \"%s\"", tr_torrentName(tor), - tor->currentDir, + tor->currentDir().c_str(), location.c_str()); tr_sys_dir_create(location.c_str(), TR_SYS_DIR_CREATE_PARENTS, 0777, nullptr); - if (!tr_sys_path_is_same(location.c_str(), tor->currentDir, nullptr)) + if (!tr_sys_path_is_same(location.c_str(), tor->currentDir().c_str(), nullptr)) { /* bad idea to move files while they're being verified... */ tr_verifyRemove(tor); @@ -2526,9 +2497,8 @@ static void setLocationImpl(void* vdata) if (do_move) { - tr_free(tor->incompleteDir); - tor->incompleteDir = nullptr; - tor->currentDir = tor->downloadDir; + tor->incomplete_dir.clear(); + tor->current_dir = tor->downloadDir(); } } @@ -2710,9 +2680,9 @@ std::optional tr_torrent::findFile(std::string& fil tr_file const& file = this->file(i); auto file_info = tr_sys_path_info{}; - if (this->downloadDir != nullptr) + if (!std::empty(this->downloadDir())) { - auto base = std::string_view{ this->downloadDir }; + auto const base = this->downloadDir().sv(); tr_buildBuf(filename, base, "/"sv, file.name); if (tr_sys_path_get_info(filename.c_str(), 0, &file_info, nullptr)) @@ -2727,9 +2697,9 @@ std::optional tr_torrent::findFile(std::string& fil } } - if (this->incompleteDir != nullptr) + if (!std::empty(this->incompleteDir())) { - auto const base = std::string_view{ this->incompleteDir }; + auto const base = this->incompleteDir().sv(); tr_buildBuf(filename, base, "/"sv, file.name); if (tr_sys_path_get_info(filename.c_str(), 0, &file_info, nullptr)) @@ -2787,25 +2757,27 @@ char* tr_torrentFindFile(tr_torrent const* tor, tr_file_index_t fileNum) /* Decide whether we should be looking for files in downloadDir or incompleteDir. */ static void refreshCurrentDir(tr_torrent* tor) { - char const* dir = nullptr; + tr_interned_string dir; - if (tor->incompleteDir == nullptr) + if (std::empty(tor->incompleteDir())) { - dir = tor->downloadDir; + dir = tor->downloadDir(); } else if (!tor->hasMetadata()) /* no files to find */ { - dir = tor->incompleteDir; + dir = tor->incompleteDir(); } - else if (!tr_torrentFindFile2(tor, 0, &dir, nullptr, nullptr)) + else { - dir = tor->incompleteDir; + auto filename = std::string{}; + auto const found = tor->findFile(filename, 0); + dir = found ? tr_interned_string{ found->base } : tor->incompleteDir(); } - TR_ASSERT(dir != nullptr); - TR_ASSERT(dir == tor->downloadDir || dir == tor->incompleteDir); + TR_ASSERT(!std::empty(dir)); + TR_ASSERT(dir == tor->downloadDir() || dir == tor->incompleteDir()); - tor->currentDir = dir; + tor->current_dir = dir; } char* tr_torrentBuildPartial(tr_torrent const* tor, tr_file_index_t i) @@ -3001,7 +2973,7 @@ static int renamePath(tr_torrent* tor, char const* oldpath, char const* newname) { int err = 0; - char const* const base = !tor->isDone() && tor->incompleteDir != nullptr ? tor->incompleteDir : tor->downloadDir; + auto const base = tor->isDone() || std::empty(tor->incompleteDir()) ? tor->downloadDir().sv() : tor->incompleteDir().sv(); auto src = tr_strvPath(base, oldpath); diff --git a/libtransmission/torrent.h b/libtransmission/torrent.h index 242652f1d..bd66d819e 100644 --- a/libtransmission/torrent.h +++ b/libtransmission/torrent.h @@ -29,6 +29,7 @@ #include "completion.h" #include "file.h" #include "file-piece-map.h" +#include "interned-string.h" #include "quark.h" #include "session.h" #include "tr-assert.h" @@ -94,8 +95,6 @@ void tr_torrentCheckSeedLimit(tr_torrent* tor); /** save a torrent's .resume file if it's changed since the last time it was saved */ void tr_torrentSave(tr_torrent* tor); -void tr_torrentSetLocalError(tr_torrent* tor, char const* fmt, ...) TR_GNUC_PRINTF(2, 3); - enum tr_verify_state { TR_VERIFY_NONE, @@ -286,6 +285,23 @@ public: setDirty(); } + /// LOCATION + + [[nodiscard]] tr_interned_string currentDir() const + { + return this->current_dir; + } + + [[nodiscard]] tr_interned_string downloadDir() const + { + return this->download_dir; + } + + [[nodiscard]] tr_interned_string incompleteDir() const + { + return this->incomplete_dir; + } + /// METAINFO - FILES [[nodiscard]] tr_file_index_t fileCount() const @@ -504,6 +520,13 @@ public: return this->isPieceTransferAllowed(TR_CLIENT_TO_PEER); } + void setLocalError(std::string_view errmsg) + { + this->error = TR_STAT_LOCAL_ERROR; + this->error_announce_url = TR_KEY_NONE; + this->error_string = errmsg; + } + void setVerifyState(tr_verify_state state); void setDateActive(time_t t); @@ -535,8 +558,8 @@ public: std::optional verify_progress; tr_stat_errtype error = TR_STAT_OK; - char errorString[128] = {}; - tr_quark error_announce_url = TR_KEY_NONE; + tr_interned_string error_announce_url; + std::string error_string; bool checkPiece(tr_piece_index_t piece); @@ -558,15 +581,16 @@ public: time_t peer_id_creation_time = 0; - /* Where the files will be when it's complete */ - char* downloadDir = nullptr; + // Where the files are when the torrent is complete. + tr_interned_string download_dir; - /* Where the files are when the torrent is incomplete */ - char* incompleteDir = nullptr; + // Where the files are when the torrent is incomplete. + // a value of TR_KEY_NONE indicates the 'incomplete_dir' feature is unused + tr_interned_string incomplete_dir; - /* Where the files are now. - * This pointer will be equal to downloadDir or incompleteDir */ - char const* currentDir = nullptr; + // Where the files are now. + // Will equal either download_dir or incomplete_dir + tr_interned_string current_dir; /* Length, in bytes, of the "info" dict in the .torrent file. */ uint64_t infoDictLength = 0; diff --git a/libtransmission/transmission.h b/libtransmission/transmission.h index c6f40417f..513a3c753 100644 --- a/libtransmission/transmission.h +++ b/libtransmission/transmission.h @@ -1343,8 +1343,8 @@ struct tr_peer_stat tr_port port; char addr[TR_INET6_ADDRSTRLEN]; - char client[80]; char flagStr[32]; + char const* client; float progress; double rateToPeer_KBps; diff --git a/macosx/QuickLookPlugin/GeneratePreviewForURL.mm b/macosx/QuickLookPlugin/GeneratePreviewForURL.mm index 2cfd89c4c..09c1b1a93 100644 --- a/macosx/QuickLookPlugin/GeneratePreviewForURL.mm +++ b/macosx/QuickLookPlugin/GeneratePreviewForURL.mm @@ -171,7 +171,7 @@ OSStatus GeneratePreviewForURL(void* thisInterface, QLPreviewRequestRef preview, #warning handle tiers? for (auto const tracker : *inf.announce_list) { - [listSection appendFormat:@"%s", tr_quark_get_string(tracker.announce_interned)]; + [listSection appendFormat:@"%s", tracker.announce_str.c_str()]; } [listSection appendString:@""]; diff --git a/tests/libtransmission/announce-list-test.cc b/tests/libtransmission/announce-list-test.cc index 803522efb..8aee12f68 100644 --- a/tests/libtransmission/announce-list-test.cc +++ b/tests/libtransmission/announce-list-test.cc @@ -36,7 +36,7 @@ TEST_F(AnnounceListTest, canAdd) EXPECT_EQ(Announce, tracker.announce.full); EXPECT_EQ("https://example.org/scrape"sv, tracker.scrape.full); EXPECT_EQ(Tier, tracker.tier); - EXPECT_EQ("example.org:443"sv, tr_quark_get_string_view(tracker.host)); + EXPECT_EQ("example.org:443"sv, tracker.host.sv()); } TEST_F(AnnounceListTest, groupsSiblingsIntoSameTier) @@ -60,9 +60,9 @@ TEST_F(AnnounceListTest, groupsSiblingsIntoSameTier) EXPECT_EQ(Announce1, announce_list.at(1).announce.full); EXPECT_EQ(Announce2, announce_list.at(0).announce.full); EXPECT_EQ(Announce3, announce_list.at(2).announce.full); - EXPECT_EQ("example.org:443"sv, tr_quark_get_string_view(announce_list.at(1).host)); - EXPECT_EQ("example.org:80"sv, tr_quark_get_string_view(announce_list.at(0).host)); - EXPECT_EQ("example.org:999"sv, tr_quark_get_string_view(announce_list.at(2).host)); + EXPECT_EQ("example.org:443"sv, announce_list.at(1).host.sv()); + EXPECT_EQ("example.org:80"sv, announce_list.at(0).host.sv()); + EXPECT_EQ("example.org:999"sv, announce_list.at(2).host.sv()); } TEST_F(AnnounceListTest, canAddWithoutScrape) @@ -74,7 +74,7 @@ TEST_F(AnnounceListTest, canAddWithoutScrape) EXPECT_TRUE(announce_list.add(Tier, Announce)); auto const tracker = announce_list.at(0); EXPECT_EQ(Announce, tracker.announce.full); - EXPECT_EQ(TR_KEY_NONE, tracker.scrape_interned); + EXPECT_TRUE(std::empty(tracker.scrape_str)); EXPECT_EQ(Tier, tracker.tier); } diff --git a/tests/libtransmission/rename-test.cc b/tests/libtransmission/rename-test.cc index 1b8118f86..b7076a4ed 100644 --- a/tests/libtransmission/rename-test.cc +++ b/tests/libtransmission/rename-test.cc @@ -43,13 +43,13 @@ protected: EXPECT_TRUE(waitFor(test, MaxWaitMsec)); } - void createSingleFileTorrentContents(char const* top) + void createSingleFileTorrentContents(std::string_view top) { auto const path = tr_strvPath(top, "hello-world.txt"); createFileWithContents(path, "hello, world!\n"); } - void createMultifileTorrentContents(char const* top) + void createMultifileTorrentContents(std::string_view top) { auto path = tr_strvPath(top, "Felidae", "Felinae", "Acinonyx", "Cheetah", "Chester"); createFileWithContents(path, "It ain't easy bein' cheesy.\n"); @@ -163,7 +163,7 @@ TEST_F(RenameTest, singleFilenameTorrent) blockingTorrentVerify(tor); expectHaveNone(tor, TotalSize); - createSingleFileTorrentContents(tor->currentDir); + createSingleFileTorrentContents(tor->currentDir().sv()); // sanity check the stats again, now that we've added the file blockingTorrentVerify(tor); @@ -197,7 +197,7 @@ TEST_F(RenameTest, singleFilenameTorrent) **** Now try a rename that should succeed ***/ - auto tmpstr = tr_strvPath(tor->currentDir, "hello-world.txt"); + auto tmpstr = tr_strvPath(tor->currentDir().sv(), "hello-world.txt"); EXPECT_TRUE(tr_sys_path_exists(tmpstr.c_str(), nullptr)); EXPECT_STREQ("hello-world.txt", tr_torrentName(tor)); EXPECT_EQ(0, torrentRenameAndWait(tor, tr_torrentName(tor), "foobar")); @@ -206,7 +206,7 @@ TEST_F(RenameTest, singleFilenameTorrent) EXPECT_STREQ("foobar", tr_torrentName(tor)); // confirm the torrent's name is now 'foobar' EXPECT_STREQ("foobar", files[0].name); // confirm the file's name is now 'foobar' in our struct EXPECT_STREQ(nullptr, strstr(tr_torrentView(tor).torrent_filename, "foobar")); // confirm .torrent file hasn't changed - tmpstr = tr_strvPath(tor->currentDir, "foobar"); + tmpstr = tr_strvPath(tor->currentDir().sv(), "foobar"); EXPECT_TRUE(tr_sys_path_exists(tmpstr.c_str(), nullptr)); // confirm the file's name is now 'foobar' on the disk EXPECT_TRUE(testFileExistsAndConsistsOfThisString(tor, 0, "hello, world!\n")); // confirm the contents are right @@ -221,7 +221,7 @@ TEST_F(RenameTest, singleFilenameTorrent) **** ...and rename it back again ***/ - tmpstr = tr_strvPath(tor->currentDir, "foobar"); + tmpstr = tr_strvPath(tor->currentDir().sv(), "foobar"); 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)); @@ -287,7 +287,7 @@ TEST_F(RenameTest, multifileTorrent) expectHaveNone(tor, TotalSize); // build the local data - createMultifileTorrentContents(tor->currentDir); + createMultifileTorrentContents(tor->currentDir().sv()); // sanity check the (full) stats blockingTorrentVerify(tor); @@ -523,7 +523,7 @@ TEST_F(RenameTest, partialFile) for (tr_file_index_t i = 0; i < 3; ++i) { - auto const expected = tr_strvPath(tor->currentDir, strings[i]); + auto const expected = tr_strvPath(tor->currentDir().sv(), strings[i]); char* path = tr_torrentFindFile(tor, i); EXPECT_EQ(expected, path); tr_free(path); diff --git a/tests/libtransmission/test-fixtures.h b/tests/libtransmission/test-fixtures.h index cc050ea8b..570f3fbd8 100644 --- a/tests/libtransmission/test-fixtures.h +++ b/tests/libtransmission/test-fixtures.h @@ -399,8 +399,8 @@ protected: { auto const file = tr_torrentFile(tor, i); - auto path = (!complete && i == 0) ? tr_strvJoin(tor->currentDir, TR_PATH_DELIMITER_STR, file.name, ".part") : - tr_strvJoin(tor->currentDir, TR_PATH_DELIMITER_STR, file.name); + auto path = (!complete && i == 0) ? tr_strvJoin(tor->currentDir().sv(), TR_PATH_DELIMITER_STR, file.name, ".part") : + tr_strvJoin(tor->currentDir().sv(), TR_PATH_DELIMITER_STR, file.name); auto const dirname = makeString(tr_sys_path_dirname(path.c_str(), nullptr)); tr_sys_dir_create(dirname.data(), TR_SYS_DIR_CREATE_PARENTS, 0700, nullptr); diff --git a/utils/show.cc b/utils/show.cc index be02f0649..ae0a1e09a 100644 --- a/utils/show.cc +++ b/utils/show.cc @@ -218,7 +218,7 @@ static void doScrape(tr_info const* inf) { for (auto const& tracker : *inf->announce_list) { - if (tracker.scrape_interned == TR_KEY_NONE) + if (std::empty(tracker.scrape_str)) { continue; }