transmission 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +0 -0
- data/LICENSE +23 -0
- data/README +50 -0
- data/Rakefile +41 -0
- data/ext/bencode.c +335 -0
- data/ext/bencode.h +64 -0
- data/ext/choking.c +335 -0
- data/ext/choking.h +30 -0
- data/ext/clients.c +90 -0
- data/ext/clients.h +25 -0
- data/ext/completion.c +266 -0
- data/ext/completion.h +67 -0
- data/ext/extconf.rb +3 -0
- data/ext/fastresume.h +375 -0
- data/ext/fdlimit.c +297 -0
- data/ext/fdlimit.h +36 -0
- data/ext/inout.c +620 -0
- data/ext/inout.h +38 -0
- data/ext/internal.h +202 -0
- data/ext/metainfo.c +339 -0
- data/ext/metainfo.h +44 -0
- data/ext/net.c +405 -0
- data/ext/net.h +54 -0
- data/ext/peer.c +584 -0
- data/ext/peer.h +55 -0
- data/ext/peermessages.h +326 -0
- data/ext/peerparse.h +564 -0
- data/ext/peerutils.h +394 -0
- data/ext/platform.c +196 -0
- data/ext/platform.h +63 -0
- data/ext/r_transmission.c +1135 -0
- data/ext/ratecontrol.c +170 -0
- data/ext/ratecontrol.h +33 -0
- data/ext/sha1.c +235 -0
- data/ext/sha1.h +68 -0
- data/ext/tracker.c +767 -0
- data/ext/tracker.h +53 -0
- data/ext/transmission.c +776 -0
- data/ext/transmission.h +317 -0
- data/ext/utils.c +142 -0
- data/ext/utils.h +164 -0
- data/lib/transmission.rb +75 -0
- metadata +98 -0
data/ext/inout.h
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
/******************************************************************************
|
2
|
+
* $Id: inout.h 346 2006-06-13 00:28:03Z titer $
|
3
|
+
*
|
4
|
+
* Copyright (c) 2005-2006 Transmission authors and contributors
|
5
|
+
*
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a
|
7
|
+
* copy of this software and associated documentation files (the "Software"),
|
8
|
+
* to deal in the Software without restriction, including without limitation
|
9
|
+
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
10
|
+
* and/or sell copies of the Software, and to permit persons to whom the
|
11
|
+
* Software is furnished to do so, subject to the following conditions:
|
12
|
+
*
|
13
|
+
* The above copyright notice and this permission notice shall be included in
|
14
|
+
* all copies or substantial portions of the Software.
|
15
|
+
*
|
16
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
22
|
+
* DEALINGS IN THE SOFTWARE.
|
23
|
+
*****************************************************************************/
|
24
|
+
|
25
|
+
#ifndef TR_IO_H
|
26
|
+
#define TR_IO_H 1
|
27
|
+
|
28
|
+
typedef struct tr_io_s tr_io_t;
|
29
|
+
|
30
|
+
void tr_ioLoadResume ( tr_torrent_t * );
|
31
|
+
|
32
|
+
tr_io_t * tr_ioInit ( tr_torrent_t * );
|
33
|
+
int tr_ioRead ( tr_io_t *, int, int, int, uint8_t * );
|
34
|
+
int tr_ioWrite ( tr_io_t *, int, int, int, uint8_t * );
|
35
|
+
void tr_ioClose ( tr_io_t * );
|
36
|
+
void tr_ioSaveResume ( tr_io_t * );
|
37
|
+
|
38
|
+
#endif
|
data/ext/internal.h
ADDED
@@ -0,0 +1,202 @@
|
|
1
|
+
/******************************************************************************
|
2
|
+
* $Id: internal.h 310 2006-06-09 19:53:35Z joshe $
|
3
|
+
*
|
4
|
+
* Copyright (c) 2005-2006 Transmission authors and contributors
|
5
|
+
*
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a
|
7
|
+
* copy of this software and associated documentation files (the "Software"),
|
8
|
+
* to deal in the Software without restriction, including without limitation
|
9
|
+
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
10
|
+
* and/or sell copies of the Software, and to permit persons to whom the
|
11
|
+
* Software is furnished to do so, subject to the following conditions:
|
12
|
+
*
|
13
|
+
* The above copyright notice and this permission notice shall be included in
|
14
|
+
* all copies or substantial portions of the Software.
|
15
|
+
*
|
16
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
22
|
+
* DEALINGS IN THE SOFTWARE.
|
23
|
+
*****************************************************************************/
|
24
|
+
|
25
|
+
#ifndef TR_INTERNAL_H
|
26
|
+
#define TR_INTERNAL_H 1
|
27
|
+
|
28
|
+
/* Standard headers used here and there.
|
29
|
+
That is probably ugly to put them all here, but it is sooo
|
30
|
+
convenient */
|
31
|
+
#include <stdio.h>
|
32
|
+
#include <stdarg.h>
|
33
|
+
#include <stdlib.h>
|
34
|
+
#include <string.h>
|
35
|
+
#include <unistd.h>
|
36
|
+
#include <errno.h>
|
37
|
+
#include <limits.h>
|
38
|
+
#include <signal.h>
|
39
|
+
#include <time.h>
|
40
|
+
#include <sys/time.h>
|
41
|
+
#include <sys/types.h>
|
42
|
+
#include <sys/stat.h>
|
43
|
+
#include <sys/resource.h>
|
44
|
+
#include <netdb.h>
|
45
|
+
#include <sys/socket.h>
|
46
|
+
#include <netinet/in.h>
|
47
|
+
#include <fcntl.h>
|
48
|
+
#include <assert.h>
|
49
|
+
#ifdef BEOS_NETSERVER
|
50
|
+
# define in_port_t uint16_t
|
51
|
+
#else
|
52
|
+
# include <arpa/inet.h>
|
53
|
+
#endif
|
54
|
+
|
55
|
+
#ifdef __GNUC__
|
56
|
+
# define UNUSED __attribute__((unused))
|
57
|
+
#else
|
58
|
+
# define UNUSED
|
59
|
+
#endif
|
60
|
+
|
61
|
+
/* We use OpenSSL whenever possible, since it is likely to be more
|
62
|
+
optimized and it is ok to use it with a MIT-licensed application.
|
63
|
+
Otherwise, we use the included implementation by vi@nwr.jp. */
|
64
|
+
#ifdef HAVE_OPENSSL
|
65
|
+
# undef SHA_DIGEST_LENGTH
|
66
|
+
# include <openssl/sha.h>
|
67
|
+
#else
|
68
|
+
# include "sha1.h"
|
69
|
+
# define SHA1(p,i,h) \
|
70
|
+
{ \
|
71
|
+
sha1_state_s pms; \
|
72
|
+
sha1_init( &pms ); \
|
73
|
+
sha1_update( &pms, (sha1_byte_t *) p, i ); \
|
74
|
+
sha1_finish( &pms, (sha1_byte_t *) h ); \
|
75
|
+
}
|
76
|
+
#endif
|
77
|
+
|
78
|
+
/* Convenient macros to perform uint32_t endian conversions with
|
79
|
+
char pointers */
|
80
|
+
#define TR_NTOHL(p,a) (a) = tr_ntohl((p))
|
81
|
+
#define TR_HTONL(a,p) tr_htonl((a), (p))
|
82
|
+
static inline uint32_t tr_ntohl( uint8_t * p )
|
83
|
+
{
|
84
|
+
uint32_t u;
|
85
|
+
memcpy( &u, p, sizeof( uint32_t ) );
|
86
|
+
return ntohl( u );
|
87
|
+
}
|
88
|
+
static inline void tr_htonl( uint32_t a, uint8_t * p )
|
89
|
+
{
|
90
|
+
uint32_t u;
|
91
|
+
u = htonl( a );
|
92
|
+
memcpy ( p, &u, sizeof( uint32_t ) );
|
93
|
+
}
|
94
|
+
|
95
|
+
/* Sometimes the system defines MAX/MIN, sometimes not. In the latter
|
96
|
+
case, define those here since we will use them */
|
97
|
+
#ifndef MAX
|
98
|
+
#define MAX(a,b) ((a)>(b)?(a):(b))
|
99
|
+
#endif
|
100
|
+
#ifndef MIN
|
101
|
+
#define MIN(a,b) ((a)>(b)?(b):(a))
|
102
|
+
#endif
|
103
|
+
|
104
|
+
#define TR_MAX_PEER_COUNT 60
|
105
|
+
|
106
|
+
typedef struct tr_completion_s tr_completion_t;
|
107
|
+
|
108
|
+
#include "platform.h"
|
109
|
+
#include "bencode.h"
|
110
|
+
#include "metainfo.h"
|
111
|
+
#include "tracker.h"
|
112
|
+
#include "fdlimit.h"
|
113
|
+
#include "peer.h"
|
114
|
+
#include "net.h"
|
115
|
+
#include "inout.h"
|
116
|
+
#include "ratecontrol.h"
|
117
|
+
#include "clients.h"
|
118
|
+
#include "choking.h"
|
119
|
+
|
120
|
+
struct tr_torrent_s
|
121
|
+
{
|
122
|
+
tr_info_t info;
|
123
|
+
|
124
|
+
tr_ratecontrol_t * globalUpload;
|
125
|
+
tr_ratecontrol_t * globalDownload;
|
126
|
+
tr_ratecontrol_t * upload;
|
127
|
+
tr_ratecontrol_t * download;
|
128
|
+
tr_fd_t * fdlimit;
|
129
|
+
|
130
|
+
int status;
|
131
|
+
int error;
|
132
|
+
char trackerError[128];
|
133
|
+
int finished;
|
134
|
+
|
135
|
+
char * id;
|
136
|
+
char * key;
|
137
|
+
int * bindPort;
|
138
|
+
|
139
|
+
/* An escaped string used to include the hash in HTTP queries */
|
140
|
+
char hashString[3*SHA_DIGEST_LENGTH+1];
|
141
|
+
|
142
|
+
char scrape[MAX_PATH_LENGTH];
|
143
|
+
|
144
|
+
/* Where to download */
|
145
|
+
char * destination;
|
146
|
+
|
147
|
+
/* How many bytes we ask for per request */
|
148
|
+
int blockSize;
|
149
|
+
int blockCount;
|
150
|
+
|
151
|
+
tr_completion_t * completion;
|
152
|
+
|
153
|
+
volatile char die;
|
154
|
+
tr_thread_t thread;
|
155
|
+
tr_lock_t lock;
|
156
|
+
|
157
|
+
tr_tracker_t * tracker;
|
158
|
+
tr_io_t * io;
|
159
|
+
uint64_t stopDate;
|
160
|
+
|
161
|
+
int peerCount;
|
162
|
+
tr_peer_t * peers[TR_MAX_PEER_COUNT];
|
163
|
+
|
164
|
+
uint64_t date;
|
165
|
+
uint64_t downloaded;
|
166
|
+
uint64_t uploaded;
|
167
|
+
|
168
|
+
tr_stat_t stats[2];
|
169
|
+
int statCur;
|
170
|
+
|
171
|
+
tr_torrent_t * prev;
|
172
|
+
tr_torrent_t * next;
|
173
|
+
};
|
174
|
+
|
175
|
+
#include "utils.h"
|
176
|
+
#include "completion.h"
|
177
|
+
|
178
|
+
struct tr_handle_s
|
179
|
+
{
|
180
|
+
int torrentCount;
|
181
|
+
tr_torrent_t * torrentList;
|
182
|
+
|
183
|
+
tr_ratecontrol_t * upload;
|
184
|
+
tr_ratecontrol_t * download;
|
185
|
+
tr_fd_t * fdlimit;
|
186
|
+
tr_choking_t * choking;
|
187
|
+
|
188
|
+
int bindPort;
|
189
|
+
int bindSocket;
|
190
|
+
|
191
|
+
int acceptPeerCount;
|
192
|
+
tr_peer_t * acceptPeers[TR_MAX_PEER_COUNT];
|
193
|
+
|
194
|
+
char id[21];
|
195
|
+
char key[21];
|
196
|
+
|
197
|
+
volatile char acceptDie;
|
198
|
+
tr_thread_t acceptThread;
|
199
|
+
tr_lock_t acceptLock;
|
200
|
+
};
|
201
|
+
|
202
|
+
#endif
|
data/ext/metainfo.c
ADDED
@@ -0,0 +1,339 @@
|
|
1
|
+
/******************************************************************************
|
2
|
+
* $Id: metainfo.c 405 2006-06-20 02:34:34Z titer $
|
3
|
+
*
|
4
|
+
* Copyright (c) 2005-2006 Transmission authors and contributors
|
5
|
+
*
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a
|
7
|
+
* copy of this software and associated documentation files (the "Software"),
|
8
|
+
* to deal in the Software without restriction, including without limitation
|
9
|
+
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
10
|
+
* and/or sell copies of the Software, and to permit persons to whom the
|
11
|
+
* Software is furnished to do so, subject to the following conditions:
|
12
|
+
*
|
13
|
+
* The above copyright notice and this permission notice shall be included in
|
14
|
+
* all copies or substantial portions of the Software.
|
15
|
+
*
|
16
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
22
|
+
* DEALINGS IN THE SOFTWARE.
|
23
|
+
*****************************************************************************/
|
24
|
+
|
25
|
+
#include "transmission.h"
|
26
|
+
|
27
|
+
/***********************************************************************
|
28
|
+
* Local prototypes
|
29
|
+
**********************************************************************/
|
30
|
+
static void strcatUTF8( char *, char * );
|
31
|
+
|
32
|
+
/***********************************************************************
|
33
|
+
* tr_metainfoParse
|
34
|
+
***********************************************************************
|
35
|
+
*
|
36
|
+
**********************************************************************/
|
37
|
+
int tr_metainfoParse( tr_info_t * inf, const char * path,
|
38
|
+
const char * savedHash, int saveCopy )
|
39
|
+
{
|
40
|
+
FILE * file;
|
41
|
+
char * buf;
|
42
|
+
benc_val_t meta, * beInfo, * list, * val;
|
43
|
+
char * s, * s2, * s3;
|
44
|
+
int i;
|
45
|
+
struct stat sb;
|
46
|
+
|
47
|
+
assert( NULL == path || NULL == savedHash );
|
48
|
+
/* if savedHash isn't null, saveCopy should be false */
|
49
|
+
assert( NULL == savedHash || !saveCopy );
|
50
|
+
|
51
|
+
if ( NULL != savedHash )
|
52
|
+
{
|
53
|
+
snprintf( inf->torrent, MAX_PATH_LENGTH, "%s/%s",
|
54
|
+
tr_getTorrentsDirectory(), savedHash );
|
55
|
+
path = inf->torrent;
|
56
|
+
}
|
57
|
+
|
58
|
+
if( stat( path, &sb ) )
|
59
|
+
{
|
60
|
+
/* fprintf( stderr, "Could not stat file (%s)\n", path );*/
|
61
|
+
return TR_PARSE_STAT;
|
62
|
+
}
|
63
|
+
if( ( sb.st_mode & S_IFMT ) != S_IFREG )
|
64
|
+
{
|
65
|
+
/* fprintf( stderr, "Not a regular file (%s)\n", path );*/
|
66
|
+
return TR_PARSE_FILE_TYPE;
|
67
|
+
}
|
68
|
+
if( sb.st_size > 2097152 )
|
69
|
+
{
|
70
|
+
/* tr_err( "Torrent file is too big (%d bytes)", sb.st_size );*/
|
71
|
+
return TR_PARSE_TOO_BIG;
|
72
|
+
}
|
73
|
+
|
74
|
+
/* Load the torrent file into our buffer */
|
75
|
+
file = fopen( path, "rb" );
|
76
|
+
if( !file )
|
77
|
+
{
|
78
|
+
/* fprintf( stderr, "Could not open file (%s)\n", path );*/
|
79
|
+
return TR_PARSE_FILE;
|
80
|
+
}
|
81
|
+
buf = malloc( sb.st_size );
|
82
|
+
fseek( file, 0, SEEK_SET );
|
83
|
+
if( fread( buf, sb.st_size, 1, file ) != 1 )
|
84
|
+
{
|
85
|
+
/* fprintf( stderr, "Read error (%s)\n", path );*/
|
86
|
+
free( buf );
|
87
|
+
fclose( file );
|
88
|
+
return TR_PARSE_READ;
|
89
|
+
}
|
90
|
+
fclose( file );
|
91
|
+
|
92
|
+
/* Parse bencoded infos */
|
93
|
+
if( tr_bencLoad( buf, sb.st_size, &meta, NULL ) )
|
94
|
+
{
|
95
|
+
/* fprintf( stderr, "Error while parsing bencoded data\n" );*/
|
96
|
+
free( buf );
|
97
|
+
return TR_PARSE_BENCODE;
|
98
|
+
}
|
99
|
+
|
100
|
+
/* Get info hash */
|
101
|
+
if( !( beInfo = tr_bencDictFind( &meta, "info" ) ) )
|
102
|
+
{
|
103
|
+
/* fprintf( stderr, "Could not find \"info\" dictionary\n" );*/
|
104
|
+
tr_bencFree( &meta );
|
105
|
+
free( buf );
|
106
|
+
return TR_PARSE_INFO_DIR;
|
107
|
+
}
|
108
|
+
SHA1( (uint8_t *) beInfo->begin,
|
109
|
+
(long) beInfo->end - (long) beInfo->begin, inf->hash );
|
110
|
+
for( i = 0; i < SHA_DIGEST_LENGTH; i++ )
|
111
|
+
{
|
112
|
+
sprintf( inf->hashString + i * 2, "%02x", inf->hash[i] );
|
113
|
+
}
|
114
|
+
|
115
|
+
if( saveCopy )
|
116
|
+
{
|
117
|
+
/* Save a copy of the torrent file in the private torrent directory */
|
118
|
+
snprintf( inf->torrent, MAX_PATH_LENGTH, "%s/%s",
|
119
|
+
tr_getTorrentsDirectory(), inf->hashString );
|
120
|
+
file = fopen( inf->torrent, "wb" );
|
121
|
+
if( !file )
|
122
|
+
{
|
123
|
+
/* fprintf( stderr, "Could not open file (%s) (%s)\n", inf->torrent, strerror(errno) );*/
|
124
|
+
tr_bencFree( &meta );
|
125
|
+
free( buf );
|
126
|
+
return TR_PARSE_FILE;
|
127
|
+
}
|
128
|
+
fseek( file, 0, SEEK_SET );
|
129
|
+
if( fwrite( buf, sb.st_size, 1, file ) != 1 )
|
130
|
+
{
|
131
|
+
/* fprintf( stderr, "Write error (%s)\n", inf->torrent );*/
|
132
|
+
tr_bencFree( &meta );
|
133
|
+
free( buf );
|
134
|
+
fclose( file );
|
135
|
+
return TR_PARSE_WRITE;
|
136
|
+
}
|
137
|
+
fclose( file );
|
138
|
+
}
|
139
|
+
else
|
140
|
+
{
|
141
|
+
snprintf( inf->torrent, MAX_PATH_LENGTH, "%s", path );
|
142
|
+
}
|
143
|
+
|
144
|
+
/* We won't need this anymore */
|
145
|
+
free( buf );
|
146
|
+
|
147
|
+
if( !( val = tr_bencDictFind( &meta, "announce" ) ) )
|
148
|
+
{
|
149
|
+
/* fprintf( stderr, "No \"announce\" entry\n" );*/
|
150
|
+
tr_bencFree( &meta );
|
151
|
+
return TR_PARSE_ANN;
|
152
|
+
}
|
153
|
+
|
154
|
+
/* Skip spaces */
|
155
|
+
s3 = val->val.s.s;
|
156
|
+
while( *s3 && *s3 == ' ' )
|
157
|
+
{
|
158
|
+
s3++;
|
159
|
+
}
|
160
|
+
|
161
|
+
/* Parse announce URL */
|
162
|
+
if( strncmp( s3, "http://", 7 ) )
|
163
|
+
{
|
164
|
+
/* fprintf( stderr, "Invalid announce URL (%s)\n",
|
165
|
+
inf->trackerAddress );
|
166
|
+
*/
|
167
|
+
tr_bencFree( &meta );
|
168
|
+
return TR_PARSE_ANN_URL;
|
169
|
+
}
|
170
|
+
s = strchr( s3 + 7, ':' );
|
171
|
+
s2 = strchr( s3 + 7, '/' );
|
172
|
+
if( s && s < s2 )
|
173
|
+
{
|
174
|
+
memcpy( inf->trackerAddress, s3 + 7,
|
175
|
+
(long) s - (long) s3 - 7 );
|
176
|
+
inf->trackerPort = atoi( s + 1 );
|
177
|
+
}
|
178
|
+
else if( s2 )
|
179
|
+
{
|
180
|
+
memcpy( inf->trackerAddress, s3 + 7,
|
181
|
+
(long) s2 - (long) s3 - 7 );
|
182
|
+
inf->trackerPort = 80;
|
183
|
+
}
|
184
|
+
else
|
185
|
+
{
|
186
|
+
/* fprintf( stderr, "Invalid announce URL (%s)\n",
|
187
|
+
inf->trackerAddress );*/
|
188
|
+
tr_bencFree( &meta );
|
189
|
+
return TR_PARSE_ANN_URL;
|
190
|
+
}
|
191
|
+
snprintf( inf->trackerAnnounce, MAX_PATH_LENGTH, "%s", s2 );
|
192
|
+
|
193
|
+
/* Piece length */
|
194
|
+
if( !( val = tr_bencDictFind( beInfo, "piece length" ) ) )
|
195
|
+
{
|
196
|
+
/* fprintf( stderr, "No \"piece length\" entry\n" );*/
|
197
|
+
tr_bencFree( &meta );
|
198
|
+
return TR_PARSE_PIECE;
|
199
|
+
}
|
200
|
+
inf->pieceSize = val->val.i;
|
201
|
+
|
202
|
+
/* Hashes */
|
203
|
+
val = tr_bencDictFind( beInfo, "pieces" );
|
204
|
+
if( val->val.s.i % SHA_DIGEST_LENGTH )
|
205
|
+
{
|
206
|
+
/* fprintf( stderr, "Invalid \"piece\" string (size is %d)\n",*/
|
207
|
+
/* val->val.s.i );*/
|
208
|
+
return TR_PARSE_PIECE;
|
209
|
+
}
|
210
|
+
inf->pieceCount = val->val.s.i / SHA_DIGEST_LENGTH;
|
211
|
+
inf->pieces = (uint8_t *) val->val.s.s; /* Ugly, but avoids a memcpy */
|
212
|
+
val->val.s.s = NULL;
|
213
|
+
|
214
|
+
/* TODO add more tests so we don't crash on weird files */
|
215
|
+
|
216
|
+
inf->totalSize = 0;
|
217
|
+
if( ( list = tr_bencDictFind( beInfo, "files" ) ) )
|
218
|
+
{
|
219
|
+
/* Multi-file mode */
|
220
|
+
int j;
|
221
|
+
|
222
|
+
val = tr_bencDictFind( beInfo, "name" );
|
223
|
+
strcatUTF8( inf->name, val->val.s.s );
|
224
|
+
|
225
|
+
inf->multifile = 1;
|
226
|
+
inf->fileCount = list->val.l.count;
|
227
|
+
inf->files = calloc( inf->fileCount * sizeof( tr_file_t ), 1 );
|
228
|
+
|
229
|
+
for( i = 0; i < list->val.l.count; i++ )
|
230
|
+
{
|
231
|
+
val = tr_bencDictFind( &list->val.l.vals[i], "path" );
|
232
|
+
strcatUTF8( inf->files[i].name, inf->name );
|
233
|
+
for( j = 0; j < val->val.l.count; j++ )
|
234
|
+
{
|
235
|
+
strcatUTF8( inf->files[i].name, "/" );
|
236
|
+
strcatUTF8( inf->files[i].name,
|
237
|
+
val->val.l.vals[j].val.s.s );
|
238
|
+
}
|
239
|
+
val = tr_bencDictFind( &list->val.l.vals[i], "length" );
|
240
|
+
inf->files[i].length = val->val.i;
|
241
|
+
inf->totalSize += val->val.i;
|
242
|
+
}
|
243
|
+
|
244
|
+
}
|
245
|
+
else
|
246
|
+
{
|
247
|
+
/* Single-file mode */
|
248
|
+
inf->multifile = 0;
|
249
|
+
inf->fileCount = 1;
|
250
|
+
inf->files = calloc( sizeof( tr_file_t ), 1 );
|
251
|
+
|
252
|
+
val = tr_bencDictFind( beInfo, "name" );
|
253
|
+
strcatUTF8( inf->files[0].name, val->val.s.s );
|
254
|
+
strcatUTF8( inf->name, val->val.s.s );
|
255
|
+
|
256
|
+
val = tr_bencDictFind( beInfo, "length" );
|
257
|
+
inf->files[0].length = val->val.i;
|
258
|
+
inf->totalSize += val->val.i;
|
259
|
+
}
|
260
|
+
|
261
|
+
if( (uint64_t) inf->pieceCount !=
|
262
|
+
( inf->totalSize + inf->pieceSize - 1 ) / inf->pieceSize )
|
263
|
+
{
|
264
|
+
/* fprintf( stderr, "Size of hashes and files don't match\n" );*/
|
265
|
+
tr_bencFree( &meta );
|
266
|
+
return TR_PARSE_HASH;
|
267
|
+
}
|
268
|
+
|
269
|
+
tr_bencFree( &meta );
|
270
|
+
return 0;
|
271
|
+
}
|
272
|
+
|
273
|
+
void tr_metainfoRemoveSaved( const char * hashString )
|
274
|
+
{
|
275
|
+
char file[MAX_PATH_LENGTH];
|
276
|
+
|
277
|
+
snprintf( file, MAX_PATH_LENGTH, "%s/%s",
|
278
|
+
tr_getTorrentsDirectory(), hashString );
|
279
|
+
unlink(file);
|
280
|
+
}
|
281
|
+
|
282
|
+
/***********************************************************************
|
283
|
+
* strcatUTF8
|
284
|
+
***********************************************************************
|
285
|
+
* According to the official specification, all strings in the torrent
|
286
|
+
* file are supposed to be UTF-8 encoded. However, there are
|
287
|
+
* non-compliant torrents around... If we encounter an invalid UTF-8
|
288
|
+
* character, we assume it is ISO 8859-1 and convert it to UTF-8.
|
289
|
+
**********************************************************************/
|
290
|
+
static void strcatUTF8( char * s, char * append )
|
291
|
+
{
|
292
|
+
char * p;
|
293
|
+
|
294
|
+
/* Go to the end of the destination string */
|
295
|
+
while( s[0] )
|
296
|
+
{
|
297
|
+
s++;
|
298
|
+
}
|
299
|
+
|
300
|
+
/* Now start appending, converting on the fly if necessary */
|
301
|
+
for( p = append; p[0]; )
|
302
|
+
{
|
303
|
+
if( !( p[0] & 0x80 ) )
|
304
|
+
{
|
305
|
+
/* ASCII character */
|
306
|
+
*(s++) = *(p++);
|
307
|
+
continue;
|
308
|
+
}
|
309
|
+
|
310
|
+
if( ( p[0] & 0xE0 ) == 0xC0 && ( p[1] & 0xC0 ) == 0x80 )
|
311
|
+
{
|
312
|
+
/* 2-bytes UTF-8 character */
|
313
|
+
*(s++) = *(p++); *(s++) = *(p++);
|
314
|
+
continue;
|
315
|
+
}
|
316
|
+
|
317
|
+
if( ( p[0] & 0xF0 ) == 0xE0 && ( p[1] & 0xC0 ) == 0x80 &&
|
318
|
+
( p[2] & 0xC0 ) == 0x80 )
|
319
|
+
{
|
320
|
+
/* 3-bytes UTF-8 character */
|
321
|
+
*(s++) = *(p++); *(s++) = *(p++);
|
322
|
+
*(s++) = *(p++);
|
323
|
+
continue;
|
324
|
+
}
|
325
|
+
|
326
|
+
if( ( p[0] & 0xF8 ) == 0xF0 && ( p[1] & 0xC0 ) == 0x80 &&
|
327
|
+
( p[2] & 0xC0 ) == 0x80 && ( p[3] & 0xC0 ) == 0x80 )
|
328
|
+
{
|
329
|
+
/* 4-bytes UTF-8 character */
|
330
|
+
*(s++) = *(p++); *(s++) = *(p++);
|
331
|
+
*(s++) = *(p++); *(s++) = *(p++);
|
332
|
+
continue;
|
333
|
+
}
|
334
|
+
|
335
|
+
/* ISO 8859-1 -> UTF-8 conversion */
|
336
|
+
*(s++) = 0xC0 | ( ( *p & 0xFF ) >> 6 );
|
337
|
+
*(s++) = 0x80 | ( *(p++) & 0x3F );
|
338
|
+
}
|
339
|
+
}
|