2007-06-18 03:40:41 +00:00
|
|
|
/*
|
2011-01-19 13:48:47 +00:00
|
|
|
* This file Copyright (C) Mnemosyne LLC
|
2007-06-18 03:40:41 +00:00
|
|
|
*
|
2010-12-27 19:18:17 +00:00
|
|
|
* This file is licensed by the GPL version 2. Works owned by the
|
2012-12-05 17:29:46 +00:00
|
|
|
* Transmission project are granted a special exemption to clause 2 (b)
|
2008-09-23 19:11:04 +00:00
|
|
|
* so that the bulk of its code can remain under the MIT license.
|
2007-06-18 03:40:41 +00:00
|
|
|
* This exemption does not extend to derived works not owned by
|
|
|
|
* the Transmission project.
|
2007-08-18 17:19:49 +00:00
|
|
|
*
|
|
|
|
* $Id$
|
2007-06-18 03:40:41 +00:00
|
|
|
*/
|
|
|
|
|
2007-11-09 20:07:52 +00:00
|
|
|
#include <assert.h>
|
2007-07-29 18:11:21 +00:00
|
|
|
#include <errno.h>
|
2008-07-15 17:16:57 +00:00
|
|
|
#include <stdio.h> /* FILE, stderr */
|
2008-02-19 18:39:49 +00:00
|
|
|
#include <stdlib.h> /* qsort */
|
2011-03-13 08:21:55 +00:00
|
|
|
#include <string.h> /* strcmp, strlen */
|
2007-07-29 18:11:21 +00:00
|
|
|
|
2007-06-18 03:40:41 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
2012-12-05 17:29:46 +00:00
|
|
|
#include <unistd.h> /* read () */
|
2007-06-18 03:40:41 +00:00
|
|
|
#include <dirent.h>
|
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
#include <event2/util.h> /* evutil_ascii_strcasecmp () */
|
2011-03-13 08:21:55 +00:00
|
|
|
|
2007-06-18 03:40:41 +00:00
|
|
|
#include "transmission.h"
|
2010-04-23 16:36:16 +00:00
|
|
|
#include "crypto.h" /* tr_sha1 */
|
2012-12-05 17:29:46 +00:00
|
|
|
#include "fdlimit.h" /* tr_open_file_for_scanning () */
|
2008-12-23 17:27:15 +00:00
|
|
|
#include "session.h"
|
2007-06-18 03:40:41 +00:00
|
|
|
#include "bencode.h"
|
|
|
|
#include "makemeta.h"
|
2011-07-13 03:23:37 +00:00
|
|
|
#include "platform.h" /* threads, locks */
|
2007-07-30 18:04:10 +00:00
|
|
|
#include "utils.h" /* buildpath */
|
2007-06-18 03:40:41 +00:00
|
|
|
#include "version.h"
|
|
|
|
|
|
|
|
/****
|
|
|
|
*****
|
|
|
|
****/
|
|
|
|
|
|
|
|
struct FileList
|
|
|
|
{
|
2008-09-23 19:11:04 +00:00
|
|
|
struct FileList * next;
|
|
|
|
uint64_t size;
|
|
|
|
char * filename;
|
2007-06-18 03:40:41 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct FileList*
|
2012-12-05 17:29:46 +00:00
|
|
|
getFiles (const char * dir,
|
2008-09-23 19:11:04 +00:00
|
|
|
const char * base,
|
2012-12-05 17:29:46 +00:00
|
|
|
struct FileList * list)
|
2007-06-18 03:40:41 +00:00
|
|
|
{
|
2008-09-23 19:11:04 +00:00
|
|
|
int i;
|
2008-10-14 03:03:29 +00:00
|
|
|
char * buf;
|
2007-06-18 03:40:41 +00:00
|
|
|
struct stat sb;
|
2008-09-23 19:11:04 +00:00
|
|
|
DIR * odir = NULL;
|
|
|
|
|
2007-06-18 03:40:41 +00:00
|
|
|
sb.st_size = 0;
|
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
buf = tr_buildPath (dir, base, NULL);
|
|
|
|
i = stat (buf, &sb);
|
|
|
|
if (i)
|
2008-09-23 19:11:04 +00:00
|
|
|
{
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_err (_ ("Torrent Creator is skipping file \"%s\": %s"),
|
|
|
|
buf, tr_strerror (errno));
|
|
|
|
tr_free (buf);
|
2007-06-18 03:40:41 +00:00
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
if (S_ISDIR (sb.st_mode) && ((odir = opendir (buf))))
|
2007-06-18 03:40:41 +00:00
|
|
|
{
|
|
|
|
struct dirent *d;
|
2012-12-05 17:29:46 +00:00
|
|
|
for (d = readdir (odir); d != NULL; d = readdir (odir))
|
|
|
|
if (d->d_name && d->d_name[0] != '.') /* skip dotfiles */
|
|
|
|
list = getFiles (buf, d->d_name, list);
|
|
|
|
closedir (odir);
|
2007-06-18 03:40:41 +00:00
|
|
|
}
|
2012-12-05 17:29:46 +00:00
|
|
|
else if (S_ISREG (sb.st_mode) && (sb.st_size > 0))
|
2007-06-18 03:40:41 +00:00
|
|
|
{
|
2012-12-05 17:29:46 +00:00
|
|
|
struct FileList * node = tr_new (struct FileList, 1);
|
2007-06-19 00:08:39 +00:00
|
|
|
node->size = sb.st_size;
|
2012-12-05 17:29:46 +00:00
|
|
|
node->filename = tr_strdup (buf);
|
2007-06-18 03:40:41 +00:00
|
|
|
node->next = list;
|
|
|
|
list = node;
|
|
|
|
}
|
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_free (buf);
|
2007-06-18 03:40:41 +00:00
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2010-07-01 15:14:35 +00:00
|
|
|
static uint32_t
|
2012-12-05 17:29:46 +00:00
|
|
|
bestPieceSize (uint64_t totalSize)
|
2007-06-18 03:40:41 +00:00
|
|
|
{
|
2010-07-01 15:14:35 +00:00
|
|
|
const uint32_t KiB = 1024;
|
2011-06-24 19:30:25 +00:00
|
|
|
const uint32_t MiB = 1048576;
|
|
|
|
const uint32_t GiB = 1073741824;
|
2007-06-18 03:40:41 +00:00
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
if (totalSize >= (2 * GiB)) return 2 * MiB;
|
|
|
|
if (totalSize >= (1 * GiB)) return 1 * MiB;
|
|
|
|
if (totalSize >= (512 * MiB)) return 512 * KiB;
|
|
|
|
if (totalSize >= (350 * MiB)) return 256 * KiB;
|
|
|
|
if (totalSize >= (150 * MiB)) return 128 * KiB;
|
|
|
|
if (totalSize >= (50 * MiB)) return 64 * KiB;
|
2008-09-23 19:11:04 +00:00
|
|
|
return 32 * KiB; /* less than 50 meg */
|
2007-06-18 03:40:41 +00:00
|
|
|
}
|
|
|
|
|
2007-06-19 00:08:39 +00:00
|
|
|
static int
|
2012-12-05 17:29:46 +00:00
|
|
|
builderFileCompare (const void * va, const void * vb)
|
2007-06-18 03:40:41 +00:00
|
|
|
{
|
2007-09-20 20:14:13 +00:00
|
|
|
const tr_metainfo_builder_file * a = va;
|
|
|
|
const tr_metainfo_builder_file * b = vb;
|
2008-09-23 19:11:04 +00:00
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
return evutil_ascii_strcasecmp (a->filename, b->filename);
|
2007-06-18 03:40:41 +00:00
|
|
|
}
|
|
|
|
|
2007-09-20 20:14:13 +00:00
|
|
|
tr_metainfo_builder*
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_metaInfoBuilderCreate (const char * topFileArg)
|
2007-06-18 03:40:41 +00:00
|
|
|
{
|
2011-07-24 20:18:33 +00:00
|
|
|
int i;
|
|
|
|
struct FileList * files;
|
|
|
|
struct FileList * walk;
|
|
|
|
char topFile[TR_PATH_MAX];
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_metainfo_builder * ret = tr_new0 (tr_metainfo_builder, 1);
|
2008-09-23 19:11:04 +00:00
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_realpath (topFileArg, topFile);
|
2011-07-24 20:18:33 +00:00
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
ret->top = tr_strdup (topFile);
|
2009-04-08 18:47:48 +00:00
|
|
|
|
2008-05-06 20:31:05 +00:00
|
|
|
{
|
2007-06-18 03:40:41 +00:00
|
|
|
struct stat sb;
|
2012-12-05 17:29:46 +00:00
|
|
|
stat (topFile, &sb);
|
|
|
|
ret->isSingleFile = !S_ISDIR (sb.st_mode);
|
2007-06-18 03:40:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* build a list of files containing topFile and,
|
|
|
|
if it's a directory, all of its children */
|
2008-05-06 20:31:05 +00:00
|
|
|
{
|
2012-12-05 17:29:46 +00:00
|
|
|
char * dir = tr_dirname (topFile);
|
|
|
|
char * base = tr_basename (topFile);
|
|
|
|
files = getFiles (dir, base, NULL);
|
|
|
|
tr_free (base);
|
|
|
|
tr_free (dir);
|
2007-06-18 03:40:41 +00:00
|
|
|
}
|
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
for (walk = files; walk != NULL; walk = walk->next)
|
2007-06-18 03:40:41 +00:00
|
|
|
++ret->fileCount;
|
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
ret->files = tr_new0 (tr_metainfo_builder_file, ret->fileCount);
|
2007-06-18 03:40:41 +00:00
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
for (i = 0, walk = files; walk != NULL; ++i)
|
2007-06-19 00:08:39 +00:00
|
|
|
{
|
2008-09-23 19:11:04 +00:00
|
|
|
struct FileList * tmp = walk;
|
2007-09-20 20:14:13 +00:00
|
|
|
tr_metainfo_builder_file * file = &ret->files[i];
|
2007-06-19 00:08:39 +00:00
|
|
|
walk = walk->next;
|
|
|
|
file->filename = tmp->filename;
|
|
|
|
file->size = tmp->size;
|
|
|
|
ret->totalSize += tmp->size;
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_free (tmp);
|
2007-06-18 03:40:41 +00:00
|
|
|
}
|
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
qsort (ret->files,
|
2007-06-19 00:08:39 +00:00
|
|
|
ret->fileCount,
|
2012-12-05 17:29:46 +00:00
|
|
|
sizeof (tr_metainfo_builder_file),
|
|
|
|
builderFileCompare);
|
2007-06-19 00:08:39 +00:00
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
ret->pieceSize = bestPieceSize (ret->totalSize);
|
|
|
|
ret->pieceCount = (int)(ret->totalSize / ret->pieceSize);
|
|
|
|
if (ret->totalSize % ret->pieceSize)
|
2007-06-18 03:40:41 +00:00
|
|
|
++ret->pieceCount;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_metaInfoBuilderFree (tr_metainfo_builder * builder)
|
2007-06-18 03:40:41 +00:00
|
|
|
{
|
2012-12-05 17:29:46 +00:00
|
|
|
if (builder)
|
2007-06-18 03:40:41 +00:00
|
|
|
{
|
2008-06-01 05:36:23 +00:00
|
|
|
tr_file_index_t t;
|
2008-09-23 19:11:04 +00:00
|
|
|
int i;
|
2012-12-05 17:29:46 +00:00
|
|
|
for (t = 0; t < builder->fileCount; ++t)
|
|
|
|
tr_free (builder->files[t].filename);
|
|
|
|
tr_free (builder->files);
|
|
|
|
tr_free (builder->top);
|
|
|
|
tr_free (builder->comment);
|
|
|
|
for (i = 0; i < builder->trackerCount; ++i)
|
|
|
|
tr_free (builder->trackers[i].announce);
|
|
|
|
tr_free (builder->trackers);
|
|
|
|
tr_free (builder->outputFile);
|
|
|
|
tr_free (builder);
|
2007-06-18 03:40:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/****
|
|
|
|
*****
|
|
|
|
****/
|
|
|
|
|
|
|
|
static uint8_t*
|
2012-12-05 17:29:46 +00:00
|
|
|
getHashInfo (tr_metainfo_builder * b)
|
2007-06-18 03:40:41 +00:00
|
|
|
{
|
2007-10-26 03:16:27 +00:00
|
|
|
uint32_t fileIndex = 0;
|
2012-12-05 17:29:46 +00:00
|
|
|
uint8_t *ret = tr_new0 (uint8_t, SHA_DIGEST_LENGTH * b->pieceCount);
|
2007-06-18 03:40:41 +00:00
|
|
|
uint8_t *walk = ret;
|
2007-07-06 18:24:54 +00:00
|
|
|
uint8_t *buf;
|
2007-06-18 03:40:41 +00:00
|
|
|
uint64_t totalRemain;
|
|
|
|
uint64_t off = 0;
|
2010-06-16 14:01:03 +00:00
|
|
|
int fd;
|
2007-06-18 03:40:41 +00:00
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
if (!b->totalSize)
|
2007-07-06 18:24:54 +00:00
|
|
|
return ret;
|
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
buf = tr_valloc (b->pieceSize);
|
2007-06-18 03:40:41 +00:00
|
|
|
b->pieceIndex = 0;
|
|
|
|
totalRemain = b->totalSize;
|
2012-12-05 17:29:46 +00:00
|
|
|
fd = tr_open_file_for_scanning (b->files[fileIndex].filename);
|
|
|
|
if (fd < 0)
|
2008-09-23 19:11:04 +00:00
|
|
|
{
|
2008-03-24 17:18:08 +00:00
|
|
|
b->my_errno = errno;
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_strlcpy (b->errfile,
|
2008-10-22 17:14:50 +00:00
|
|
|
b->files[fileIndex].filename,
|
2012-12-05 17:29:46 +00:00
|
|
|
sizeof (b->errfile));
|
2008-03-24 17:18:08 +00:00
|
|
|
b->result = TR_MAKEMETA_IO_READ;
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_free (buf);
|
|
|
|
tr_free (ret);
|
2008-03-02 19:42:45 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2012-12-05 17:29:46 +00:00
|
|
|
while (totalRemain)
|
2007-06-18 03:40:41 +00:00
|
|
|
{
|
2010-07-01 15:14:35 +00:00
|
|
|
uint8_t * bufptr = buf;
|
2012-12-05 17:29:46 +00:00
|
|
|
const uint32_t thisPieceSize = (uint32_t) MIN (b->pieceSize, totalRemain);
|
2010-07-01 15:14:35 +00:00
|
|
|
uint32_t leftInPiece = thisPieceSize;
|
2007-06-18 03:40:41 +00:00
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
assert (b->pieceIndex < b->pieceCount);
|
2007-06-18 03:40:41 +00:00
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
while (leftInPiece)
|
2007-06-18 03:40:41 +00:00
|
|
|
{
|
2012-12-05 17:29:46 +00:00
|
|
|
const size_t n_this_pass = (size_t) MIN ((b->files[fileIndex].size - off), leftInPiece);
|
|
|
|
const ssize_t n_read = read (fd, bufptr, n_this_pass);
|
2011-02-09 05:16:37 +00:00
|
|
|
bufptr += n_read;
|
|
|
|
off += n_read;
|
|
|
|
leftInPiece -= n_read;
|
2012-12-05 17:29:46 +00:00
|
|
|
if (off == b->files[fileIndex].size)
|
2008-09-23 19:11:04 +00:00
|
|
|
{
|
2007-06-18 03:40:41 +00:00
|
|
|
off = 0;
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_close_file (fd);
|
2010-06-16 14:01:03 +00:00
|
|
|
fd = -1;
|
2012-12-05 17:29:46 +00:00
|
|
|
if (++fileIndex < b->fileCount)
|
2008-09-23 19:11:04 +00:00
|
|
|
{
|
2012-12-05 17:29:46 +00:00
|
|
|
fd = tr_open_file_for_scanning (b->files[fileIndex].filename);
|
|
|
|
if (fd < 0)
|
2008-09-23 19:11:04 +00:00
|
|
|
{
|
2008-03-24 17:18:08 +00:00
|
|
|
b->my_errno = errno;
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_strlcpy (b->errfile,
|
2008-10-22 17:14:50 +00:00
|
|
|
b->files[fileIndex].filename,
|
2012-12-05 17:29:46 +00:00
|
|
|
sizeof (b->errfile));
|
2008-03-24 17:18:08 +00:00
|
|
|
b->result = TR_MAKEMETA_IO_READ;
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_free (buf);
|
|
|
|
tr_free (ret);
|
2008-03-02 19:42:45 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2007-06-18 03:40:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
assert (bufptr - buf == (int)thisPieceSize);
|
|
|
|
assert (leftInPiece == 0);
|
|
|
|
tr_sha1 (walk, buf, thisPieceSize, NULL);
|
2007-06-18 03:40:41 +00:00
|
|
|
walk += SHA_DIGEST_LENGTH;
|
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
if (b->abortFlag)
|
2008-09-23 19:11:04 +00:00
|
|
|
{
|
2008-03-24 17:18:08 +00:00
|
|
|
b->result = TR_MAKEMETA_CANCELLED;
|
2007-06-18 03:40:41 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
totalRemain -= thisPieceSize;
|
|
|
|
++b->pieceIndex;
|
|
|
|
}
|
2008-09-23 19:11:04 +00:00
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
assert (b->abortFlag
|
|
|
|
|| (walk - ret == (int)(SHA_DIGEST_LENGTH * b->pieceCount)));
|
|
|
|
assert (b->abortFlag || !totalRemain);
|
2007-06-18 03:40:41 +00:00
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
if (fd >= 0)
|
|
|
|
tr_close_file (fd);
|
2007-06-18 03:40:41 +00:00
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_free (buf);
|
2007-06-18 03:40:41 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2012-12-05 17:29:46 +00:00
|
|
|
getFileInfo (const char * topFile,
|
2008-09-23 19:11:04 +00:00
|
|
|
const tr_metainfo_builder_file * file,
|
|
|
|
tr_benc * uninitialized_length,
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_benc * uninitialized_path)
|
2007-06-18 03:40:41 +00:00
|
|
|
{
|
2010-10-17 22:28:28 +00:00
|
|
|
size_t offset;
|
2007-06-18 03:40:41 +00:00
|
|
|
|
|
|
|
/* get the file size */
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_bencInitInt (uninitialized_length, file->size);
|
2007-06-18 03:40:41 +00:00
|
|
|
|
2009-06-20 00:39:30 +00:00
|
|
|
/* how much of file->filename to walk past */
|
2012-12-05 17:29:46 +00:00
|
|
|
offset = strlen (topFile);
|
|
|
|
if (offset>0 && topFile[offset-1]!=TR_PATH_DELIMITER)
|
2010-10-17 22:28:28 +00:00
|
|
|
++offset; /* +1 for the path delimiter */
|
2009-06-20 00:39:30 +00:00
|
|
|
|
|
|
|
/* build the path list */
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_bencInitList (uninitialized_path, 0);
|
|
|
|
if (strlen (file->filename) > offset) {
|
|
|
|
char * filename = tr_strdup (file->filename + offset);
|
2010-10-17 22:28:28 +00:00
|
|
|
char * walk = filename;
|
|
|
|
const char * token;
|
2012-12-05 17:29:46 +00:00
|
|
|
while ((token = tr_strsep (&walk, TR_PATH_DELIMITER_STR)))
|
|
|
|
tr_bencListAddStr (uninitialized_path, token);
|
|
|
|
tr_free (filename);
|
2007-06-18 03:40:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2012-12-05 17:29:46 +00:00
|
|
|
makeInfoDict (tr_benc * dict,
|
|
|
|
tr_metainfo_builder * builder)
|
2007-06-18 03:40:41 +00:00
|
|
|
{
|
|
|
|
uint8_t * pch;
|
2008-10-14 03:39:16 +00:00
|
|
|
char * base;
|
2007-06-18 03:40:41 +00:00
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_bencDictReserve (dict, 5);
|
2008-09-23 19:11:04 +00:00
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
if (builder->isSingleFile)
|
2010-09-21 16:58:15 +00:00
|
|
|
{
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_bencDictAddInt (dict, "length", builder->files[0].size);
|
2010-09-21 16:58:15 +00:00
|
|
|
}
|
2010-09-30 05:22:33 +00:00
|
|
|
else /* root node is a directory */
|
2008-09-23 19:11:04 +00:00
|
|
|
{
|
|
|
|
uint32_t i;
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_benc * list = tr_bencDictAddList (dict, "files",
|
|
|
|
builder->fileCount);
|
|
|
|
for (i = 0; i < builder->fileCount; ++i)
|
2008-09-23 19:11:04 +00:00
|
|
|
{
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_benc * d = tr_bencListAddDict (list, 2);
|
|
|
|
tr_benc * length = tr_bencDictAdd (d, "length");
|
|
|
|
tr_benc * pathVal = tr_bencDictAdd (d, "path");
|
|
|
|
getFileInfo (builder->top, &builder->files[i], length, pathVal);
|
2008-04-18 16:23:59 +00:00
|
|
|
}
|
2007-06-18 03:40:41 +00:00
|
|
|
}
|
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
base = tr_basename (builder->top);
|
|
|
|
tr_bencDictAddStr (dict, "name", base);
|
|
|
|
tr_free (base);
|
2007-07-25 01:00:17 +00:00
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_bencDictAddInt (dict, "piece length", builder->pieceSize);
|
2007-07-25 01:00:17 +00:00
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
if ((pch = getHashInfo (builder)))
|
2008-09-23 19:11:04 +00:00
|
|
|
{
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_bencDictAddRaw (dict, "pieces", pch,
|
|
|
|
SHA_DIGEST_LENGTH * builder->pieceCount);
|
|
|
|
tr_free (pch);
|
2008-03-02 19:42:45 +00:00
|
|
|
}
|
2007-07-25 01:00:17 +00:00
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_bencDictAddInt (dict, "private", builder->isPrivate ? 1 : 0);
|
2007-06-18 03:40:41 +00:00
|
|
|
}
|
|
|
|
|
2008-03-24 15:58:06 +00:00
|
|
|
static void
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_realMakeMetaInfo (tr_metainfo_builder * builder)
|
2007-06-18 03:40:41 +00:00
|
|
|
{
|
2008-09-23 19:11:04 +00:00
|
|
|
int i;
|
2008-04-18 16:23:59 +00:00
|
|
|
tr_benc top;
|
2007-06-18 03:40:41 +00:00
|
|
|
|
2008-06-01 05:36:23 +00:00
|
|
|
/* allow an empty set, but if URLs *are* listed, verify them. #814, #971 */
|
2012-12-05 17:29:46 +00:00
|
|
|
for (i = 0; i < builder->trackerCount && !builder->result; ++i) {
|
|
|
|
if (!tr_urlIsValidTracker (builder->trackers[i].announce)) {
|
|
|
|
tr_strlcpy (builder->errfile, builder->trackers[i].announce,
|
|
|
|
sizeof (builder->errfile));
|
2008-06-01 05:36:23 +00:00
|
|
|
builder->result = TR_MAKEMETA_URL;
|
2009-09-17 01:18:59 +00:00
|
|
|
}
|
|
|
|
}
|
2007-06-18 03:40:41 +00:00
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_bencInitDict (&top, 6);
|
2008-04-18 16:23:59 +00:00
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
if (!builder->fileCount || !builder->totalSize ||
|
|
|
|
!builder->pieceSize || !builder->pieceCount)
|
2010-07-07 22:50:18 +00:00
|
|
|
{
|
|
|
|
builder->errfile[0] = '\0';
|
|
|
|
builder->my_errno = ENOENT;
|
|
|
|
builder->result = TR_MAKEMETA_IO_READ;
|
2011-03-22 15:19:54 +00:00
|
|
|
builder->isDone = true;
|
2010-07-07 22:50:18 +00:00
|
|
|
}
|
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
if (!builder->result && builder->trackerCount)
|
2008-06-01 05:36:23 +00:00
|
|
|
{
|
2008-09-23 19:11:04 +00:00
|
|
|
int prevTier = -1;
|
2008-06-01 05:36:23 +00:00
|
|
|
tr_benc * tier = NULL;
|
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
if (builder->trackerCount > 1)
|
2008-08-11 17:29:53 +00:00
|
|
|
{
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_benc * annList = tr_bencDictAddList (&top, "announce-list",
|
|
|
|
0);
|
|
|
|
for (i = 0; i < builder->trackerCount; ++i)
|
2008-09-23 19:11:04 +00:00
|
|
|
{
|
2012-12-05 17:29:46 +00:00
|
|
|
if (prevTier != builder->trackers[i].tier)
|
2008-09-23 19:11:04 +00:00
|
|
|
{
|
2008-08-11 17:29:53 +00:00
|
|
|
prevTier = builder->trackers[i].tier;
|
2012-12-05 17:29:46 +00:00
|
|
|
tier = tr_bencListAddList (annList, 0);
|
2008-08-11 17:29:53 +00:00
|
|
|
}
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_bencListAddStr (tier, builder->trackers[i].announce);
|
2008-06-01 05:36:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_bencDictAddStr (&top, "announce", builder->trackers[0].announce);
|
2008-06-01 05:36:23 +00:00
|
|
|
}
|
2008-08-11 17:29:53 +00:00
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
if (!builder->result && !builder->abortFlag)
|
2008-03-24 15:58:06 +00:00
|
|
|
{
|
2012-12-05 17:29:46 +00:00
|
|
|
if (builder->comment && *builder->comment)
|
|
|
|
tr_bencDictAddStr (&top, "comment", builder->comment);
|
|
|
|
tr_bencDictAddStr (&top, "created by",
|
|
|
|
TR_NAME "/" LONG_VERSION_STRING);
|
|
|
|
tr_bencDictAddInt (&top, "creation date", time (NULL));
|
|
|
|
tr_bencDictAddStr (&top, "encoding", "UTF-8");
|
|
|
|
makeInfoDict (tr_bencDictAddDict (&top, "info", 666), builder);
|
2008-03-24 15:58:06 +00:00
|
|
|
}
|
2007-06-18 03:40:41 +00:00
|
|
|
|
|
|
|
/* save the file */
|
2012-12-05 17:29:46 +00:00
|
|
|
if (!builder->result && !builder->abortFlag)
|
2008-09-23 19:11:04 +00:00
|
|
|
{
|
2012-12-05 17:29:46 +00:00
|
|
|
if (tr_bencToFile (&top, TR_FMT_BENC, builder->outputFile))
|
2008-09-23 19:11:04 +00:00
|
|
|
{
|
2008-03-24 17:18:08 +00:00
|
|
|
builder->my_errno = errno;
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_strlcpy (builder->errfile, builder->outputFile,
|
|
|
|
sizeof (builder->errfile));
|
2008-03-24 17:18:08 +00:00
|
|
|
builder->result = TR_MAKEMETA_IO_WRITE;
|
2008-03-24 15:58:06 +00:00
|
|
|
}
|
2007-06-18 03:40:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* cleanup */
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_bencFree (&top);
|
|
|
|
if (builder->abortFlag)
|
2008-03-24 17:18:08 +00:00
|
|
|
builder->result = TR_MAKEMETA_CANCELLED;
|
2007-06-18 03:40:41 +00:00
|
|
|
builder->isDone = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
|
|
****
|
|
|
|
**** A threaded builder queue
|
|
|
|
****
|
|
|
|
***/
|
|
|
|
|
2007-09-20 20:14:13 +00:00
|
|
|
static tr_metainfo_builder * queue = NULL;
|
2007-06-18 03:40:41 +00:00
|
|
|
|
2008-09-23 19:11:04 +00:00
|
|
|
static tr_thread * workerThread = NULL;
|
2007-06-18 03:40:41 +00:00
|
|
|
|
2008-09-23 19:11:04 +00:00
|
|
|
static tr_lock*
|
2012-12-05 17:29:46 +00:00
|
|
|
getQueueLock (void)
|
2007-06-18 03:40:41 +00:00
|
|
|
{
|
2007-09-20 16:32:01 +00:00
|
|
|
static tr_lock * lock = NULL;
|
2007-06-18 03:40:41 +00:00
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
if (!lock)
|
|
|
|
lock = tr_lockNew ();
|
2007-06-18 03:40:41 +00:00
|
|
|
|
|
|
|
return lock;
|
|
|
|
}
|
|
|
|
|
2008-09-23 19:11:04 +00:00
|
|
|
static void
|
2012-12-05 17:29:46 +00:00
|
|
|
makeMetaWorkerFunc (void * unused UNUSED)
|
2007-06-18 03:40:41 +00:00
|
|
|
{
|
2012-12-05 17:29:46 +00:00
|
|
|
for (;;)
|
2007-06-18 03:40:41 +00:00
|
|
|
{
|
2007-09-20 20:14:13 +00:00
|
|
|
tr_metainfo_builder * builder = NULL;
|
2007-06-18 03:40:41 +00:00
|
|
|
|
|
|
|
/* find the next builder to process */
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_lock * lock = getQueueLock ();
|
|
|
|
tr_lockLock (lock);
|
|
|
|
if (queue)
|
2008-09-23 19:11:04 +00:00
|
|
|
{
|
2007-06-18 03:40:41 +00:00
|
|
|
builder = queue;
|
|
|
|
queue = queue->nextBuilder;
|
|
|
|
}
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_lockUnlock (lock);
|
2007-06-18 03:40:41 +00:00
|
|
|
|
|
|
|
/* if no builders, this worker thread is done */
|
2012-12-05 17:29:46 +00:00
|
|
|
if (builder == NULL)
|
2008-09-23 19:11:04 +00:00
|
|
|
break;
|
2007-06-18 03:40:41 +00:00
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_realMakeMetaInfo (builder);
|
2007-06-18 03:40:41 +00:00
|
|
|
}
|
|
|
|
|
2007-07-30 15:27:52 +00:00
|
|
|
workerThread = NULL;
|
2007-06-18 03:40:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-12-05 17:29:46 +00:00
|
|
|
tr_makeMetaInfo (tr_metainfo_builder * builder,
|
2008-09-23 19:11:04 +00:00
|
|
|
const char * outputFile,
|
|
|
|
const tr_tracker_info * trackers,
|
|
|
|
int trackerCount,
|
|
|
|
const char * comment,
|
2012-12-05 17:29:46 +00:00
|
|
|
int isPrivate)
|
2007-06-18 03:40:41 +00:00
|
|
|
{
|
2008-09-23 19:11:04 +00:00
|
|
|
int i;
|
2007-09-20 16:32:01 +00:00
|
|
|
tr_lock * lock;
|
2007-06-18 03:40:41 +00:00
|
|
|
|
2008-04-17 19:54:22 +00:00
|
|
|
/* free any variables from a previous run */
|
2012-12-05 17:29:46 +00:00
|
|
|
for (i = 0; i < builder->trackerCount; ++i)
|
|
|
|
tr_free (builder->trackers[i].announce);
|
|
|
|
tr_free (builder->trackers);
|
|
|
|
tr_free (builder->comment);
|
|
|
|
tr_free (builder->outputFile);
|
2008-04-17 19:54:22 +00:00
|
|
|
|
|
|
|
/* initialize the builder variables */
|
2007-06-18 03:40:41 +00:00
|
|
|
builder->abortFlag = 0;
|
2009-09-17 01:18:59 +00:00
|
|
|
builder->result = 0;
|
2007-06-18 03:40:41 +00:00
|
|
|
builder->isDone = 0;
|
2009-09-17 01:18:59 +00:00
|
|
|
builder->pieceIndex = 0;
|
2008-06-01 05:36:23 +00:00
|
|
|
builder->trackerCount = trackerCount;
|
2012-12-05 17:29:46 +00:00
|
|
|
builder->trackers = tr_new0 (tr_tracker_info, builder->trackerCount);
|
|
|
|
for (i = 0; i < builder->trackerCount; ++i) {
|
2008-06-01 05:36:23 +00:00
|
|
|
builder->trackers[i].tier = trackers[i].tier;
|
2012-12-05 17:29:46 +00:00
|
|
|
builder->trackers[i].announce = tr_strdup (trackers[i].announce);
|
2008-06-01 05:36:23 +00:00
|
|
|
}
|
2012-12-05 17:29:46 +00:00
|
|
|
builder->comment = tr_strdup (comment);
|
2007-06-18 03:40:41 +00:00
|
|
|
builder->isPrivate = isPrivate;
|
2012-12-05 17:29:46 +00:00
|
|
|
if (outputFile && *outputFile)
|
|
|
|
builder->outputFile = tr_strdup (outputFile);
|
2008-09-23 19:11:04 +00:00
|
|
|
else
|
2012-12-05 17:29:46 +00:00
|
|
|
builder->outputFile = tr_strdup_printf ("%s.torrent", builder->top);
|
2007-06-18 03:40:41 +00:00
|
|
|
|
|
|
|
/* enqueue the builder */
|
2012-12-05 17:29:46 +00:00
|
|
|
lock = getQueueLock ();
|
|
|
|
tr_lockLock (lock);
|
2007-06-18 03:40:41 +00:00
|
|
|
builder->nextBuilder = queue;
|
|
|
|
queue = builder;
|
2012-12-05 17:29:46 +00:00
|
|
|
if (!workerThread)
|
|
|
|
workerThread = tr_threadNew (makeMetaWorkerFunc, NULL);
|
|
|
|
tr_lockUnlock (lock);
|
2007-06-18 03:40:41 +00:00
|
|
|
}
|
|
|
|
|