diff --git a/libtransmission/metainfo.c b/libtransmission/metainfo.c index 51b065947..180cf76bb 100644 --- a/libtransmission/metainfo.c +++ b/libtransmission/metainfo.c @@ -36,7 +36,7 @@ static inline bool char_is_path_separator(char c) return strchr(PATH_DELIMITER_CHARS, c) != NULL; } -char* tr_metainfoGetBasename(tr_info const* inf) +static char* metainfoGetBasenameNameAndPartialHash(tr_info const* inf) { char const* name = inf->originalName; size_t const name_len = strlen(name); @@ -53,9 +53,30 @@ char* tr_metainfoGetBasename(tr_info const* inf) return ret; } -static char* getTorrentFilename(tr_session const* session, tr_info const* inf) +static char* metainfoGetBasenameHashOnly(tr_info const* inf) { - char* base = tr_metainfoGetBasename(inf); + return tr_strdup(inf->hashString); +} + +char* tr_metainfoGetBasename(tr_info const* inf, enum tr_metainfo_basename_format format) +{ + switch (format) + { + case TR_METAINFO_BASENAME_NAME_AND_PARTIAL_HASH: + return metainfoGetBasenameNameAndPartialHash(inf); + + case TR_METAINFO_BASENAME_HASH: + return metainfoGetBasenameHashOnly(inf); + + default: + TR_ASSERT_MSG(false, "unknown metainfo basename format %d", (int)format); + return NULL; + } +} + +static char* getTorrentFilename(tr_session const* session, tr_info const* inf, enum tr_metainfo_basename_format format) +{ + char* base = tr_metainfoGetBasename(inf, format); char* filename = tr_strdup_printf("%s" TR_PATH_DELIMITER_STR "%s.torrent", tr_getTorrentDir(session), base); tr_free(base); return filename; @@ -632,7 +653,7 @@ static char const* tr_metainfoParseImpl(tr_session const* session, tr_info* inf, /* filename of Transmission's copy */ tr_free(inf->torrent); - inf->torrent = session != NULL ? getTorrentFilename(session, inf) : NULL; + inf->torrent = session != NULL ? getTorrentFilename(session, inf, TR_METAINFO_BASENAME_HASH) : NULL; return NULL; } @@ -688,7 +709,26 @@ void tr_metainfoRemoveSaved(tr_session const* session, tr_info const* inf) { char* filename; - filename = getTorrentFilename(session, inf); + filename = getTorrentFilename(session, inf, TR_METAINFO_BASENAME_HASH); + tr_sys_path_remove(filename, NULL); + tr_free(filename); + + filename = getTorrentFilename(session, inf, TR_METAINFO_BASENAME_NAME_AND_PARTIAL_HASH); tr_sys_path_remove(filename, NULL); tr_free(filename); } + +void tr_metainfoMigrateFile(tr_session const* session, tr_info const* info, enum tr_metainfo_basename_format old_format, + enum tr_metainfo_basename_format new_format) +{ + char* old_filename = getTorrentFilename(session, info, old_format); + char* new_filename = getTorrentFilename(session, info, new_format); + + if (tr_sys_path_rename(old_filename, new_filename, NULL)) + { + tr_logAddNamedError(info->name, "Migrated torrent file from \"%s\" to \"%s\"", old_filename, new_filename); + } + + tr_free(new_filename); + tr_free(old_filename); +} diff --git a/libtransmission/metainfo.h b/libtransmission/metainfo.h index e192b7a5a..375453704 100644 --- a/libtransmission/metainfo.h +++ b/libtransmission/metainfo.h @@ -15,9 +15,18 @@ #include "transmission.h" #include "variant.h" +enum tr_metainfo_basename_format +{ + TR_METAINFO_BASENAME_NAME_AND_PARTIAL_HASH, + TR_METAINFO_BASENAME_HASH +}; + bool tr_metainfoParse(tr_session const* session, tr_variant const* variant, tr_info* setmeInfo, bool* setmeHasInfoDict, size_t* setmeInfoDictLength); void tr_metainfoRemoveSaved(tr_session const* session, tr_info const* info); -char* tr_metainfoGetBasename(tr_info const*); +char* tr_metainfoGetBasename(tr_info const*, enum tr_metainfo_basename_format format); + +void tr_metainfoMigrateFile(tr_session const* session, tr_info const* info, enum tr_metainfo_basename_format old_format, + enum tr_metainfo_basename_format new_format); diff --git a/libtransmission/rename-test.c b/libtransmission/rename-test.c index 44dd98e50..5b21a807d 100644 --- a/libtransmission/rename-test.c +++ b/libtransmission/rename-test.c @@ -207,7 +207,7 @@ static int test_single_filename_torrent(void) /* (while it's renamed: confirm that the .resume file remembers the changes) */ tr_torrentSaveResume(tor); libttest_sync(); - loaded = tr_torrentLoadResume(tor, ~0, ctor); + loaded = tr_torrentLoadResume(tor, ~0, ctor, NULL); check_str(tr_torrentName(tor), ==, "foobar"); check_uint((loaded & TR_FR_NAME), !=, 0); @@ -359,7 +359,7 @@ static int test_multifile_torrent(void) /* 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"); - loaded = tr_torrentLoadResume(tor, ~0, ctor); + loaded = tr_torrentLoadResume(tor, ~0, ctor, NULL); check_uint((loaded & TR_FR_FILENAMES), !=, 0); check_str(files[0].name, ==, expected_files[0]); check_str(files[1].name, ==, "Felidae/Felinae/Felis/placeholder/Kyphi"); diff --git a/libtransmission/resume.c b/libtransmission/resume.c index 82b1f8f07..1189c8d82 100644 --- a/libtransmission/resume.c +++ b/libtransmission/resume.c @@ -28,9 +28,9 @@ enum MAX_REMEMBERED_PEERS = 200 }; -static char* getResumeFilename(tr_torrent const* tor) +static char* getResumeFilename(tr_torrent const* tor, enum tr_metainfo_basename_format format) { - char* base = tr_metainfoGetBasename(tr_torrentInfo(tor)); + char* base = tr_metainfoGetBasename(tr_torrentInfo(tor), format); char* filename = tr_strdup_printf("%s" TR_PATH_DELIMITER_STR "%s.resume", tr_getResumeDir(tor->session), base); tr_free(base); return filename; @@ -736,7 +736,7 @@ void tr_torrentSaveResume(tr_torrent* tor) saveFilenames(&top, tor); saveName(&top, tor); - filename = getResumeFilename(tor); + filename = getResumeFilename(tor, TR_METAINFO_BASENAME_HASH); if ((err = tr_variantToFile(&top, TR_VARIANT_FMT_BENC, filename)) != 0) { @@ -748,7 +748,7 @@ void tr_torrentSaveResume(tr_torrent* tor) tr_variantFree(&top); } -static uint64_t loadFromFile(tr_torrent* tor, uint64_t fieldsToLoad) +static uint64_t loadFromFile(tr_torrent* tor, uint64_t fieldsToLoad, bool* didRenameToHashOnlyName) { TR_ASSERT(tr_isTorrent(tor)); @@ -762,15 +762,41 @@ static uint64_t loadFromFile(tr_torrent* tor, uint64_t fieldsToLoad) bool const wasDirty = tor->isDirty; tr_error* error = NULL; - filename = getResumeFilename(tor); + if (didRenameToHashOnlyName != NULL) + { + *didRenameToHashOnlyName = false; + } + + filename = getResumeFilename(tor, TR_METAINFO_BASENAME_HASH); if (!tr_variantFromFile(&top, TR_VARIANT_FMT_BENC, filename, &error)) { tr_logAddTorDbg(tor, "Couldn't read \"%s\": %s", filename, error->message); - tr_error_free(error); + tr_error_clear(&error); - tr_free(filename); - return fieldsLoaded; + char* old_filename = getResumeFilename(tor, TR_METAINFO_BASENAME_NAME_AND_PARTIAL_HASH); + + if (!tr_variantFromFile(&top, TR_VARIANT_FMT_BENC, old_filename, &error)) + { + tr_logAddTorDbg(tor, "Couldn't read \"%s\" either: %s", old_filename, error->message); + tr_error_free(error); + + tr_free(old_filename); + tr_free(filename); + return fieldsLoaded; + } + + if (tr_sys_path_rename(old_filename, filename, NULL)) + { + tr_logAddTorDbg(tor, "Migrated resume file from \"%s\" to \"%s\"", old_filename, filename); + + if (didRenameToHashOnlyName != NULL) + { + *didRenameToHashOnlyName = true; + } + } + + tr_free(old_filename); } tr_logAddTorDbg(tor, "Read resume file \"%s\"", filename); @@ -975,7 +1001,7 @@ static uint64_t useFallbackFields(tr_torrent* tor, uint64_t fields, tr_ctor cons return setFromCtor(tor, fields, ctor, TR_FALLBACK); } -uint64_t tr_torrentLoadResume(tr_torrent* tor, uint64_t fieldsToLoad, tr_ctor const* ctor) +uint64_t tr_torrentLoadResume(tr_torrent* tor, uint64_t fieldsToLoad, tr_ctor const* ctor, bool* didRenameToHashOnlyName) { TR_ASSERT(tr_isTorrent(tor)); @@ -983,7 +1009,7 @@ uint64_t tr_torrentLoadResume(tr_torrent* tor, uint64_t fieldsToLoad, tr_ctor co ret |= useManditoryFields(tor, fieldsToLoad, ctor); fieldsToLoad &= ~ret; - ret |= loadFromFile(tor, fieldsToLoad); + ret |= loadFromFile(tor, fieldsToLoad, didRenameToHashOnlyName); fieldsToLoad &= ~ret; ret |= useFallbackFields(tor, fieldsToLoad, ctor); @@ -992,7 +1018,13 @@ uint64_t tr_torrentLoadResume(tr_torrent* tor, uint64_t fieldsToLoad, tr_ctor co void tr_torrentRemoveResume(tr_torrent const* tor) { - char* filename = getResumeFilename(tor); + char* filename; + + filename = getResumeFilename(tor, TR_METAINFO_BASENAME_HASH); + tr_sys_path_remove(filename, NULL); + tr_free(filename); + + filename = getResumeFilename(tor, TR_METAINFO_BASENAME_NAME_AND_PARTIAL_HASH); tr_sys_path_remove(filename, NULL); tr_free(filename); } diff --git a/libtransmission/resume.h b/libtransmission/resume.h index 513c1b5f7..64e97736c 100644 --- a/libtransmission/resume.h +++ b/libtransmission/resume.h @@ -41,7 +41,7 @@ enum /** * Returns a bitwise-or'ed set of the loaded resume data */ -uint64_t tr_torrentLoadResume(tr_torrent* tor, uint64_t fieldsToLoad, tr_ctor const* ctor); +uint64_t tr_torrentLoadResume(tr_torrent* tor, uint64_t fieldsToLoad, tr_ctor const* ctor, bool* didRenameToHashOnlyName); void tr_torrentSaveResume(tr_torrent* tor); diff --git a/libtransmission/torrent.c b/libtransmission/torrent.c index 4f7e75cbe..ee0631a2f 100644 --- a/libtransmission/torrent.c +++ b/libtransmission/torrent.c @@ -968,7 +968,16 @@ static void torrentInit(tr_torrent* tor, tr_ctor const* ctor) tr_torrentSetAddedDate(tor, tr_time()); /* this is a default value to be overwritten by the resume file */ torrentInitFromInfo(tor); - loaded = tr_torrentLoadResume(tor, ~0, ctor); + + bool didRenameResumeFileToHashOnlyName = false; + loaded = tr_torrentLoadResume(tor, ~0, ctor, &didRenameResumeFileToHashOnlyName); + + if (didRenameResumeFileToHashOnlyName) + { + /* Rename torrent file as well */ + tr_metainfoMigrateFile(session, &tor->info, TR_METAINFO_BASENAME_NAME_AND_PARTIAL_HASH, TR_METAINFO_BASENAME_HASH); + } + tor->completeness = tr_cpGetStatus(&tor->completion); setLocalErrorIfFilesDisappeared(tor);