transmission 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/peerutils.h
ADDED
@@ -0,0 +1,394 @@
|
|
1
|
+
/******************************************************************************
|
2
|
+
* $Id: peerutils.h 261 2006-05-29 21:27:31Z 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
|
+
static void updateInterest( tr_torrent_t * tor, tr_peer_t * peer );
|
26
|
+
|
27
|
+
/***********************************************************************
|
28
|
+
* peerInit
|
29
|
+
***********************************************************************
|
30
|
+
* Allocates a new tr_peer_t and returns a pointer to it.
|
31
|
+
**********************************************************************/
|
32
|
+
static tr_peer_t * peerInit()
|
33
|
+
{
|
34
|
+
tr_peer_t * peer;
|
35
|
+
|
36
|
+
peer = calloc( sizeof( tr_peer_t ), 1 );
|
37
|
+
peer->amChoking = 1;
|
38
|
+
peer->peerChoking = 1;
|
39
|
+
peer->date = tr_date();
|
40
|
+
peer->keepAlive = peer->date;
|
41
|
+
peer->download = tr_rcInit();
|
42
|
+
|
43
|
+
return peer;
|
44
|
+
}
|
45
|
+
|
46
|
+
/***********************************************************************
|
47
|
+
* peerAttach
|
48
|
+
***********************************************************************
|
49
|
+
* Deallocates the tr_peer_t and returns 0 if we reached the maximum
|
50
|
+
* authorized number of peers. Otherwise, adds the tr_peer_t to the
|
51
|
+
* peers list.
|
52
|
+
**********************************************************************/
|
53
|
+
static int peerAttach( tr_torrent_t * tor, tr_peer_t * peer )
|
54
|
+
{
|
55
|
+
if( tor->peerCount >= TR_MAX_PEER_COUNT )
|
56
|
+
{
|
57
|
+
tr_peerDestroy( tor->fdlimit, peer );
|
58
|
+
return 0;
|
59
|
+
}
|
60
|
+
|
61
|
+
tor->peers[tor->peerCount++] = peer;
|
62
|
+
return 1;
|
63
|
+
}
|
64
|
+
|
65
|
+
static int peerCmp( tr_peer_t * peer1, tr_peer_t * peer2 )
|
66
|
+
{
|
67
|
+
/* Wait until we got the peers' ids */
|
68
|
+
if( peer1->status < PEER_STATUS_CONNECTED ||
|
69
|
+
peer2->status < PEER_STATUS_CONNECTED )
|
70
|
+
{
|
71
|
+
return 1;
|
72
|
+
}
|
73
|
+
|
74
|
+
return memcmp( peer1->id, peer2->id, 20 );
|
75
|
+
}
|
76
|
+
|
77
|
+
/***********************************************************************
|
78
|
+
* addWithAddr
|
79
|
+
***********************************************************************
|
80
|
+
* Does nothing if we already have a peer matching 'addr' and 'port'.
|
81
|
+
* Otherwise adds such a new peer.
|
82
|
+
**********************************************************************/
|
83
|
+
static void addWithAddr( tr_torrent_t * tor, struct in_addr addr,
|
84
|
+
in_port_t port )
|
85
|
+
{
|
86
|
+
int i;
|
87
|
+
tr_peer_t * peer;
|
88
|
+
|
89
|
+
for( i = 0; i < tor->peerCount; i++ )
|
90
|
+
{
|
91
|
+
peer = tor->peers[i];
|
92
|
+
if( peer->addr.s_addr == addr.s_addr &&
|
93
|
+
peer->port == port )
|
94
|
+
{
|
95
|
+
/* We are already connected to this peer */
|
96
|
+
return;
|
97
|
+
}
|
98
|
+
}
|
99
|
+
|
100
|
+
peer = peerInit();
|
101
|
+
if( !peerAttach( tor, peer ) )
|
102
|
+
{
|
103
|
+
return;
|
104
|
+
}
|
105
|
+
|
106
|
+
peer->addr = addr;
|
107
|
+
peer->port = port;
|
108
|
+
peer->status = PEER_STATUS_IDLE;
|
109
|
+
}
|
110
|
+
|
111
|
+
static int checkPeer( tr_torrent_t * tor, int i )
|
112
|
+
{
|
113
|
+
tr_peer_t * peer = tor->peers[i];
|
114
|
+
|
115
|
+
if( peer->status < PEER_STATUS_CONNECTED &&
|
116
|
+
tr_date() > peer->date + 8000 )
|
117
|
+
{
|
118
|
+
/* If it has been too long, don't wait for the socket
|
119
|
+
to timeout - forget about it now */
|
120
|
+
peer_dbg( "connection timeout" );
|
121
|
+
return 1;
|
122
|
+
}
|
123
|
+
|
124
|
+
/* Drop peers who haven't even sent a keep-alive within the
|
125
|
+
last 3 minutes */
|
126
|
+
if( tr_date() > peer->date + 180000 )
|
127
|
+
{
|
128
|
+
peer_dbg( "read timeout" );
|
129
|
+
return 1;
|
130
|
+
}
|
131
|
+
|
132
|
+
/* Drop peers which are supposed to upload but actually
|
133
|
+
haven't sent anything within the last minute */
|
134
|
+
if( peer->inRequestCount && tr_date() > peer->date + 60000 )
|
135
|
+
{
|
136
|
+
peer_dbg( "bad uploader" );
|
137
|
+
return 1;
|
138
|
+
}
|
139
|
+
|
140
|
+
if( peer->status & PEER_STATUS_CONNECTED )
|
141
|
+
{
|
142
|
+
/* Send keep-alive every 2 minutes */
|
143
|
+
if( tr_date() > peer->keepAlive + 120000 )
|
144
|
+
{
|
145
|
+
sendKeepAlive( peer );
|
146
|
+
peer->keepAlive = tr_date();
|
147
|
+
}
|
148
|
+
}
|
149
|
+
|
150
|
+
/* Connect */
|
151
|
+
if( ( peer->status & PEER_STATUS_IDLE ) &&
|
152
|
+
!tr_fdSocketWillCreate( tor->fdlimit, 0 ) )
|
153
|
+
{
|
154
|
+
peer->socket = tr_netOpen( peer->addr, peer->port );
|
155
|
+
if( peer->socket < 0 )
|
156
|
+
{
|
157
|
+
peer_dbg( "connection failed" );
|
158
|
+
tr_fdSocketClosed( tor->fdlimit, 0 );
|
159
|
+
return 1;
|
160
|
+
}
|
161
|
+
peer->status = PEER_STATUS_CONNECTING;
|
162
|
+
}
|
163
|
+
|
164
|
+
/* Try to send handshake */
|
165
|
+
if( peer->status & PEER_STATUS_CONNECTING )
|
166
|
+
{
|
167
|
+
uint8_t buf[68];
|
168
|
+
tr_info_t * inf = &tor->info;
|
169
|
+
int ret;
|
170
|
+
|
171
|
+
buf[0] = 19;
|
172
|
+
memcpy( &buf[1], "BitTorrent protocol", 19 );
|
173
|
+
memset( &buf[20], 0, 8 );
|
174
|
+
memcpy( &buf[28], inf->hash, 20 );
|
175
|
+
memcpy( &buf[48], tor->id, 20 );
|
176
|
+
|
177
|
+
ret = tr_netSend( peer->socket, buf, 68 );
|
178
|
+
if( ret & TR_NET_CLOSE )
|
179
|
+
{
|
180
|
+
peer_dbg( "connection closed" );
|
181
|
+
return 1;
|
182
|
+
}
|
183
|
+
else if( !( ret & TR_NET_BLOCK ) )
|
184
|
+
{
|
185
|
+
peer_dbg( "SEND handshake" );
|
186
|
+
peer->status = PEER_STATUS_HANDSHAKE;
|
187
|
+
}
|
188
|
+
}
|
189
|
+
|
190
|
+
return 0;
|
191
|
+
}
|
192
|
+
|
193
|
+
/***********************************************************************
|
194
|
+
* isInteresting
|
195
|
+
***********************************************************************
|
196
|
+
* Returns 1 if 'peer' has at least one piece that we haven't completed,
|
197
|
+
* or 0 otherwise.
|
198
|
+
**********************************************************************/
|
199
|
+
static int isInteresting( tr_torrent_t * tor, tr_peer_t * peer )
|
200
|
+
{
|
201
|
+
tr_info_t * inf = &tor->info;
|
202
|
+
|
203
|
+
int i;
|
204
|
+
int bitfieldSize = ( inf->pieceCount + 7 ) / 8;
|
205
|
+
uint8_t * bitfield = tr_cpPieceBitfield( tor->completion );
|
206
|
+
|
207
|
+
if( !peer->bitfield )
|
208
|
+
{
|
209
|
+
/* We don't know what this peer has */
|
210
|
+
return 0;
|
211
|
+
}
|
212
|
+
|
213
|
+
for( i = 0; i < bitfieldSize; i++ )
|
214
|
+
{
|
215
|
+
if( ( peer->bitfield[i] & ~(bitfield[i]) ) & 0xFF )
|
216
|
+
{
|
217
|
+
return 1;
|
218
|
+
}
|
219
|
+
}
|
220
|
+
|
221
|
+
return 0;
|
222
|
+
}
|
223
|
+
static void updateInterest( tr_torrent_t * tor, tr_peer_t * peer )
|
224
|
+
{
|
225
|
+
int interested = isInteresting( tor, peer );
|
226
|
+
|
227
|
+
if( interested && !peer->amInterested )
|
228
|
+
{
|
229
|
+
sendInterest( peer, 1 );
|
230
|
+
}
|
231
|
+
if( !interested && peer->amInterested )
|
232
|
+
{
|
233
|
+
sendInterest( peer, 0 );
|
234
|
+
}
|
235
|
+
}
|
236
|
+
|
237
|
+
/***********************************************************************
|
238
|
+
* chooseBlock
|
239
|
+
***********************************************************************
|
240
|
+
* At this point, we know the peer has at least one block we have an
|
241
|
+
* interest in. If he has more than one, we choose which one we are
|
242
|
+
* going to ask first.
|
243
|
+
* Our main goal is to complete pieces, so we look the pieces which are
|
244
|
+
* missing less blocks.
|
245
|
+
**********************************************************************/
|
246
|
+
static inline int chooseBlock( tr_torrent_t * tor, tr_peer_t * peer )
|
247
|
+
{
|
248
|
+
tr_info_t * inf = &tor->info;
|
249
|
+
|
250
|
+
int i;
|
251
|
+
int missingBlocks, minMissing;
|
252
|
+
int poolSize, * pool;
|
253
|
+
int block, minDownloading;
|
254
|
+
|
255
|
+
/* Choose a piece */
|
256
|
+
pool = malloc( inf->pieceCount * sizeof( int ) );
|
257
|
+
poolSize = 0;
|
258
|
+
minMissing = tor->blockCount + 1;
|
259
|
+
for( i = 0; i < inf->pieceCount; i++ )
|
260
|
+
{
|
261
|
+
missingBlocks = tr_cpMissingBlocksForPiece( tor->completion, i );
|
262
|
+
if( missingBlocks < 1 )
|
263
|
+
{
|
264
|
+
/* We already have or are downloading all blocks */
|
265
|
+
continue;
|
266
|
+
}
|
267
|
+
if( !tr_bitfieldHas( peer->bitfield, i ) )
|
268
|
+
{
|
269
|
+
/* The peer doesn't have this piece */
|
270
|
+
continue;
|
271
|
+
}
|
272
|
+
if( peer->banfield && tr_bitfieldHas( peer->banfield, i ) )
|
273
|
+
{
|
274
|
+
/* The peer is banned for this piece */
|
275
|
+
continue;
|
276
|
+
}
|
277
|
+
|
278
|
+
/* We are interested in this piece, remember it */
|
279
|
+
if( missingBlocks < minMissing )
|
280
|
+
{
|
281
|
+
minMissing = missingBlocks;
|
282
|
+
poolSize = 0;
|
283
|
+
}
|
284
|
+
if( missingBlocks <= minMissing )
|
285
|
+
{
|
286
|
+
pool[poolSize++] = i;
|
287
|
+
}
|
288
|
+
}
|
289
|
+
|
290
|
+
if( poolSize )
|
291
|
+
{
|
292
|
+
/* All pieces in 'pool' have 'minMissing' missing blocks. Find
|
293
|
+
the rarest ones. */
|
294
|
+
uint8_t * bitfield;
|
295
|
+
int piece;
|
296
|
+
int min, foo, j;
|
297
|
+
int * pool2;
|
298
|
+
int pool2Size;
|
299
|
+
|
300
|
+
pool2 = malloc( poolSize * sizeof( int ) );
|
301
|
+
pool2Size = 0;
|
302
|
+
min = TR_MAX_PEER_COUNT + 1;
|
303
|
+
for( i = 0; i < poolSize; i++ )
|
304
|
+
{
|
305
|
+
foo = 0;
|
306
|
+
for( j = 0; j < tor->peerCount; j++ )
|
307
|
+
{
|
308
|
+
bitfield = tor->peers[j]->bitfield;
|
309
|
+
if( bitfield && tr_bitfieldHas( bitfield, pool[i] ) )
|
310
|
+
{
|
311
|
+
foo++;
|
312
|
+
}
|
313
|
+
}
|
314
|
+
if( foo < min )
|
315
|
+
{
|
316
|
+
min = foo;
|
317
|
+
pool2Size = 0;
|
318
|
+
}
|
319
|
+
if( foo <= min )
|
320
|
+
{
|
321
|
+
pool2[pool2Size++] = pool[i];
|
322
|
+
}
|
323
|
+
}
|
324
|
+
free( pool );
|
325
|
+
|
326
|
+
if( pool2Size < 1 )
|
327
|
+
{
|
328
|
+
/* Shouldn't happen */
|
329
|
+
free( pool2 );
|
330
|
+
return -1;
|
331
|
+
}
|
332
|
+
|
333
|
+
/* All pieces in pool2 have the same number of missing blocks,
|
334
|
+
and are availabme from the same number of peers. Pick a
|
335
|
+
random one */
|
336
|
+
piece = pool2[tr_rand(pool2Size)];
|
337
|
+
free( pool2 );
|
338
|
+
|
339
|
+
/* Pick a block in this piece */
|
340
|
+
block = tr_cpMissingBlockInPiece( tor->completion, piece );
|
341
|
+
goto check;
|
342
|
+
}
|
343
|
+
|
344
|
+
free( pool );
|
345
|
+
|
346
|
+
/* "End game" mode */
|
347
|
+
minDownloading = 255;
|
348
|
+
block = -1;
|
349
|
+
for( i = 0; i < inf->pieceCount; i++ )
|
350
|
+
{
|
351
|
+
int downloaders, block2;
|
352
|
+
if( !tr_bitfieldHas( peer->bitfield, i ) )
|
353
|
+
{
|
354
|
+
/* The peer doesn't have this piece */
|
355
|
+
continue;
|
356
|
+
}
|
357
|
+
if( peer->banfield && tr_bitfieldHas( peer->banfield, i ) )
|
358
|
+
{
|
359
|
+
/* The peer is banned for this piece */
|
360
|
+
continue;
|
361
|
+
}
|
362
|
+
if( tr_cpPieceIsComplete( tor->completion, i ) )
|
363
|
+
{
|
364
|
+
/* We already have it */
|
365
|
+
continue;
|
366
|
+
}
|
367
|
+
block2 = tr_cpMostMissingBlockInPiece( tor->completion, i, &downloaders );
|
368
|
+
if( block2 > -1 && downloaders < minDownloading )
|
369
|
+
{
|
370
|
+
block = block2;
|
371
|
+
minDownloading = downloaders;
|
372
|
+
}
|
373
|
+
}
|
374
|
+
|
375
|
+
check:
|
376
|
+
if( block < 0 )
|
377
|
+
{
|
378
|
+
/* Shouldn't happen */
|
379
|
+
return -1;
|
380
|
+
}
|
381
|
+
|
382
|
+
for( i = 0; i < peer->inRequestCount; i++ )
|
383
|
+
{
|
384
|
+
tr_request_t * r;
|
385
|
+
r = &peer->inRequests[i];
|
386
|
+
if( tr_block( r->index, r->begin ) == block )
|
387
|
+
{
|
388
|
+
/* We are already asking this peer for this block */
|
389
|
+
return -1;
|
390
|
+
}
|
391
|
+
}
|
392
|
+
|
393
|
+
return block;
|
394
|
+
}
|
data/ext/platform.c
ADDED
@@ -0,0 +1,196 @@
|
|
1
|
+
/******************************************************************************
|
2
|
+
* $Id: platform.c 310 2006-06-09 19:53:35Z joshe $
|
3
|
+
*
|
4
|
+
* Copyright (c) 2005 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
|
+
#ifdef SYS_BEOS
|
26
|
+
#include <fs_info.h>
|
27
|
+
#include <FindDirectory.h>
|
28
|
+
#endif
|
29
|
+
#include <sys/types.h>
|
30
|
+
#include <dirent.h>
|
31
|
+
|
32
|
+
#include "transmission.h"
|
33
|
+
|
34
|
+
static void
|
35
|
+
tr_migrateResume( const char *oldDirectory, const char *newDirectory )
|
36
|
+
{
|
37
|
+
DIR * dirh;
|
38
|
+
struct dirent * dirp;
|
39
|
+
char oldFile[MAX_PATH_LENGTH];
|
40
|
+
char newFile[MAX_PATH_LENGTH];
|
41
|
+
|
42
|
+
if( ( dirh = opendir( oldDirectory ) ) )
|
43
|
+
{
|
44
|
+
while( ( dirp = readdir( dirh ) ) )
|
45
|
+
{
|
46
|
+
if( strncmp( "resume.", dirp->d_name, 7 ) )
|
47
|
+
{
|
48
|
+
continue;
|
49
|
+
}
|
50
|
+
snprintf( oldFile, MAX_PATH_LENGTH, "%s/%s",
|
51
|
+
oldDirectory, dirp->d_name );
|
52
|
+
snprintf( newFile, MAX_PATH_LENGTH, "%s/%s",
|
53
|
+
newDirectory, dirp->d_name );
|
54
|
+
rename( oldFile, newFile );
|
55
|
+
}
|
56
|
+
|
57
|
+
closedir( dirh );
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
char * tr_getPrefsDirectory()
|
62
|
+
{
|
63
|
+
static char prefsDirectory[MAX_PATH_LENGTH];
|
64
|
+
static int init = 0;
|
65
|
+
|
66
|
+
if( init )
|
67
|
+
{
|
68
|
+
return prefsDirectory;
|
69
|
+
}
|
70
|
+
|
71
|
+
#ifdef SYS_BEOS
|
72
|
+
find_directory( B_USER_SETTINGS_DIRECTORY, dev_for_path("/boot"),
|
73
|
+
true, prefsDirectory, MAX_PATH_LENGTH );
|
74
|
+
strcat( prefsDirectory, "/Transmission" );
|
75
|
+
#elif defined( SYS_DARWIN )
|
76
|
+
snprintf( prefsDirectory, MAX_PATH_LENGTH,
|
77
|
+
"%s/Library/Caches/Transmission", getenv( "HOME" ) );
|
78
|
+
#else
|
79
|
+
snprintf( prefsDirectory, MAX_PATH_LENGTH, "%s/.transmission",
|
80
|
+
getenv( "HOME" ) );
|
81
|
+
#endif
|
82
|
+
|
83
|
+
tr_mkdir( prefsDirectory );
|
84
|
+
init = 1;
|
85
|
+
|
86
|
+
#ifdef SYS_DARWIN
|
87
|
+
char oldDirectory[MAX_PATH_LENGTH];
|
88
|
+
snprintf( oldDirectory, MAX_PATH_LENGTH, "%s/.transmission",
|
89
|
+
getenv( "HOME" ) );
|
90
|
+
tr_migrateResume( oldDirectory, prefsDirectory );
|
91
|
+
rmdir( oldDirectory );
|
92
|
+
#endif
|
93
|
+
|
94
|
+
return prefsDirectory;
|
95
|
+
}
|
96
|
+
|
97
|
+
char * tr_getCacheDirectory()
|
98
|
+
{
|
99
|
+
static char cacheDirectory[MAX_PATH_LENGTH];
|
100
|
+
static int init = 0;
|
101
|
+
|
102
|
+
if( init )
|
103
|
+
{
|
104
|
+
return cacheDirectory;
|
105
|
+
}
|
106
|
+
|
107
|
+
#ifdef SYS_BEOS
|
108
|
+
/* XXX hey Bryan, is this fine with you? */
|
109
|
+
snprintf( cacheDirectory, MAX_PATH_LENGTH, "%s/Cache",
|
110
|
+
tr_getPrefsDirectory() );
|
111
|
+
#elif defined( SYS_DARWIN )
|
112
|
+
snprintf( cacheDirectory, MAX_PATH_LENGTH, "%s",
|
113
|
+
tr_getPrefsDirectory() );
|
114
|
+
#else
|
115
|
+
snprintf( cacheDirectory, MAX_PATH_LENGTH, "%s/cache",
|
116
|
+
tr_getPrefsDirectory() );
|
117
|
+
#endif
|
118
|
+
|
119
|
+
tr_mkdir( cacheDirectory );
|
120
|
+
init = 1;
|
121
|
+
|
122
|
+
if( strcmp( tr_getPrefsDirectory(), cacheDirectory ) )
|
123
|
+
{
|
124
|
+
tr_migrateResume( tr_getPrefsDirectory(), cacheDirectory );
|
125
|
+
}
|
126
|
+
|
127
|
+
return cacheDirectory;
|
128
|
+
}
|
129
|
+
|
130
|
+
char * tr_getTorrentsDirectory()
|
131
|
+
{
|
132
|
+
static char torrentsDirectory[MAX_PATH_LENGTH];
|
133
|
+
static int init = 0;
|
134
|
+
|
135
|
+
if( init )
|
136
|
+
{
|
137
|
+
return torrentsDirectory;
|
138
|
+
}
|
139
|
+
|
140
|
+
#ifdef SYS_BEOS
|
141
|
+
/* XXX hey Bryan, is this fine with you? */
|
142
|
+
snprintf( torrentsDirectory, MAX_PATH_LENGTH, "%s/Torrents",
|
143
|
+
tr_getPrefsDirectory() );
|
144
|
+
#elif defined( SYS_DARWIN )
|
145
|
+
snprintf( torrentsDirectory, MAX_PATH_LENGTH,
|
146
|
+
"%s/Library/Application Support/Transmission/Torrents",
|
147
|
+
getenv( "HOME" ) );
|
148
|
+
#else
|
149
|
+
snprintf( torrentsDirectory, MAX_PATH_LENGTH, "%s/torrents",
|
150
|
+
tr_getPrefsDirectory() );
|
151
|
+
#endif
|
152
|
+
|
153
|
+
tr_mkdir( torrentsDirectory );
|
154
|
+
init = 1;
|
155
|
+
|
156
|
+
return torrentsDirectory;
|
157
|
+
}
|
158
|
+
|
159
|
+
void tr_threadCreate( tr_thread_t * t, void (*func)(void *), void * arg )
|
160
|
+
{
|
161
|
+
#ifdef SYS_BEOS
|
162
|
+
*t = spawn_thread( (void *) func, "torrent-tx", B_NORMAL_PRIORITY, arg );
|
163
|
+
resume_thread( *t );
|
164
|
+
#else
|
165
|
+
pthread_create( t, NULL, (void *) func, arg );
|
166
|
+
#endif
|
167
|
+
}
|
168
|
+
|
169
|
+
void tr_threadJoin( tr_thread_t * t )
|
170
|
+
{
|
171
|
+
#ifdef SYS_BEOS
|
172
|
+
long exit;
|
173
|
+
wait_for_thread( *t, &exit );
|
174
|
+
#else
|
175
|
+
pthread_join( *t, NULL );
|
176
|
+
#endif
|
177
|
+
}
|
178
|
+
|
179
|
+
void tr_lockInit( tr_lock_t * l )
|
180
|
+
{
|
181
|
+
#ifdef SYS_BEOS
|
182
|
+
*l = create_sem( 1, "" );
|
183
|
+
#else
|
184
|
+
pthread_mutex_init( l, NULL );
|
185
|
+
#endif
|
186
|
+
}
|
187
|
+
|
188
|
+
void tr_lockClose( tr_lock_t * l )
|
189
|
+
{
|
190
|
+
#ifdef SYS_BEOS
|
191
|
+
delete_sem( *l );
|
192
|
+
#else
|
193
|
+
pthread_mutex_destroy( l );
|
194
|
+
#endif
|
195
|
+
}
|
196
|
+
|