source: trunk/daemon/torrents.c @ 5579

Last change on this file since 5579 was 5579, checked in by charles, 14 years ago

#853: transmission-(daemon|gtk) segfault when querying status

  • Property svn:keywords set to Date Rev Author Id
File size: 20.3 KB
Line 
1/******************************************************************************
2 * $Id: torrents.c 5579 2008-04-10 19:02:24Z charles $
3 *
4 * Copyright (c) 2007 Joshua Elsasser
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 <sys/types.h>
26#include <sys/param.h>
27#include <sys/stat.h>
28#include <sys/time.h>
29#include <sys/uio.h>
30#include <assert.h>
31#include <ctype.h>
32#include <errno.h>
33#include <event.h>
34#include <fcntl.h>
35#include <time.h>
36#include <stddef.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <unistd.h>
41
42#include <libtransmission/bencode.h>
43#include <libtransmission/transmission.h>
44#include <libtransmission/trcompat.h>
45
46#include "bsdtree.h"
47#include "errors.h"
48#include "misc.h"
49#include "torrents.h"
50
51#define EXIT_TIMEOUT 10         /* how many seconds to wait on exit */
52#define TIMER_SECS   1          /* timer interval seconds */
53#define TIMER_USECS  0          /* timer interval microseconds */
54
55struct tor
56{
57    int             id;
58    uint8_t         hash[SHA_DIGEST_LENGTH];
59    tr_torrent    * tor;
60    RB_ENTRY( tor ) idlinks;
61    RB_ENTRY( tor ) hashlinks;
62};
63
64RB_HEAD( tortree, tor );
65RB_HEAD( hashtree, tor );
66
67static struct tor * opentor    ( const char *, const char *, uint8_t *, size_t,
68                                  const char * );
69static void         closetor   ( struct tor *, int );
70static void         starttimer ( int );
71static void         timerfunc  ( int, short, void * );
72static int          loadstate  ( void );
73static int          savestate  ( void );
74
75static struct event_base * gl_base      = NULL;
76static tr_handle         * gl_handle    = NULL;
77static struct tortree      gl_tree      = RB_INITIALIZER( &gl_tree );
78static struct hashtree     gl_hashes    = RB_INITIALIZER( &gl_hashes );
79static int                 gl_lastid    = 0;
80static struct event        gl_event;
81static time_t              gl_exiting   = 0;
82static int                 gl_exitval   = 0;
83static char                gl_state[MAXPATHLEN];
84static char                gl_newstate[MAXPATHLEN];
85
86static int                 gl_autostart = 1;
87static int                 gl_pex       = 1;
88static int                 gl_port      = TR_DEFAULT_PORT;
89static int                 gl_mapping   = 0;
90static int                 gl_uplimit   = -1;
91static int                 gl_downlimit = -1;
92static char                gl_dir[MAXPATHLEN];
93static tr_encryption_mode  gl_crypto    = TR_ENCRYPTION_PREFERRED;
94
95static int
96torhashcmp( struct tor * left, struct tor * right )
97{
98    return memcmp( left->hash, right->hash, sizeof left->hash );
99}
100
101RB_GENERATE_STATIC( hashtree, tor, hashlinks, torhashcmp )
102
103INTCMP_FUNC( toridcmp, tor, id )
104RB_GENERATE_STATIC( tortree, tor, idlinks, toridcmp )
105
106void
107torrent_init( struct event_base * base )
108{
109    assert( NULL == gl_handle && NULL == gl_base );
110
111    gl_base   = base;
112    gl_handle = tr_init( tr_getDefaultConfigDir(), "daemon" );
113
114    confpath( gl_state, sizeof gl_state, CONF_FILE_STATE, 0 );
115    strlcpy( gl_newstate, gl_state, sizeof gl_state );
116    strlcat( gl_newstate, ".new", sizeof gl_state );
117    absolutify( gl_dir, sizeof gl_dir, "." );
118
119    loadstate();
120}
121
122int
123torrent_add_file( const char * path, const char * dir, int autostart )
124{
125    struct tor * tor;
126
127    assert( NULL != gl_handle );
128    assert( !gl_exiting );
129
130    tor = opentor( path, NULL, NULL, 0, dir );
131    if( NULL == tor )
132    {
133        return -1;
134    }
135
136    if( 0 > autostart )
137    {
138        autostart = gl_autostart;
139    }
140    if( autostart )
141    {
142        tr_torrentStart( tor->tor );
143    }
144
145    savestate();
146
147    return tor->id;
148}
149
150int
151torrent_add_data( uint8_t * data, size_t size, const char * dir, int autostart )
152{
153    struct tor * tor;
154
155    assert( NULL != gl_handle );
156    assert( !gl_exiting );
157
158    tor = opentor( NULL, NULL, data, size, dir );
159    if( NULL == tor )
160    {
161        return -1;
162    }
163
164    if( 0 > autostart )
165    {
166        autostart = gl_autostart;
167    }
168    if( autostart )
169    {
170        tr_torrentStart( tor->tor );
171    }
172
173    savestate();
174
175    return tor->id;
176}
177
178static struct tor *
179idlookup( int id )
180{
181    struct tor * found = NULL;
182
183    if( gl_handle && !gl_exiting )
184    {
185        struct tor key;
186        memset( &key, 0, sizeof key );
187        key.id = id;
188        found = RB_FIND( tortree, &gl_tree, &key );
189    }
190
191    return found;
192}
193
194void
195torrent_start( int id )
196{
197    struct tor * tor = idlookup( id );
198    if( tor && !TR_STATUS_IS_ACTIVE( tr_torrentStat( tor->tor )->status ) ) {
199        tr_torrentStart( tor->tor );
200        savestate();
201    }
202
203}
204
205void
206torrent_stop( int id )
207{
208    struct tor * tor = idlookup( id );
209    if( tor && TR_STATUS_IS_ACTIVE( tr_torrentStat( tor->tor )->status ) ) {
210        tr_torrentStop( tor->tor );
211        savestate( );
212    }
213}
214
215void
216torrent_verify( int id )
217{
218    struct tor * tor = idlookup( id );
219    if( tor )
220        tr_torrentVerify( tor->tor );
221}
222
223void
224torrent_remove( int id )
225{
226    struct tor * tor = idlookup( id );
227    if( tor ) {
228        closetor( tor, 1 );
229        savestate();
230    }
231}
232
233tr_torrent *
234torrent_handle( int id )
235{
236    const struct tor * tor = idlookup( id );
237    return tor ? tor->tor : NULL;
238}
239   
240const tr_info *
241torrent_info( int id )
242{
243    return tr_torrentInfo( torrent_handle( id ) );
244}
245
246const tr_stat *
247torrent_stat( int id )
248{
249    return tr_torrentStat( torrent_handle( id ) );
250}
251
252static struct tor *
253hashlookup( const uint8_t * hash )
254{
255    struct tor key, * found;
256
257    memset( &key, 0, sizeof key );
258    memcpy( key.hash, hash, sizeof key.hash );
259    found = RB_FIND( hashtree, &gl_hashes, &key );
260
261    return found;
262}
263
264int
265torrent_lookup( const uint8_t * hashstr )
266{
267    uint8_t      hash[SHA_DIGEST_LENGTH];
268    size_t       ii;
269    struct tor * tor;
270    char         buf[3];
271
272    assert( NULL != gl_handle );
273    assert( !gl_exiting );
274
275    memset( buf, 0, sizeof buf );
276    for( ii = 0; sizeof( hash ) > ii; ii++ )
277    {
278        if( !isxdigit( hashstr[2*ii] ) || !isxdigit( hashstr[1+2*ii] ) )
279        {
280            return -1;
281        }
282        memcpy( buf, &hashstr[2*ii], 2 );
283        hash[ii] = strtol( buf, NULL, 16 );
284    }
285
286    tor = hashlookup( hash );
287    if( NULL == tor )
288    {
289        return -1;
290    }
291
292    return tor->id;
293}
294
295static struct tor *
296iterate( struct tor * tor )
297{
298    struct tor * next = NULL;
299
300    if( gl_handle && !gl_exiting )
301        next = tor ? RB_NEXT( tortree, &gl_tree, tor )
302                   : RB_MIN( tortree, &gl_tree );
303
304    return next;
305}
306
307void *
308torrent_iter( void * cur, int * id )
309{
310    struct tor * next = iterate( cur );
311    if( next )
312        *id = next->id;
313    return next;
314}
315
316void
317torrent_exit( int exitval )
318{
319    struct tor * tor;
320
321    assert( NULL != gl_handle );
322    assert( !gl_exiting );
323    gl_exiting = time( NULL );
324    gl_exitval = exitval;
325
326    RB_FOREACH( tor, tortree, &gl_tree )
327    {
328        closetor( tor, 0 );
329    }
330
331    tr_natTraversalEnable( gl_handle, 0 );
332    starttimer( 1 );
333}
334
335void
336torrent_set_autostart( int autostart )
337{
338    assert( NULL != gl_handle );
339    assert( !gl_exiting );
340    gl_autostart = autostart;
341    savestate();
342}
343
344int
345torrent_get_autostart( void )
346{
347    return gl_autostart;
348}
349
350void
351torrent_set_port( int port )
352{
353    assert( NULL != gl_handle );
354    assert( !gl_exiting );
355    if( 0 < port && 0xffff > port )
356    {
357        gl_port = port;
358        tr_setBindPort( gl_handle, port );
359        savestate();
360    }
361}
362
363int
364torrent_get_port( void )
365{
366    return gl_port;
367}
368
369void
370torrent_set_pex( int pex )
371{
372    assert( NULL != gl_handle );
373    assert( !gl_exiting );
374
375    if( gl_pex != pex )
376    {
377        gl_pex = pex;
378
379        tr_setPexEnabled( gl_handle, gl_pex );
380
381        savestate( );
382    }
383}
384
385int
386torrent_get_pex( void )
387{
388    return gl_pex;
389}
390
391void
392torrent_enable_port_mapping( int automap )
393{
394    assert( NULL != gl_handle );
395    assert( !gl_exiting );
396    gl_mapping = ( automap ? 1 : 0 );
397    tr_natTraversalEnable( gl_handle, gl_mapping );
398    savestate();
399}
400
401int
402torrent_get_port_mapping( void )
403{
404    return gl_mapping;
405}
406
407void
408torrent_set_uplimit( int uplimit )
409{
410    assert( NULL != gl_handle );
411    assert( !gl_exiting );
412    gl_uplimit = uplimit;
413    tr_setGlobalSpeedLimit   ( gl_handle, TR_UP, uplimit );
414    tr_setUseGlobalSpeedLimit( gl_handle, TR_UP, uplimit > 0 );
415    savestate();
416}
417
418int
419torrent_get_uplimit( void )
420{
421    return gl_uplimit;
422}
423
424void
425torrent_set_downlimit( int downlimit )
426{
427    assert( NULL != gl_handle );
428    assert( !gl_exiting );
429    gl_downlimit = downlimit;
430    tr_setGlobalSpeedLimit   ( gl_handle, TR_DOWN, downlimit );
431    tr_setUseGlobalSpeedLimit( gl_handle, TR_DOWN, downlimit > 0 );
432    savestate();
433}
434
435int
436torrent_get_downlimit( void )
437{
438    return gl_downlimit;
439}
440
441void
442torrent_set_directory( const char * path )
443{
444    assert( NULL != gl_handle );
445    assert( !gl_exiting );
446
447    absolutify( gl_dir, sizeof gl_dir, path );
448    savestate();
449}
450
451const char *
452torrent_get_directory( void )
453{
454    return gl_dir;
455}
456
457void
458torrent_set_encryption(tr_encryption_mode mode)
459{
460    tr_setEncryptionMode(gl_handle, mode);
461    gl_crypto = mode;
462    savestate();
463}
464
465tr_encryption_mode
466torrent_get_encryption(void)
467{
468    return tr_getEncryptionMode(gl_handle);
469}
470
471struct tor *
472opentor( const char * path, const char * hash, uint8_t * data, size_t size,
473         const char * dir )
474{
475    struct tor * tor, * found;
476    int          errcode;
477    const tr_info  * inf;
478    tr_ctor        * ctor;
479
480    assert( ( NULL != path && NULL == hash && NULL == data ) ||
481            ( NULL == path && NULL != hash && NULL == data ) ||
482            ( NULL == path && NULL == hash && NULL != data ) );
483
484    /* XXX should probably wrap around back to 1 and avoid duplicates */
485    if( INT_MAX == gl_lastid )
486    {
487        errmsg( "Congratulations, you're the %ith torrent! Your prize the "
488                "inability to load any more torrents, enjoy!", INT_MAX );
489        return NULL;
490    }
491
492    tor = calloc( 1, sizeof *tor );
493    if( NULL == tor )
494    {
495        mallocmsg( sizeof *tor );
496        return NULL;
497    }
498
499    if( dir == NULL )
500        dir = gl_dir;
501
502    ctor = tr_ctorNew( gl_handle );
503    tr_ctorSetPaused( ctor, TR_FORCE, 1 );
504    tr_ctorSetDestination( ctor, TR_FORCE, dir );
505    if( path != NULL )
506        tr_ctorSetMetainfoFromFile( ctor, path );
507    else if( hash != NULL )
508        tr_ctorSetMetainfoFromHash( ctor, hash );
509    else
510        tr_ctorSetMetainfo( ctor, data, size );
511    tor->tor = tr_torrentNew( gl_handle, ctor, &errcode );
512    tr_ctorFree( ctor );
513
514    if( NULL == tor->tor )
515    {
516        found = NULL;
517        switch( errcode )
518        {
519            case TR_EINVALID:
520                if( NULL == path )
521                {
522                    errmsg( "invalid torrent file" );
523                }
524                else
525                {
526                    errmsg( "invalid torrent file: %s", path );
527                }
528                break;
529            case TR_EUNSUPPORTED:
530                if( NULL == path )
531                {
532                    errmsg( "unsupported torrent file" );
533                }
534                else
535                {
536                    errmsg( "unsupported torrent file: %s", path );
537                }
538                break;
539            case TR_EDUPLICATE:
540                /* XXX not yet
541                found = hashlookup( tor->hash, 1 );
542                assert( NULL != found );
543                found->deleting = 0;
544                */
545                errmsg( "XXX loaded duplicate torrent" );
546                break;
547            default:
548                if( NULL == path )
549                {
550                    errmsg( "torrent file failed to load" );
551                }
552                else
553                {
554                    errmsg( "torrent file failed to load: %s", path );
555                }
556                break;
557        }
558        free( tor );
559        return found;
560    }
561    gl_lastid++;
562    tor->id       = gl_lastid;
563
564    assert( sizeof( inf->hash ) == sizeof( tor->hash ) );
565    inf = tr_torrentInfo( tor->tor );
566    memcpy( tor->hash, inf->hash, sizeof tor->hash );
567
568    found = RB_INSERT( tortree, &gl_tree, tor );
569    assert( NULL == found );
570    found = RB_INSERT( hashtree, &gl_hashes, tor );
571    assert( NULL == found );
572
573    return tor;
574}
575
576static void
577freetor( struct tor * tor )
578{
579    tr_torrentClose( tor->tor );
580    RB_REMOVE( tortree, &gl_tree, tor );
581    RB_REMOVE( hashtree, &gl_hashes, tor );
582    free( tor );
583}
584
585void
586closetor( struct tor * tor, int calltimer )
587{
588    if( NULL != tor )
589    {
590        freetor( tor );
591
592        starttimer( calltimer );
593    }
594}
595
596void
597starttimer( int callnow )
598{
599    if( !evtimer_initialized( &gl_event ) )
600    {
601        evtimer_set( &gl_event, timerfunc, NULL );
602        event_base_set( gl_base, &gl_event );
603    }
604
605    if( callnow )
606    {
607        timerfunc( -1, EV_TIMEOUT, NULL );
608    }
609}
610
611static void
612timerfunc( int fd UNUSED, short event UNUSED, void * arg UNUSED )
613{
614    struct tor             * tor, * next;
615    const tr_handle_status * hs;
616    int                      stillmore;
617    struct timeval           tv;
618
619    /* true if we've still got live torrents... */
620    stillmore = tr_torrentCount( gl_handle ) != 0;
621
622    if( gl_exiting )
623    {
624        if( !stillmore )
625        {
626            hs = tr_handleStatus( gl_handle );
627            if( TR_NAT_TRAVERSAL_UNMAPPED != hs->natTraversalStatus )
628            {
629                stillmore = 1;
630            }
631        }
632
633        if( !stillmore || EXIT_TIMEOUT <= time( NULL ) - gl_exiting )
634        {
635            if( stillmore )
636            {
637                errmsg( "timing out trackers and/or port mapping on exit" );
638            }
639            for( tor = RB_MIN( tortree, &gl_tree ); NULL != tor; tor = next )
640            {
641                next = RB_NEXT( tortree, &gl_tree, tor );
642                freetor( tor );
643            }
644            tr_close( gl_handle );
645            exit( gl_exitval );
646        }
647    }
648
649    if( stillmore )
650    {
651        memset( &tv, 0, sizeof tv );
652        tv.tv_sec  = TIMER_SECS;
653        tv.tv_usec = TIMER_USECS;
654        evtimer_add( &gl_event, &tv );
655    }
656}
657
658int
659loadstate( void )
660{
661    uint8_t   *  buf;
662    size_t       len;
663    benc_val_t   top, * num, * str, * list;
664    int          ii;
665    struct tor * tor;
666    const char * dir;
667
668    buf = readfile( gl_state, &len );
669    if( NULL == buf )
670    {
671        return -1;
672    }
673
674    if( tr_bencLoad( buf, len, &top, NULL ) )
675    {
676        free( buf );
677        errmsg( "failed to load bencoded data from %s", gl_state );
678        return -1;
679    }
680    free( buf );
681
682    num = tr_bencDictFind( &top, "autostart" );
683    if( tr_bencIsInt( num ) )
684        gl_autostart = ( num->val.i ? 1 : 0 );
685
686    num = tr_bencDictFind( &top, "port" );
687    if( tr_bencIsInt( num ) && 0 < num->val.i && 0xffff > num->val.i )
688    {
689        gl_port = num->val.i;
690    }
691    tr_setBindPort( gl_handle, gl_port );
692
693    num = tr_bencDictFind( &top, "default-pex" );
694    if( tr_bencIsInt( num ) )
695        gl_pex = ( num->val.i ? 1 : 0 );
696
697    num = tr_bencDictFind( &top, "port-mapping" );
698    if( tr_bencIsInt( num ) )
699        gl_mapping = ( num->val.i ? 1 : 0 );
700    tr_natTraversalEnable( gl_handle, gl_mapping );
701
702    num = tr_bencDictFind( &top, "upload-limit" );
703    if( tr_bencIsInt( num ) )
704        gl_uplimit = num->val.i;
705    tr_setGlobalSpeedLimit( gl_handle, TR_UP, gl_uplimit );
706    tr_setUseGlobalSpeedLimit( gl_handle, TR_UP, gl_uplimit > 0 );
707
708    num = tr_bencDictFind( &top, "download-limit" );
709    if( tr_bencIsInt( num ) )
710        gl_downlimit = num->val.i;
711    tr_setGlobalSpeedLimit( gl_handle, TR_DOWN, gl_downlimit );
712    tr_setUseGlobalSpeedLimit( gl_handle, TR_DOWN, gl_downlimit > 0 );
713
714    str = tr_bencDictFind( &top, "default-directory" );
715    if( tr_bencIsString( str ) )
716        strlcpy( gl_dir, str->val.s.s, sizeof gl_dir );
717
718    str = tr_bencDictFind( &top, "encryption-mode" );
719    if( tr_bencIsString( str ) )
720    {
721        if(!strcasecmp(str->val.s.s, "preferred"))
722            gl_crypto = TR_ENCRYPTION_PREFERRED;
723        else if(!strcasecmp(str->val.s.s, "required"))
724            gl_crypto = TR_ENCRYPTION_REQUIRED;
725    }
726
727    tr_setEncryptionMode(gl_handle, gl_crypto);
728
729    list = tr_bencDictFind( &top, "torrents" );
730    if( !tr_bencIsList( list ) )
731        return 0;
732
733    for( ii = 0; ii < list->val.l.count; ii++ )
734    {
735        tr_benc * dict = &list->val.l.vals[ii];
736        if( !tr_bencIsDict( dict ) )
737            continue;
738
739        str = tr_bencDictFind( dict, "directory" );
740        dir = tr_bencIsString( str ) ? str->val.s.s : NULL;
741
742        str = tr_bencDictFind( dict, "hash" );
743        if( !tr_bencIsString( str ) || 2 * SHA_DIGEST_LENGTH != str->val.s.i )
744            continue;
745
746        tor = opentor( NULL, str->val.s.s, NULL, 0, dir );
747        if( !tor )
748            continue;
749
750        num = tr_bencDictFind( dict, "pex" );
751        if( tr_bencIsInt( num ) )
752            fprintf( stderr, "warning: obsolete command 'pex'\n" );
753
754        num = tr_bencDictFind( dict, "paused" );
755        if( tr_bencIsInt( num ) && !num->val.i )
756            tr_torrentStart( tor->tor );
757    }
758
759    return 0;
760}
761
762int
763savestate( void )
764{
765    benc_val_t   top, * list, * tor;
766    struct tor * ii;
767    uint8_t    * buf;
768    int          len;
769
770    tr_bencInit( &top, TYPE_DICT );
771    if( tr_bencDictReserve( &top, 9 ) )
772    {
773      nomem:
774        tr_bencFree( &top );
775        errmsg( "failed to save state: failed to allocate memory" );
776        return -1;
777    }
778    tr_bencInitInt( tr_bencDictAdd( &top, "autostart" ),      gl_autostart );
779    tr_bencInitInt( tr_bencDictAdd( &top, "port" ),           gl_port );
780    tr_bencInitInt( tr_bencDictAdd( &top, "default-pex" ),    gl_pex );
781    tr_bencInitInt( tr_bencDictAdd( &top, "port-mapping" ),   gl_mapping );
782    tr_bencInitInt( tr_bencDictAdd( &top, "upload-limit" ),   gl_uplimit );
783    tr_bencInitInt( tr_bencDictAdd( &top, "download-limit" ), gl_downlimit );
784    tr_bencInitStr( tr_bencDictAdd( &top, "default-directory" ),
785                    gl_dir, -1, 1 );
786    if(TR_ENCRYPTION_REQUIRED == gl_crypto)
787        tr_bencInitStr(tr_bencDictAdd(&top, "encryption-mode"), "required", -1, 1);
788    else
789        tr_bencInitStr(tr_bencDictAdd(&top, "encryption-mode"), "preferred", -1, 1);
790    list = tr_bencDictAdd( &top, "torrents" );
791    tr_bencInit( list, TYPE_LIST );
792
793    len = 0;
794    RB_FOREACH( ii, tortree, &gl_tree )
795    {
796        len++;
797    }
798    if( tr_bencListReserve( list, len ) )
799    {
800        goto nomem;
801    }
802
803    RB_FOREACH( ii, tortree, &gl_tree )
804    {
805        const tr_info * inf;
806        const tr_stat * st;
807        tor = tr_bencListAdd( list );
808        assert( NULL != tor );
809        tr_bencInit( tor, TYPE_DICT );
810        inf    = tr_torrentInfo( ii->tor );
811        st     = tr_torrentStat( ii->tor );
812        if( tr_bencDictReserve( tor, 3 ) )
813        {
814            goto nomem;
815        }
816        tr_bencInitStr( tr_bencDictAdd( tor, "hash" ),
817                        inf->hashString, 2 * SHA_DIGEST_LENGTH, 1 );
818        tr_bencInitInt( tr_bencDictAdd( tor, "paused" ),
819                        !TR_STATUS_IS_ACTIVE( st->status ) );
820        tr_bencInitStr( tr_bencDictAdd( tor, "directory" ),
821                        tr_torrentGetFolder( ii->tor ), -1, 1 );
822    }
823
824    buf = ( uint8_t * )tr_bencSave( &top, &len );
825    SAFEBENCFREE( &top );
826    if( NULL == buf )
827    {
828        errnomsg( "failed to save state: bencoding failed" );
829        return -1;
830    }
831
832    if( 0 > writefile( gl_newstate, buf, len ) )
833    {
834        free( buf );
835        return -1;
836    }
837    free( buf );
838
839    if( 0 > rename( gl_newstate, gl_state ) )
840    {
841        errnomsg( "failed to save state: failed to rename %s to %s",
842                  gl_newstate, CONF_FILE_STATE );
843        return -1;
844    }
845
846    return 0;
847}
Note: See TracBrowser for help on using the repository browser.