Go back to using hash as base name for resume and torrent files

The format introduced in TRAC-394 is nice but brings its own issues (e.g.
TRAC-4189, #122). I'm okay with a bit of grepping myself if it makes the
experience better for end users.

Using hashes results in filenames well under 255 bytes limit on some
filesystems. If even that will not be enough, I'd suggest reporting the
issue elsewhere.

Fixes: #122
This commit is contained in:
Mike Gelfand 2017-07-26 21:20:30 +03:00
parent 760c98f8a2
commit bb4741002f
6 changed files with 111 additions and 21 deletions

View File

@ -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);
}

View File

@ -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);

View File

@ -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");

View File

@ -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);
}

View File

@ -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);

View File

@ -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);