mirror of
https://github.com/transmission/transmission
synced 2024-12-24 08:43:27 +00:00
(libT) #1220 'change top folder names' -- when the root file/folder is changed, update tr_info.name too.
This commit is contained in:
parent
9236571f1c
commit
434bd6b287
8 changed files with 150 additions and 13 deletions
|
@ -36,8 +36,9 @@ char*
|
|||
tr_metainfoGetBasename (const tr_info * inf)
|
||||
{
|
||||
size_t i;
|
||||
const size_t name_len = strlen (inf->name);
|
||||
char * ret = tr_strdup_printf ("%s.%16.16s", inf->name, inf->hashString);
|
||||
const char * name = inf->originalName;
|
||||
const size_t name_len = strlen (name);
|
||||
char * ret = tr_strdup_printf ("%s.%16.16s", name, inf->hashString);
|
||||
|
||||
for (i=0; i<name_len; ++i)
|
||||
if (ret[i] == '/')
|
||||
|
@ -405,11 +406,15 @@ tr_metainfoParseImpl (const tr_session * session,
|
|||
if (tr_variantDictFindStr (d, TR_KEY_display_name, &str, &len))
|
||||
{
|
||||
tr_free (inf->name);
|
||||
tr_free (inf->originalName);
|
||||
inf->name = tr_strndup (str, len);
|
||||
inf->originalName = tr_strndup (str, len);
|
||||
}
|
||||
|
||||
if (!inf->name)
|
||||
inf->name = tr_strdup (inf->hashString);
|
||||
inf->name = tr_strdup (inf->hashString);
|
||||
if (!inf->originalName)
|
||||
inf->originalName = tr_strdup (inf->hashString);
|
||||
}
|
||||
else /* not a magnet link and has no info dict... */
|
||||
{
|
||||
|
@ -439,7 +444,9 @@ tr_metainfoParseImpl (const tr_session * session,
|
|||
if (!str || !*str)
|
||||
return "name";
|
||||
tr_free (inf->name);
|
||||
tr_free (inf->originalName);
|
||||
inf->name = tr_utf8clean (str, len);
|
||||
inf->originalName = tr_strdup (inf->name);
|
||||
}
|
||||
|
||||
/* comment */
|
||||
|
@ -560,6 +567,7 @@ tr_metainfoFree (tr_info * inf)
|
|||
tr_free (inf->comment);
|
||||
tr_free (inf->creator);
|
||||
tr_free (inf->torrent);
|
||||
tr_free (inf->originalName);
|
||||
tr_free (inf->name);
|
||||
|
||||
for (i=0; i<inf->trackerCount; i++)
|
||||
|
|
|
@ -154,6 +154,7 @@ create_torrent_from_base64_metainfo (tr_ctor * ctor, const char * metainfo_base6
|
|||
static int
|
||||
test_single_filename_torrent (void)
|
||||
{
|
||||
uint64_t loaded;
|
||||
tr_torrent * tor;
|
||||
char * tmpstr;
|
||||
const size_t totalSize = 14;
|
||||
|
@ -207,12 +208,22 @@ test_single_filename_torrent (void)
|
|||
|
||||
tmpstr = tr_buildPath (tor->downloadDir, "hello-world.txt", NULL);
|
||||
check (tr_fileExists (tmpstr, NULL));
|
||||
check_streq ("hello-world.txt", tr_torrentName(tor));
|
||||
check_int_eq (0, torrentRenameAndWait (tor, "hello-world.txt", "foobar"));
|
||||
check (!tr_fileExists (tmpstr, NULL));
|
||||
check (tor->info.files[0].is_renamed);
|
||||
check_streq ("foobar", tor->info.files[0].name);
|
||||
tr_free (tmpstr);
|
||||
check_streq ("foobar", tr_torrentName(tor));
|
||||
check (strstr (tor->info.torrent, "foobar") == NULL);
|
||||
check (testFileExistsAndConsistsOfThisString (tor, 0, "hello, world!\n"));
|
||||
tr_free (tmpstr);
|
||||
|
||||
/* (while it's renamed: confirm that the .resume file remembers the changes) */
|
||||
tr_torrentSaveResume (tor);
|
||||
sync ();
|
||||
loaded = tr_torrentLoadResume (tor, ~0, ctor);
|
||||
check_streq ("foobar", tr_torrentName(tor));
|
||||
check ((loaded & TR_FR_NAME) != 0);
|
||||
|
||||
/***
|
||||
**** ...and rename it back again
|
||||
|
@ -224,6 +235,7 @@ test_single_filename_torrent (void)
|
|||
check (!tr_fileExists (tmpstr, NULL));
|
||||
check (tor->info.files[0].is_renamed);
|
||||
check_streq ("hello-world.txt", tor->info.files[0].name);
|
||||
check_streq ("hello-world.txt", tr_torrentName(tor));
|
||||
tr_free (tmpstr);
|
||||
check (testFileExistsAndConsistsOfThisString (tor, 0, "hello, world!\n"));
|
||||
|
||||
|
@ -265,12 +277,9 @@ create_multifile_torrent_contents (const char * top)
|
|||
static int
|
||||
test_multifile_torrent (void)
|
||||
{
|
||||
//tr_file_stat * file_stats;
|
||||
//tr_file_index_t n;
|
||||
tr_file_index_t i;
|
||||
uint64_t loaded;
|
||||
tr_torrent * tor;
|
||||
//tr_file_index_t i;
|
||||
tr_ctor * ctor;
|
||||
char * str;
|
||||
char * tmp;
|
||||
|
|
|
@ -340,6 +340,36 @@ loadIdleLimits (tr_variant * dict, tr_torrent * tor)
|
|||
****
|
||||
***/
|
||||
|
||||
static void
|
||||
saveName (tr_variant * dict, const tr_torrent * tor)
|
||||
{
|
||||
tr_variantDictAddStr (dict, TR_KEY_name, tr_torrentName(tor));
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
loadName (tr_variant * dict, tr_torrent * tor)
|
||||
{
|
||||
uint64_t ret = 0;
|
||||
const char * name;
|
||||
|
||||
if (tr_variantDictFindStr (dict, TR_KEY_name, &name, NULL))
|
||||
{
|
||||
ret = TR_FR_NAME;
|
||||
|
||||
if (tr_strcmp0 (tr_torrentName(tor), name))
|
||||
{
|
||||
tr_free (tor->info.name);
|
||||
tor->info.name = tr_strdup (name);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
static void
|
||||
saveFilenames (tr_variant * dict, const tr_torrent * tor)
|
||||
{
|
||||
|
@ -650,6 +680,7 @@ tr_torrentSaveResume (tr_torrent * tor)
|
|||
saveRatioLimits (&top, tor);
|
||||
saveIdleLimits (&top, tor);
|
||||
saveFilenames (&top, tor);
|
||||
saveName (&top, tor);
|
||||
|
||||
filename = getResumeFilename (tor);
|
||||
if ((err = tr_variantToFile (&top, TR_VARIANT_FMT_BENC, filename)))
|
||||
|
@ -805,6 +836,9 @@ loadFromFile (tr_torrent * tor, uint64_t fieldsToLoad)
|
|||
if (fieldsToLoad & TR_FR_FILENAMES)
|
||||
fieldsLoaded |= loadFilenames (&top, tor);
|
||||
|
||||
if (fieldsToLoad & TR_FR_NAME)
|
||||
fieldsLoaded |= loadName (&top, tor);
|
||||
|
||||
/* loading the resume file triggers of a lot of changes,
|
||||
* but none of them needs to trigger a re-saving of the
|
||||
* same resume information... */
|
||||
|
|
|
@ -39,7 +39,8 @@ enum
|
|||
TR_FR_IDLELIMIT = (1 << 17),
|
||||
TR_FR_TIME_SEEDING = (1 << 18),
|
||||
TR_FR_TIME_DOWNLOADING = (1 << 19),
|
||||
TR_FR_FILENAMES = (1 << 20)
|
||||
TR_FR_FILENAMES = (1 << 20),
|
||||
TR_FR_NAME = (1 << 21),
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -53,4 +54,7 @@ void tr_torrentSaveResume (tr_torrent * tor);
|
|||
|
||||
void tr_torrentRemoveResume (const tr_torrent * tor);
|
||||
|
||||
int tr_torrentRenameResume (const tr_torrent * tor,
|
||||
const char * newname);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -374,6 +374,7 @@ tr_torrentGetMetadataPercent (const tr_torrent * tor)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* FIXME: this should be renamed tr_metainfoGetMagnetLink() and moved to metainfo.c for consistency */
|
||||
char *
|
||||
tr_torrentInfoGetMagnetLink (const tr_info * inf)
|
||||
{
|
||||
|
|
|
@ -3440,6 +3440,16 @@ struct rename_data
|
|||
void * callback_user_data;
|
||||
};
|
||||
|
||||
static void
|
||||
torrentRenameDone (tr_torrent * tor UNUSED,
|
||||
const char * oldpath UNUSED,
|
||||
const char * newname UNUSED,
|
||||
int error,
|
||||
void * user_data)
|
||||
{
|
||||
*(int*)user_data = error;
|
||||
}
|
||||
|
||||
static void
|
||||
torrentRenamePath (void * vdata)
|
||||
{
|
||||
|
@ -3477,8 +3487,14 @@ torrentRenamePath (void * vdata)
|
|||
|
||||
if (!error)
|
||||
{
|
||||
/* update tr_info.files */
|
||||
for (i=0; i<n; ++i)
|
||||
renameTorrentFileString(tor, oldpath, newname, file_indices[i]);
|
||||
|
||||
/* update tr_info.name if user changed the toplevel */
|
||||
if ((n == tor->info.fileCount) && (strchr(oldpath,'/')==NULL))
|
||||
tr_torrentRename (tor, newname, torrentRenameDone, &error);
|
||||
|
||||
tr_torrentSetDirty (tor);
|
||||
}
|
||||
}
|
||||
|
@ -3521,3 +3537,44 @@ tr_torrentRenamePath (tr_torrent * tor,
|
|||
|
||||
tr_runInEventThread (tor->session, torrentRenamePath, data);
|
||||
}
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
||||
static void
|
||||
torrentRename (void * vdata)
|
||||
{
|
||||
int error = 0;
|
||||
struct rename_data * data = vdata;
|
||||
tr_torrent * const tor = data->tor;
|
||||
|
||||
tr_free (tor->info.name);
|
||||
tor->info.name = data->newname;
|
||||
tr_torrentSetDirty (tor);
|
||||
tor->anyDate = tr_time ();
|
||||
|
||||
/* callback */
|
||||
if (data->callback != NULL)
|
||||
(*data->callback)(tor, data->oldpath, data->newname, error, data->callback_user_data);
|
||||
|
||||
/* cleanup */
|
||||
tr_free (data);
|
||||
}
|
||||
|
||||
void
|
||||
tr_torrentRename (tr_torrent * tor,
|
||||
const char * newname,
|
||||
tr_torrent_rename_done_func callback,
|
||||
void * callback_user_data)
|
||||
{
|
||||
struct rename_data * data;
|
||||
|
||||
data = tr_new0 (struct rename_data, 1);
|
||||
data->tor = tor;
|
||||
data->newname = tr_strdup (newname);
|
||||
data->callback = callback;
|
||||
data->callback_user_data = callback_user_data;
|
||||
|
||||
tr_runInEventThread (tor->session, torrentRename, data);
|
||||
}
|
||||
|
|
|
@ -1109,6 +1109,9 @@ typedef void (tr_torrent_rename_done_func)(tr_torrent * torrent,
|
|||
* @callback: the callback invoked when the renaming finishes, or NULL
|
||||
* @callback_data: the pointer to pass in the callback's user_data arg
|
||||
*
|
||||
* As a special case, renaming the root file in a torrent will call
|
||||
* tr_torrentRename (tor, newname).
|
||||
*
|
||||
* EXAMPLES
|
||||
*
|
||||
* Consider a tr_torrent where its
|
||||
|
@ -1116,7 +1119,8 @@ typedef void (tr_torrent_rename_done_func)(tr_torrent * torrent,
|
|||
* info.files[1].name is "frobnitz-linux/frobnitz.iso".
|
||||
*
|
||||
* 1. tr_torrentRenamePath (tor, "frobnitz-linux", "foo") will rename
|
||||
* the "frotbnitz-linux" folder as "foo" and update files[*].name.
|
||||
* the "frotbnitz-linux" folder as "foo", update info.files[*].name,
|
||||
* and also call tr_torrentRename(tor,"foo").
|
||||
*
|
||||
* 2. tr_torrentRenamePath (tor, "frobnitz-linux/checksum", "foo") will
|
||||
* rename the "frobnitz-linux/checksum" file as "foo" and update
|
||||
|
@ -1125,8 +1129,8 @@ typedef void (tr_torrent_rename_done_func)(tr_torrent * torrent,
|
|||
* RETURN
|
||||
*
|
||||
* Changing tr_info's contents requires a session lock, so this function
|
||||
* returns asynchronously to avoid blocking. If you don't care about error
|
||||
* checking, you can pass NULL as the callback and callback_user_data arg.
|
||||
* returns asynchronously to avoid blocking. If you don't want to be notified
|
||||
* when the function has finished, you can pass NULL as the callback arg.
|
||||
*
|
||||
* On success, the callback's error argument will be 0.
|
||||
*
|
||||
|
@ -1144,6 +1148,21 @@ void tr_torrentRenamePath (tr_torrent * tor,
|
|||
void * callback_user_data);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Changes the torrent's name.
|
||||
* @see-also tr_torrentRenamePath
|
||||
*
|
||||
* This function changes tr_info.name.
|
||||
*
|
||||
* Changing tr_info's contents requires a session lock, so this function
|
||||
* returns asynchronously to avoid blocking. If you don't want to be notified
|
||||
* when the function has finished, you can pass NULL as the callback arg.
|
||||
*/
|
||||
void tr_torrentRename (tr_torrent * tor,
|
||||
const char * newname,
|
||||
tr_torrent_rename_done_func callback,
|
||||
void * callback_user_data);
|
||||
|
||||
enum
|
||||
{
|
||||
TR_LOC_MOVING,
|
||||
|
@ -1757,7 +1776,12 @@ struct tr_info
|
|||
/* total size of the torrent, in bytes */
|
||||
uint64_t totalSize;
|
||||
|
||||
/* the torrent's name */
|
||||
/* The original name that came in this torrent's metainfo.
|
||||
* This may differ from "name" if tr_torrentRename() is called.
|
||||
* CLIENT CODE: NOT USE THIS FIELD. */
|
||||
char * originalName;
|
||||
|
||||
/* The torrent's name. */
|
||||
char * name;
|
||||
|
||||
/* Path to torrent Transmission's internal copy of the .torrent file. */
|
||||
|
|
|
@ -827,7 +827,7 @@ Session :: parseResponse( const char * json, size_t jsonLength )
|
|||
else if (tr_variantDictFindInt (args, TR_KEY_id, &id) && id)
|
||||
{
|
||||
// let's get the updated file list
|
||||
char * req = tr_strdup_printf ("{ \"arguments\": { \"fields\": [ \"files\", \"id\" ], \"ids\": %d }, \"method\": \"torrent-get\", \"tag\": %d }",
|
||||
char * req = tr_strdup_printf ("{ \"arguments\": { \"fields\": [ \"files\", \"id\", \"name\" ], \"ids\": %d }, \"method\": \"torrent-get\", \"tag\": %d }",
|
||||
int(id),
|
||||
int(TAG_SOME_TORRENTS));
|
||||
exec (req);
|
||||
|
|
Loading…
Reference in a new issue