source: branches/1.9x/libtransmission/bencode.c @ 10342

Last change on this file since 10342 was 10342, checked in by charles, 11 years ago

(1.9x libT) in tr_bencToFile(), call fsync() before close() for better ext4 safety

  • Property svn:keywords set to Date Rev Author Id
File size: 42.2 KB
Line 
1/*
2 * This file Copyright (C) 2008-2010 Mnemosyne LLC
3 *
4 * This file is licensed by the GPL version 2.  Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
9 *
10 * $Id: bencode.c 10342 2010-03-09 22:59:13Z charles $
11 */
12
13#include <assert.h>
14#include <ctype.h> /* isdigit */
15#include <errno.h>
16#include <math.h> /* fabs */
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20
21#include <sys/types.h> /* stat() */
22#include <sys/stat.h> /* stat() */
23#include <locale.h>
24#include <unistd.h> /* stat(), close() */
25
26#include <event.h> /* evbuffer */
27
28#include "ConvertUTF.h"
29
30#include "transmission.h"
31#include "bencode.h"
32#include "json.h"
33#include "list.h"
34#include "ptrarray.h"
35#include "utils.h" /* tr_new(), tr_free() */
36
37#ifndef ENODATA
38 #define ENODATA EIO
39#endif
40
41/**
42***
43**/
44
45static tr_bool
46isContainer( const tr_benc * val )
47{
48    return tr_bencIsList( val ) || tr_bencIsDict( val );
49}
50
51static tr_bool
52isSomething( const tr_benc * val )
53{
54    return isContainer( val ) || tr_bencIsInt( val )
55                              || tr_bencIsString( val )
56                              || tr_bencIsReal( val )
57                              || tr_bencIsBool( val );
58}
59
60static void
61tr_bencInit( tr_benc * val,
62             int       type )
63{
64    memset( val, 0, sizeof( *val ) );
65    val->type = type;
66}
67
68/***
69****  tr_bencParse()
70****  tr_bencLoad()
71***/
72
73/**
74 * The initial i and trailing e are beginning and ending delimiters.
75 * You can have negative numbers such as i-3e. You cannot prefix the
76 * number with a zero such as i04e. However, i0e is valid.
77 * Example: i3e represents the integer "3"
78 * NOTE: The maximum number of bit of this integer is unspecified,
79 * but to handle it as a signed 64bit integer is mandatory to handle
80 * "large files" aka .torrent for more that 4Gbyte
81 */
82int
83tr_bencParseInt( const uint8_t *  buf,
84                 const uint8_t *  bufend,
85                 const uint8_t ** setme_end,
86                 int64_t *        setme_val )
87{
88    char *       endptr;
89    const void * begin;
90    const void * end;
91    int64_t      val;
92
93    if( buf >= bufend )
94        return EILSEQ;
95    if( *buf != 'i' )
96        return EILSEQ;
97
98    begin = buf + 1;
99    end = memchr( begin, 'e', ( bufend - buf ) - 1 );
100    if( end == NULL )
101        return EILSEQ;
102
103    errno = 0;
104    val = evutil_strtoll( begin, &endptr, 10 );
105    if( errno || ( endptr != end ) ) /* incomplete parse */
106        return EILSEQ;
107    if( val && *(const char*)begin == '0' ) /* no leading zeroes! */
108        return EILSEQ;
109
110    *setme_end = (const uint8_t*)end + 1;
111    *setme_val = val;
112    return 0;
113}
114
115/**
116 * Byte strings are encoded as follows:
117 * <string length encoded in base ten ASCII>:<string data>
118 * Note that there is no constant beginning delimiter, and no ending delimiter.
119 * Example: 4:spam represents the string "spam"
120 */
121int
122tr_bencParseStr( const uint8_t *  buf,
123                 const uint8_t *  bufend,
124                 const uint8_t ** setme_end,
125                 const uint8_t ** setme_str,
126                 size_t *         setme_strlen )
127{
128    size_t       len;
129    const void * end;
130    char *       endptr;
131
132    if( buf >= bufend )
133        return EILSEQ;
134
135    if( !isdigit( *buf  ) )
136        return EILSEQ;
137
138    end = memchr( buf, ':', bufend - buf );
139    if( end == NULL )
140        return EILSEQ;
141
142    errno = 0;
143    len = strtoul( (const char*)buf, &endptr, 10 );
144    if( errno || endptr != end )
145        return EILSEQ;
146
147    if( (const uint8_t*)end + 1 + len > bufend )
148        return EILSEQ;
149
150    *setme_end = (const uint8_t*)end + 1 + len;
151    *setme_str = (const uint8_t*)end + 1;
152    *setme_strlen = len;
153    return 0;
154}
155
156/* set to 1 to help expose bugs with tr_bencListAdd and tr_bencDictAdd */
157#define LIST_SIZE 4 /* number of items to increment list/dict buffer by */
158
159static int
160makeroom( tr_benc * val,
161          size_t    count )
162{
163    assert( TR_TYPE_LIST == val->type || TR_TYPE_DICT == val->type );
164
165    if( val->val.l.count + count > val->val.l.alloc )
166    {
167        /* We need a bigger boat */
168        const int len = val->val.l.alloc + count +
169                        ( count % LIST_SIZE ? LIST_SIZE -
170                          ( count % LIST_SIZE ) : 0 );
171        void * tmp = realloc( val->val.l.vals, len * sizeof( tr_benc ) );
172        if( !tmp )
173            return 1;
174
175        val->val.l.alloc = len;
176        val->val.l.vals  = tmp;
177    }
178
179    return 0;
180}
181
182static tr_benc*
183getNode( tr_benc *     top,
184         tr_ptrArray * parentStack,
185         int           type )
186{
187    tr_benc * parent;
188
189    assert( top );
190    assert( parentStack );
191
192    if( tr_ptrArrayEmpty( parentStack ) )
193        return top;
194
195    parent = tr_ptrArrayBack( parentStack );
196    assert( parent );
197
198    /* dictionary keys must be strings */
199    if( ( parent->type == TR_TYPE_DICT )
200      && ( type != TR_TYPE_STR )
201      && ( !( parent->val.l.count % 2 ) ) )
202        return NULL;
203
204    makeroom( parent, 1 );
205    return parent->val.l.vals + parent->val.l.count++;
206}
207
208/**
209 * This function's previous recursive implementation was
210 * easier to read, but was vulnerable to a smash-stacking
211 * attack via maliciously-crafted bencoded data. (#667)
212 */
213static int
214tr_bencParseImpl( const void *     buf_in,
215                  const void *     bufend_in,
216                  tr_benc *        top,
217                  tr_ptrArray *    parentStack,
218                  const uint8_t ** setme_end )
219{
220    int             err;
221    const uint8_t * buf = buf_in;
222    const uint8_t * bufend = bufend_in;
223
224    tr_bencInit( top, 0 );
225
226    while( buf != bufend )
227    {
228        if( buf > bufend ) /* no more text to parse... */
229            return 1;
230
231        if( *buf == 'i' ) /* int */
232        {
233            int64_t         val;
234            const uint8_t * end;
235            tr_benc *       node;
236
237            if( ( err = tr_bencParseInt( buf, bufend, &end, &val ) ) )
238                return err;
239
240            node = getNode( top, parentStack, TR_TYPE_INT );
241            if( !node )
242                return EILSEQ;
243
244            tr_bencInitInt( node, val );
245            buf = end;
246
247            if( tr_ptrArrayEmpty( parentStack ) )
248                break;
249        }
250        else if( *buf == 'l' ) /* list */
251        {
252            tr_benc * node = getNode( top, parentStack, TR_TYPE_LIST );
253            if( !node )
254                return EILSEQ;
255            tr_bencInit( node, TR_TYPE_LIST );
256            tr_ptrArrayAppend( parentStack, node );
257            ++buf;
258        }
259        else if( *buf == 'd' ) /* dict */
260        {
261            tr_benc * node = getNode( top, parentStack, TR_TYPE_DICT );
262            if( !node )
263                return EILSEQ;
264            tr_bencInit( node, TR_TYPE_DICT );
265            tr_ptrArrayAppend( parentStack, node );
266            ++buf;
267        }
268        else if( *buf == 'e' ) /* end of list or dict */
269        {
270            tr_benc * node;
271            ++buf;
272            if( tr_ptrArrayEmpty( parentStack ) )
273                return EILSEQ;
274
275            node = tr_ptrArrayBack( parentStack );
276            if( tr_bencIsDict( node ) && ( node->val.l.count % 2 ) )
277            {
278                /* odd # of children in dict */
279                tr_bencFree( &node->val.l.vals[--node->val.l.count] );
280                return EILSEQ;
281            }
282
283            tr_ptrArrayPop( parentStack );
284            if( tr_ptrArrayEmpty( parentStack ) )
285                break;
286        }
287        else if( isdigit( *buf ) ) /* string? */
288        {
289            const uint8_t * end;
290            const uint8_t * str;
291            size_t          str_len;
292            tr_benc *       node;
293
294            if( ( err = tr_bencParseStr( buf, bufend, &end, &str, &str_len ) ) )
295                return err;
296
297            node = getNode( top, parentStack, TR_TYPE_STR );
298            if( !node )
299                return EILSEQ;
300
301            tr_bencInitStr( node, str, str_len );
302            buf = end;
303
304            if( tr_ptrArrayEmpty( parentStack ) )
305                break;
306        }
307        else /* invalid bencoded text... march past it */
308        {
309            ++buf;
310        }
311    }
312
313    err = !isSomething( top ) || !tr_ptrArrayEmpty( parentStack );
314
315    if( !err && setme_end )
316        *setme_end = buf;
317
318    return err;
319}
320
321int
322tr_bencParse( const void *     buf,
323              const void *     end,
324              tr_benc *        top,
325              const uint8_t ** setme_end )
326{
327    int           err;
328    tr_ptrArray   parentStack = TR_PTR_ARRAY_INIT;
329
330    top->type = 0; /* set to `uninitialized' */
331    err = tr_bencParseImpl( buf, end, top, &parentStack, setme_end );
332    if( err )
333        tr_bencFree( top );
334
335    tr_ptrArrayDestruct( &parentStack, NULL );
336    return err;
337}
338
339int
340tr_bencLoad( const void * buf_in,
341             size_t       buflen,
342             tr_benc *    setme_benc,
343             char **      setme_end )
344{
345    const uint8_t * buf = buf_in;
346    const uint8_t * end;
347    const int       ret = tr_bencParse( buf, buf + buflen, setme_benc, &end );
348
349    if( !ret && setme_end )
350        *setme_end = (char*) end;
351    return ret;
352}
353
354/***
355****
356***/
357
358/* returns true if the benc's string was malloced.
359 * this occurs when the string is too long for our string buffer */
360static inline int
361stringIsAlloced( const tr_benc * val )
362{
363    return val->val.s.len >= sizeof( val->val.s.str.buf );
364}
365
366/* returns a const pointer to the benc's string */
367static inline const char*
368getStr( const tr_benc* val )
369{
370    return stringIsAlloced(val) ? val->val.s.str.ptr : val->val.s.str.buf;
371}
372
373static int
374dictIndexOf( const tr_benc * val, const char * key )
375{
376    if( tr_bencIsDict( val ) )
377    {
378        size_t       i;
379        const size_t len = strlen( key );
380
381        for( i = 0; ( i + 1 ) < val->val.l.count; i += 2 )
382        {
383            const tr_benc * child = val->val.l.vals + i;
384            if( ( child->type == TR_TYPE_STR )
385              && ( child->val.s.len == len )
386              && !memcmp( getStr(child), key, len ) )
387                return i;
388        }
389    }
390
391    return -1;
392}
393
394tr_benc *
395tr_bencDictFind( tr_benc * val, const char * key )
396{
397    const int i = dictIndexOf( val, key );
398
399    return i < 0 ? NULL : &val->val.l.vals[i + 1];
400}
401
402static tr_bool
403tr_bencDictFindType( tr_benc * dict, const char * key, int type, tr_benc ** setme )
404{
405    return tr_bencIsType( *setme = tr_bencDictFind( dict, key ), type );
406}
407
408size_t
409tr_bencListSize( const tr_benc * list )
410{
411    return tr_bencIsList( list ) ? list->val.l.count : 0;
412}
413
414tr_benc*
415tr_bencListChild( tr_benc * val,
416                  size_t    i )
417{
418    tr_benc * ret = NULL;
419
420    if( tr_bencIsList( val ) && ( i < val->val.l.count ) )
421        ret = val->val.l.vals + i;
422    return ret;
423}
424
425static void
426tr_benc_warning( const char * err )
427{
428    fprintf( stderr, "warning: %s\n", err );
429}
430
431tr_bool
432tr_bencGetInt( const tr_benc * val,
433               int64_t *       setme )
434{
435    tr_bool success = FALSE;
436
437    if( !success && (( success = tr_bencIsInt( val ))))
438        if( setme )
439            *setme = val->val.i;
440
441    if( !success && (( success = tr_bencIsBool( val )))) {
442        tr_benc_warning( "reading bool as an int" );
443        if( setme )
444            *setme = val->val.b ? 1 : 0;
445    }
446
447    return success;
448}
449
450tr_bool
451tr_bencGetStr( const tr_benc * val,
452               const char **   setme )
453{
454    const int success = tr_bencIsString( val );
455
456    if( success )
457        *setme = getStr( val );
458
459    return success;
460}
461
462tr_bool
463tr_bencGetBool( const tr_benc * val, tr_bool * setme )
464{
465    const char * str;
466    tr_bool success = FALSE;
467
468    if(( success = tr_bencIsBool( val )))
469        *setme = val->val.b;
470
471    if( !success && tr_bencIsInt( val ) )
472        if(( success = ( val->val.i==0 || val->val.i==1 ) ))
473            *setme = val->val.i!=0;
474
475    if( !success && tr_bencGetStr( val, &str ) )
476        if(( success = ( !strcmp(str,"true") || !strcmp(str,"false"))))
477            *setme = !strcmp(str,"true");
478
479    return success;
480}
481
482tr_bool
483tr_bencGetReal( const tr_benc * val, double * setme )
484{
485    tr_bool success = FALSE;
486
487    if( !success && (( success = tr_bencIsReal( val ))))
488        *setme = val->val.d;
489
490    if( !success && (( success = tr_bencIsInt( val ))))
491        *setme = val->val.i;
492
493    if( !success && tr_bencIsString(val) )
494    {
495        char * endptr;
496        char locale[128];
497        double d;
498
499        /* the json spec requires a '.' decimal point regardless of locale */
500        tr_strlcpy( locale, setlocale( LC_NUMERIC, NULL ), sizeof( locale ) );
501        setlocale( LC_NUMERIC, "POSIX" );
502        d  = strtod( getStr(val), &endptr );
503        setlocale( LC_NUMERIC, locale );
504
505        if(( success = ( getStr(val) != endptr ) && !*endptr ))
506            *setme = d;
507    }
508
509
510    return success;
511}
512
513tr_bool
514tr_bencDictFindInt( tr_benc * dict, const char * key, int64_t * setme )
515{
516    return tr_bencGetInt( tr_bencDictFind( dict, key ), setme );
517}
518
519tr_bool
520tr_bencDictFindBool( tr_benc * dict, const char * key, tr_bool * setme )
521{
522    return tr_bencGetBool( tr_bencDictFind( dict, key ), setme );
523}
524
525tr_bool
526tr_bencDictFindReal( tr_benc * dict, const char * key, double * setme )
527{
528    return tr_bencGetReal( tr_bencDictFind( dict, key ), setme );
529}
530
531tr_bool
532tr_bencDictFindStr( tr_benc *  dict, const char *  key, const char ** setme )
533{
534    return tr_bencGetStr( tr_bencDictFind( dict, key ), setme );
535}
536
537tr_bool
538tr_bencDictFindList( tr_benc * dict, const char * key, tr_benc ** setme )
539{
540    return tr_bencDictFindType( dict, key, TR_TYPE_LIST, setme );
541}
542
543tr_bool
544tr_bencDictFindDict( tr_benc * dict, const char * key, tr_benc ** setme )
545{
546    return tr_bencDictFindType( dict, key, TR_TYPE_DICT, setme );
547}
548
549tr_bool
550tr_bencDictFindRaw( tr_benc         * dict,
551                    const char      * key,
552                    const uint8_t  ** setme_raw,
553                    size_t          * setme_len )
554{
555    tr_benc * child;
556    const tr_bool found = tr_bencDictFindType( dict, key, TR_TYPE_STR, &child );
557
558    if( found ) {
559        *setme_raw = (uint8_t*) getStr(child);
560        *setme_len = child->val.s.len;
561    }
562
563    return found;
564}
565
566/***
567****
568***/
569
570void
571tr_bencInitRaw( tr_benc * val, const void * src, size_t byteCount )
572{
573    char * setme;
574    tr_bencInit( val, TR_TYPE_STR );
575
576    /* There's no way in benc notation to distinguish between
577     * zero-terminated strings and raw byte arrays.
578     * Because of this, tr_bencMergeDicts() and tr_bencListCopy()
579     * don't know whether or not a TR_TYPE_STR node needs a '\0'.
580     * Append one, een to the raw arrays, just to be safe. */
581
582    if( byteCount < sizeof( val->val.s.str.buf ) )
583        setme = val->val.s.str.buf;
584    else
585        setme = val->val.s.str.ptr = tr_new( char, byteCount + 1 );
586
587    memcpy( setme, src, byteCount );
588    setme[byteCount] = '\0';
589    val->val.s.len = byteCount;
590}
591
592void
593tr_bencInitStr( tr_benc * val, const void * str, int len )
594{
595    if( str == NULL )
596        len = 0;
597    else if( len < 0 )
598        len = strlen( str );
599
600    tr_bencInitRaw( val, str, len );
601}
602
603void
604tr_bencInitBool( tr_benc * b, int value )
605{
606    tr_bencInit( b, TR_TYPE_BOOL );
607    b->val.b = value != 0;
608}
609
610void
611tr_bencInitReal( tr_benc * b, double value )
612{
613    tr_bencInit( b, TR_TYPE_REAL );
614    b->val.d = value;
615}
616
617void
618tr_bencInitInt( tr_benc * b, int64_t value )
619{
620    tr_bencInit( b, TR_TYPE_INT );
621    b->val.i = value;
622}
623
624int
625tr_bencInitList( tr_benc * b, size_t reserveCount )
626{
627    tr_bencInit( b, TR_TYPE_LIST );
628    return tr_bencListReserve( b, reserveCount );
629}
630
631int
632tr_bencListReserve( tr_benc * b, size_t count )
633{
634    assert( tr_bencIsList( b ) );
635    return makeroom( b, count );
636}
637
638int
639tr_bencInitDict( tr_benc * b, size_t reserveCount )
640{
641    tr_bencInit( b, TR_TYPE_DICT );
642    return tr_bencDictReserve( b, reserveCount );
643}
644
645int
646tr_bencDictReserve( tr_benc * b, size_t reserveCount )
647{
648    assert( tr_bencIsDict( b ) );
649    return makeroom( b, reserveCount * 2 );
650}
651
652tr_benc *
653tr_bencListAdd( tr_benc * list )
654{
655    tr_benc * item;
656
657    assert( tr_bencIsList( list ) );
658
659    if( list->val.l.count == list->val.l.alloc )
660        tr_bencListReserve( list, LIST_SIZE );
661
662    assert( list->val.l.count < list->val.l.alloc );
663
664    item = &list->val.l.vals[list->val.l.count];
665    list->val.l.count++;
666    tr_bencInit( item, TR_TYPE_INT );
667
668    return item;
669}
670
671tr_benc *
672tr_bencListAddInt( tr_benc * list, int64_t val )
673{
674    tr_benc * node = tr_bencListAdd( list );
675
676    tr_bencInitInt( node, val );
677    return node;
678}
679
680tr_benc *
681tr_bencListAddReal( tr_benc * list, double val )
682{
683    tr_benc * node = tr_bencListAdd( list );
684    tr_bencInitReal( node, val );
685    return node;
686}
687
688tr_benc *
689tr_bencListAddBool( tr_benc * list, tr_bool val )
690{
691    tr_benc * node = tr_bencListAdd( list );
692    tr_bencInitBool( node, val );
693    return node;
694}
695
696tr_benc *
697tr_bencListAddStr( tr_benc * list, const char * val )
698{
699    tr_benc * node = tr_bencListAdd( list );
700    tr_bencInitStr( node, val, -1 );
701    return node;
702}
703
704tr_benc *
705tr_bencListAddRaw( tr_benc * list, const uint8_t * val, size_t len )
706{
707    tr_benc * node = tr_bencListAdd( list );
708    tr_bencInitRaw( node, val, len );
709    return node;
710}
711
712tr_benc*
713tr_bencListAddList( tr_benc * list,
714                    size_t    reserveCount )
715{
716    tr_benc * child = tr_bencListAdd( list );
717
718    tr_bencInitList( child, reserveCount );
719    return child;
720}
721
722tr_benc*
723tr_bencListAddDict( tr_benc * list,
724                    size_t    reserveCount )
725{
726    tr_benc * child = tr_bencListAdd( list );
727
728    tr_bencInitDict( child, reserveCount );
729    return child;
730}
731
732tr_benc *
733tr_bencDictAdd( tr_benc *    dict,
734                const char * key )
735{
736    tr_benc * keyval, * itemval;
737
738    assert( tr_bencIsDict( dict ) );
739    if( dict->val.l.count + 2 > dict->val.l.alloc )
740        makeroom( dict, 2 );
741    assert( dict->val.l.count + 2 <= dict->val.l.alloc );
742
743    keyval = dict->val.l.vals + dict->val.l.count++;
744    tr_bencInitStr( keyval, key, -1 );
745
746    itemval = dict->val.l.vals + dict->val.l.count++;
747    tr_bencInit( itemval, TR_TYPE_INT );
748
749    return itemval;
750}
751
752static tr_benc*
753dictFindOrAdd( tr_benc * dict, const char * key, int type )
754{
755    tr_benc * child;
756
757    /* see if it already exists, and if so, try to reuse it */
758    if(( child = tr_bencDictFind( dict, key ))) {
759        if( !tr_bencIsType( child, type ) ) {
760            tr_bencDictRemove( dict, key );
761            child = NULL;
762        }
763    }
764
765    /* if it doesn't exist, create it */
766    if( child == NULL )
767        child = tr_bencDictAdd( dict, key );
768
769    return child;
770}
771
772tr_benc*
773tr_bencDictAddInt( tr_benc *    dict,
774                   const char * key,
775                   int64_t      val )
776{
777    tr_benc * child = dictFindOrAdd( dict, key, TR_TYPE_INT );
778    tr_bencInitInt( child, val );
779    return child;
780}
781
782tr_benc*
783tr_bencDictAddBool( tr_benc * dict, const char * key, tr_bool val )
784{
785    tr_benc * child = dictFindOrAdd( dict, key, TR_TYPE_BOOL );
786    tr_bencInitBool( child, val );
787    return child;
788}
789
790tr_benc*
791tr_bencDictAddReal( tr_benc * dict, const char * key, double val )
792{
793    tr_benc * child = dictFindOrAdd( dict, key, TR_TYPE_REAL );
794    tr_bencInitReal( child, val );
795    return child;
796}
797
798tr_benc*
799tr_bencDictAddStr( tr_benc * dict, const char * key, const char * val )
800{
801    tr_benc * child;
802
803    /* see if it already exists, and if so, try to reuse it */
804    if(( child = tr_bencDictFind( dict, key ))) {
805        if( tr_bencIsString( child ) ) {
806            if( stringIsAlloced( child ) )
807                tr_free( child->val.s.str.ptr );
808        } else {
809            tr_bencDictRemove( dict, key );
810            child = NULL;
811        }
812    }
813
814    /* if it doesn't exist, create it */
815    if( child == NULL )
816        child = tr_bencDictAdd( dict, key );
817
818    /* set it */
819    tr_bencInitStr( child, val, -1 );
820
821    return child;
822}
823
824tr_benc*
825tr_bencDictAddRaw( tr_benc *    dict,
826                   const char * key,
827                   const void * src,
828                   size_t       len )
829{
830    tr_benc * child;
831
832    /* see if it already exists, and if so, try to reuse it */
833    if(( child = tr_bencDictFind( dict, key ))) {
834        if( tr_bencIsString( child ) ) {
835            if( stringIsAlloced( child ) )
836                tr_free( child->val.s.str.ptr );
837        } else {
838            tr_bencDictRemove( dict, key );
839            child = NULL;
840        }
841    }
842
843    /* if it doesn't exist, create it */
844    if( child == NULL )
845        child = tr_bencDictAdd( dict, key );
846
847    /* set it */
848    tr_bencInitRaw( child, src, len );
849
850    return child;
851}
852
853tr_benc*
854tr_bencDictAddList( tr_benc *    dict,
855                    const char * key,
856                    size_t       reserveCount )
857{
858    tr_benc * child = tr_bencDictAdd( dict, key );
859
860    tr_bencInitList( child, reserveCount );
861    return child;
862}
863
864tr_benc*
865tr_bencDictAddDict( tr_benc *    dict,
866                    const char * key,
867                    size_t       reserveCount )
868{
869    tr_benc * child = tr_bencDictAdd( dict, key );
870
871    tr_bencInitDict( child, reserveCount );
872    return child;
873}
874
875int
876tr_bencDictRemove( tr_benc *    dict,
877                   const char * key )
878{
879    int i = dictIndexOf( dict, key );
880
881    if( i >= 0 )
882    {
883        const int n = dict->val.l.count;
884        tr_bencFree( &dict->val.l.vals[i] );
885        tr_bencFree( &dict->val.l.vals[i + 1] );
886        if( i + 2 < n )
887        {
888            dict->val.l.vals[i]   = dict->val.l.vals[n - 2];
889            dict->val.l.vals[i + 1] = dict->val.l.vals[n - 1];
890        }
891        dict->val.l.count -= 2;
892    }
893    return i >= 0; /* return true if found */
894}
895
896/***
897****  BENC WALKING
898***/
899
900struct KeyIndex
901{
902    const char *  key;
903    int           index;
904};
905
906static int
907compareKeyIndex( const void * va,
908                 const void * vb )
909{
910    const struct KeyIndex * a = va;
911    const struct KeyIndex * b = vb;
912
913    return strcmp( a->key, b->key );
914}
915
916struct SaveNode
917{
918    const tr_benc *  val;
919    int              valIsVisited;
920    int              childCount;
921    int              childIndex;
922    int *            children;
923};
924
925static struct SaveNode*
926nodeNewDict( const tr_benc * val )
927{
928    int               i, j;
929    int               nKeys;
930    struct SaveNode * node;
931    struct KeyIndex * indices;
932
933    assert( tr_bencIsDict( val ) );
934
935    nKeys = val->val.l.count / 2;
936    node = tr_new0( struct SaveNode, 1 );
937    node->val = val;
938    node->children = tr_new0( int, nKeys * 2 );
939
940    /* ugh, a dictionary's children have to be sorted by key... */
941    indices = tr_new( struct KeyIndex, nKeys );
942    for( i = j = 0; i < ( nKeys * 2 ); i += 2, ++j )
943    {
944        indices[j].key = getStr(&val->val.l.vals[i]);
945        indices[j].index = i;
946    }
947    qsort( indices, j, sizeof( struct KeyIndex ), compareKeyIndex );
948    for( i = 0; i < j; ++i )
949    {
950        const int index = indices[i].index;
951        node->children[node->childCount++] = index;
952        node->children[node->childCount++] = index + 1;
953    }
954
955    assert( node->childCount == nKeys * 2 );
956    tr_free( indices );
957    return node;
958}
959
960static struct SaveNode*
961nodeNewList( const tr_benc * val )
962{
963    int               i, n;
964    struct SaveNode * node;
965
966    assert( tr_bencIsList( val ) );
967
968    n = val->val.l.count;
969    node = tr_new0( struct SaveNode, 1 );
970    node->val = val;
971    node->childCount = n;
972    node->children = tr_new0( int, n );
973    for( i = 0; i < n; ++i ) /* a list's children don't need to be reordered */
974        node->children[i] = i;
975
976    return node;
977}
978
979static struct SaveNode*
980nodeNewLeaf( const tr_benc * val )
981{
982    struct SaveNode * node;
983
984    assert( !isContainer( val ) );
985
986    node = tr_new0( struct SaveNode, 1 );
987    node->val = val;
988    return node;
989}
990
991static struct SaveNode*
992nodeNew( const tr_benc * val )
993{
994    struct SaveNode * node;
995
996    if( tr_bencIsList( val ) )
997        node = nodeNewList( val );
998    else if( tr_bencIsDict( val ) )
999        node = nodeNewDict( val );
1000    else
1001        node = nodeNewLeaf( val );
1002
1003    return node;
1004}
1005
1006typedef void ( *BencWalkFunc )( const tr_benc * val, void * user_data );
1007
1008struct WalkFuncs
1009{
1010    BencWalkFunc    intFunc;
1011    BencWalkFunc    boolFunc;
1012    BencWalkFunc    realFunc;
1013    BencWalkFunc    stringFunc;
1014    BencWalkFunc    dictBeginFunc;
1015    BencWalkFunc    listBeginFunc;
1016    BencWalkFunc    containerEndFunc;
1017};
1018
1019/**
1020 * This function's previous recursive implementation was
1021 * easier to read, but was vulnerable to a smash-stacking
1022 * attack via maliciously-crafted bencoded data. (#667)
1023 */
1024static void
1025bencWalk( const tr_benc          * top,
1026          const struct WalkFuncs * walkFuncs,
1027          void                   * user_data )
1028{
1029    tr_ptrArray stack = TR_PTR_ARRAY_INIT;
1030
1031    tr_ptrArrayAppend( &stack, nodeNew( top ) );
1032
1033    while( !tr_ptrArrayEmpty( &stack ) )
1034    {
1035        struct SaveNode * node = tr_ptrArrayBack( &stack );
1036        const tr_benc *   val;
1037
1038        if( !node->valIsVisited )
1039        {
1040            val = node->val;
1041            node->valIsVisited = TRUE;
1042        }
1043        else if( node->childIndex < node->childCount )
1044        {
1045            const int index = node->children[node->childIndex++];
1046            val = node->val->val.l.vals +  index;
1047        }
1048        else /* done with this node */
1049        {
1050            if( isContainer( node->val ) )
1051                walkFuncs->containerEndFunc( node->val, user_data );
1052            tr_ptrArrayPop( &stack );
1053            tr_free( node->children );
1054            tr_free( node );
1055            continue;
1056        }
1057
1058        if( val ) switch( val->type )
1059            {
1060                case TR_TYPE_INT:
1061                    walkFuncs->intFunc( val, user_data );
1062                    break;
1063
1064                case TR_TYPE_BOOL:
1065                    walkFuncs->boolFunc( val, user_data );
1066                    break;
1067
1068                case TR_TYPE_REAL:
1069                    walkFuncs->realFunc( val, user_data );
1070                    break;
1071
1072                case TR_TYPE_STR:
1073                    walkFuncs->stringFunc( val, user_data );
1074                    break;
1075
1076                case TR_TYPE_LIST:
1077                    if( val != node->val )
1078                        tr_ptrArrayAppend( &stack, nodeNew( val ) );
1079                    else
1080                        walkFuncs->listBeginFunc( val, user_data );
1081                    break;
1082
1083                case TR_TYPE_DICT:
1084                    if( val != node->val )
1085                        tr_ptrArrayAppend( &stack, nodeNew( val ) );
1086                    else
1087                        walkFuncs->dictBeginFunc( val, user_data );
1088                    break;
1089
1090                default:
1091                    /* did caller give us an uninitialized val? */
1092                    tr_err( "%s", _( "Invalid metadata" ) );
1093                    break;
1094            }
1095    }
1096
1097    tr_ptrArrayDestruct( &stack, NULL );
1098}
1099
1100/****
1101*****
1102****/
1103
1104static void
1105saveIntFunc( const tr_benc * val, void * evbuf )
1106{
1107    evbuffer_add_printf( evbuf, "i%" PRId64 "e", val->val.i );
1108}
1109
1110static void
1111saveBoolFunc( const tr_benc * val, void * evbuf )
1112{
1113    if( val->val.b )
1114        evbuffer_add( evbuf, "i1e", 3 );
1115    else
1116        evbuffer_add( evbuf, "i0e", 3 );
1117}
1118
1119static void
1120saveRealFunc( const tr_benc * val, void * evbuf )
1121{
1122    char buf[128];
1123    char locale[128];
1124    size_t len;
1125
1126    /* always use a '.' decimal point s.t. locale-hopping doesn't bite us */
1127    tr_strlcpy( locale, setlocale( LC_NUMERIC, NULL ), sizeof( locale ) );
1128    setlocale( LC_NUMERIC, "POSIX" );
1129    tr_snprintf( buf, sizeof( buf ), "%f", val->val.d );
1130    setlocale( LC_NUMERIC, locale );
1131
1132    len = strlen( buf );
1133    evbuffer_add_printf( evbuf, "%lu:", (unsigned long)len );
1134    evbuffer_add( evbuf, buf, len );
1135}
1136
1137static void
1138saveStringFunc( const tr_benc * val, void * evbuf )
1139{
1140    evbuffer_add_printf( evbuf, "%lu:", (unsigned long)val->val.s.len );
1141    evbuffer_add( evbuf, getStr(val), val->val.s.len );
1142}
1143
1144static void
1145saveDictBeginFunc( const tr_benc * val UNUSED, void * evbuf )
1146{
1147    evbuffer_add( evbuf, "d", 1 );
1148}
1149
1150static void
1151saveListBeginFunc( const tr_benc * val UNUSED, void * evbuf )
1152{
1153    evbuffer_add( evbuf, "l", 1 );
1154}
1155
1156static void
1157saveContainerEndFunc( const tr_benc * val UNUSED, void * evbuf )
1158{
1159    evbuffer_add( evbuf, "e", 1 );
1160}
1161
1162static const struct WalkFuncs saveFuncs = { saveIntFunc,
1163                                            saveBoolFunc,
1164                                            saveRealFunc,
1165                                            saveStringFunc,
1166                                            saveDictBeginFunc,
1167                                            saveListBeginFunc,
1168                                            saveContainerEndFunc };
1169
1170/***
1171****
1172***/
1173
1174static void
1175freeDummyFunc( const tr_benc * val UNUSED,
1176               void * buf          UNUSED  )
1177{}
1178
1179static void
1180freeStringFunc( const tr_benc * val,
1181                void *          freeme )
1182{
1183    if( stringIsAlloced( val ) )
1184        tr_ptrArrayAppend( freeme, val->val.s.str.ptr );
1185}
1186
1187static void
1188freeContainerBeginFunc( const tr_benc * val,
1189                        void *          freeme )
1190{
1191    tr_ptrArrayAppend( freeme, val->val.l.vals );
1192}
1193
1194static const struct WalkFuncs freeWalkFuncs = { freeDummyFunc,
1195                                                freeDummyFunc,
1196                                                freeDummyFunc,
1197                                                freeStringFunc,
1198                                                freeContainerBeginFunc,
1199                                                freeContainerBeginFunc,
1200                                                freeDummyFunc };
1201
1202void
1203tr_bencFree( tr_benc * val )
1204{
1205    if( isSomething( val ) )
1206    {
1207        tr_ptrArray a = TR_PTR_ARRAY_INIT;
1208        bencWalk( val, &freeWalkFuncs, &a );
1209        tr_ptrArrayDestruct( &a, tr_free );
1210    }
1211}
1212
1213/***
1214****
1215***/
1216
1217/** @brief Implementation helper class for tr_bencToBuffer(TR_FMT_JSON) */
1218struct ParentState
1219{
1220    int    bencType;
1221    int    childIndex;
1222    int    childCount;
1223};
1224
1225/** @brief Implementation helper class for tr_bencToBuffer(TR_FMT_JSON) */
1226struct jsonWalk
1227{
1228    tr_bool doIndent;
1229    tr_list * parents;
1230    struct evbuffer *  out;
1231};
1232
1233static void
1234jsonIndent( struct jsonWalk * data )
1235{
1236    if( data->doIndent )
1237    {
1238        char buf[1024];
1239        const int width = tr_list_size( data->parents ) * 4;
1240
1241        buf[0] = '\n';
1242        memset( buf+1, ' ', width );
1243        evbuffer_add( data->out, buf, 1+width );
1244    }
1245}
1246
1247static void
1248jsonChildFunc( struct jsonWalk * data )
1249{
1250    if( data->parents )
1251    {
1252        struct ParentState * parentState = data->parents->data;
1253
1254        switch( parentState->bencType )
1255        {
1256            case TR_TYPE_DICT:
1257            {
1258                const int i = parentState->childIndex++;
1259                if( !( i % 2 ) )
1260                    evbuffer_add( data->out, ": ", data->doIndent ? 2 : 1 );
1261                else {
1262                    const tr_bool isLast = parentState->childIndex == parentState->childCount;
1263                    if( !isLast ) {
1264                        evbuffer_add( data->out, ", ", data->doIndent ? 2 : 1 );
1265                        jsonIndent( data );
1266                    }
1267                }
1268                break;
1269            }
1270
1271            case TR_TYPE_LIST:
1272            {
1273                const tr_bool isLast = ++parentState->childIndex == parentState->childCount;
1274                if( !isLast ) {
1275                    evbuffer_add( data->out, ", ", data->doIndent ? 2 : 1 );
1276                    jsonIndent( data );
1277                }
1278                break;
1279            }
1280
1281            default:
1282                break;
1283        }
1284    }
1285}
1286
1287static void
1288jsonPushParent( struct jsonWalk * data,
1289                const tr_benc *   benc )
1290{
1291    struct ParentState * parentState = tr_new( struct ParentState, 1 );
1292
1293    parentState->bencType = benc->type;
1294    parentState->childIndex = 0;
1295    parentState->childCount = benc->val.l.count;
1296    tr_list_prepend( &data->parents, parentState );
1297}
1298
1299static void
1300jsonPopParent( struct jsonWalk * data )
1301{
1302    tr_free( tr_list_pop_front( &data->parents ) );
1303}
1304
1305static void
1306jsonIntFunc( const tr_benc * val,
1307             void *          vdata )
1308{
1309    struct jsonWalk * data = vdata;
1310
1311    evbuffer_add_printf( data->out, "%" PRId64, val->val.i );
1312    jsonChildFunc( data );
1313}
1314
1315static void
1316jsonBoolFunc( const tr_benc * val, void * vdata )
1317{
1318    struct jsonWalk * data = vdata;
1319
1320    if( val->val.b )
1321        evbuffer_add( data->out, "true", 4 );
1322    else
1323        evbuffer_add( data->out, "false", 5 );
1324
1325    jsonChildFunc( data );
1326}
1327
1328static void
1329jsonRealFunc( const tr_benc * val, void * vdata )
1330{
1331    struct jsonWalk * data = vdata;
1332    char locale[128];
1333
1334    if( fabs( val->val.d ) < 0.00001 )
1335        evbuffer_add( data->out, "0", 1 );
1336    else {
1337        /* json requires a '.' decimal point regardless of locale */
1338        tr_strlcpy( locale, setlocale( LC_NUMERIC, NULL ), sizeof( locale ) );
1339        setlocale( LC_NUMERIC, "POSIX" );
1340        evbuffer_add_printf( data->out, "%.4f", tr_truncd( val->val.d, 4 ) );
1341        setlocale( LC_NUMERIC, locale );
1342    }
1343
1344    jsonChildFunc( data );
1345}
1346
1347static void
1348jsonStringFunc( const tr_benc * val, void * vdata )
1349{
1350    struct jsonWalk * data = vdata;
1351    const unsigned char * it = (const unsigned char *) getStr(val);
1352    const unsigned char * end = it + val->val.s.len;
1353
1354    evbuffer_expand( data->out, val->val.s.len + 2 );
1355    evbuffer_add( data->out, "\"", 1 );
1356
1357    for( ; it!=end; ++it )
1358    {
1359        switch( *it )
1360        {
1361            case '/': evbuffer_add( data->out, "\\/", 2 ); break;
1362            case '\b': evbuffer_add( data->out, "\\b", 2 ); break;
1363            case '\f': evbuffer_add( data->out, "\\f", 2 ); break;
1364            case '\n': evbuffer_add( data->out, "\\n", 2 ); break;
1365            case '\r': evbuffer_add( data->out, "\\r", 2 ); break;
1366            case '\t': evbuffer_add( data->out, "\\t", 2 ); break;
1367            case '"': evbuffer_add( data->out, "\\\"", 2 ); break;
1368            case '\\': evbuffer_add( data->out, "\\\\", 2 ); break;
1369
1370            default:
1371                if( isascii( *it ) )
1372                    evbuffer_add( data->out, it, 1 );
1373                else {
1374                    const UTF8 * tmp = it;
1375                    UTF32        buf = 0;
1376                    UTF32 *      u32 = &buf;
1377                    ConversionResult result = ConvertUTF8toUTF32( &tmp, end, &u32, &buf + 1, 0 );
1378                    if((( result==conversionOK ) || (result==targetExhausted)) && (tmp!=it)) {
1379                        evbuffer_add_printf( data->out, "\\u%04x", (unsigned int)buf );
1380                        it = tmp - 1;
1381                    }
1382                }
1383        }
1384    }
1385    evbuffer_add( data->out, "\"", 1 );
1386    jsonChildFunc( data );
1387}
1388
1389static void
1390jsonDictBeginFunc( const tr_benc * val,
1391                   void *          vdata )
1392{
1393    struct jsonWalk * data = vdata;
1394
1395    jsonPushParent( data, val );
1396    evbuffer_add( data->out, "{", 1 );
1397    if( val->val.l.count )
1398        jsonIndent( data );
1399}
1400
1401static void
1402jsonListBeginFunc( const tr_benc * val,
1403                   void *          vdata )
1404{
1405    const size_t      nChildren = tr_bencListSize( val );
1406    struct jsonWalk * data = vdata;
1407
1408    jsonPushParent( data, val );
1409    evbuffer_add( data->out, "[", 1 );
1410    if( nChildren )
1411        jsonIndent( data );
1412}
1413
1414static void
1415jsonContainerEndFunc( const tr_benc * val,
1416                      void *          vdata )
1417{
1418    struct jsonWalk * data = vdata;
1419    int               emptyContainer = FALSE;
1420
1421    jsonPopParent( data );
1422    if( !emptyContainer )
1423        jsonIndent( data );
1424    if( tr_bencIsDict( val ) )
1425        evbuffer_add( data->out, "}", 1 );
1426    else /* list */
1427        evbuffer_add( data->out, "]", 1 );
1428    jsonChildFunc( data );
1429}
1430
1431static const struct WalkFuncs jsonWalkFuncs = { jsonIntFunc,
1432                                                jsonBoolFunc,
1433                                                jsonRealFunc,
1434                                                jsonStringFunc,
1435                                                jsonDictBeginFunc,
1436                                                jsonListBeginFunc,
1437                                                jsonContainerEndFunc };
1438
1439/***
1440****
1441***/
1442
1443static void
1444tr_bencListCopy( tr_benc * target, const tr_benc * src )
1445{
1446    int i = 0;
1447    const tr_benc * val;
1448
1449    while(( val = tr_bencListChild( (tr_benc*)src, i++ )))
1450    {
1451       if( tr_bencIsBool( val ) )
1452       {
1453           tr_bool boolVal = 0;
1454           tr_bencGetBool( val, &boolVal );
1455           tr_bencListAddBool( target, boolVal );
1456       }
1457       else if( tr_bencIsReal( val ) )
1458       {
1459           double realVal = 0;
1460           tr_bencGetReal( val, &realVal );
1461           tr_bencListAddReal( target, realVal );
1462       }
1463       else if( tr_bencIsInt( val ) )
1464       {
1465           int64_t intVal = 0;
1466           tr_bencGetInt( val, &intVal );
1467           tr_bencListAddInt( target, intVal );
1468       }
1469       else if( tr_bencIsString( val ) )
1470       {
1471           tr_bencListAddRaw( target, (const uint8_t*)getStr( val ), val->val.s.len );
1472       }
1473       else if( tr_bencIsDict( val ) )
1474       {
1475           tr_bencMergeDicts( tr_bencListAddDict( target, 0 ), val );
1476       }
1477       else if ( tr_bencIsList( val ) )
1478       {
1479           tr_bencListCopy( tr_bencListAddList( target, 0 ), val );
1480       }
1481       else
1482       {
1483           tr_err( "tr_bencListCopy skipping item" );
1484       }
1485   }
1486}
1487
1488static size_t
1489tr_bencDictSize( const tr_benc * dict )
1490{
1491    size_t count = 0;
1492
1493    if( tr_bencIsDict( dict ) )
1494        count = dict->val.l.count / 2;
1495
1496    return count;
1497}
1498
1499tr_bool
1500tr_bencDictChild( tr_benc * dict, size_t n, const char ** key, tr_benc ** val )
1501{
1502    tr_bool success = 0;
1503
1504    assert( tr_bencIsDict( dict ) );
1505
1506    if( tr_bencIsDict( dict ) && (n*2)+1 <= dict->val.l.count )
1507    {
1508        tr_benc * k = dict->val.l.vals + (n*2);
1509        tr_benc * v = dict->val.l.vals + (n*2) + 1;
1510        if(( success = tr_bencGetStr( k, key ) && isSomething( v )))
1511            *val = v;
1512    }
1513
1514    return success;
1515}
1516
1517void
1518tr_bencMergeDicts( tr_benc * target, const tr_benc * source )
1519{
1520    size_t i;
1521    const size_t sourceCount = tr_bencDictSize( source );
1522
1523    assert( tr_bencIsDict( target ) );
1524    assert( tr_bencIsDict( source ) );
1525
1526    for( i=0; i<sourceCount; ++i )
1527    {
1528        const char * key;
1529        tr_benc * val;
1530        tr_benc * t;
1531
1532        if( tr_bencDictChild( (tr_benc*)source, i, &key, &val ) )
1533        {
1534            if( tr_bencIsBool( val ) )
1535            {
1536                tr_bool boolVal;
1537                tr_bencGetBool( val, &boolVal );
1538                tr_bencDictAddBool( target, key, boolVal );
1539            }
1540            else if( tr_bencIsReal( val ) )
1541            {
1542                double realVal = 0;
1543                tr_bencGetReal( val, &realVal );
1544                tr_bencDictAddReal( target, key, realVal );
1545            }
1546            else if( tr_bencIsInt( val ) )
1547            {
1548                int64_t intVal = 0;
1549                tr_bencGetInt( val, &intVal );
1550                tr_bencDictAddInt( target, key, intVal );
1551            }
1552            else if( tr_bencIsString( val ) )
1553            {
1554                tr_bencDictAddRaw( target, key, getStr( val ), val->val.s.len );
1555            }
1556            else if( tr_bencIsDict( val ) && tr_bencDictFindDict( target, key, &t ) )
1557            {
1558                tr_bencMergeDicts( t, val );
1559            }
1560            else if( tr_bencIsList( val ) )
1561            {
1562                if( tr_bencDictFind( target, key ) == NULL )
1563                {
1564                    tr_bencListCopy( tr_bencDictAddList( target, key, tr_bencListSize( val ) ), val );
1565                }
1566            }
1567            else
1568            {
1569                tr_dbg( "tr_bencMergeDicts skipping \"%s\"", key );
1570            }
1571        }
1572    }
1573}
1574
1575/***
1576****
1577***/
1578
1579void
1580tr_bencToBuf( const tr_benc * top, tr_fmt_mode mode, struct evbuffer * buf )
1581{
1582    evbuffer_drain( buf, EVBUFFER_LENGTH( buf ) );
1583    evbuffer_expand( buf, 4096 ); /* alloc a little memory to start off with */
1584
1585    switch( mode )
1586    {
1587        case TR_FMT_BENC:
1588            bencWalk( top, &saveFuncs, buf );
1589            break;
1590
1591        case TR_FMT_JSON:
1592        case TR_FMT_JSON_LEAN: {
1593            struct jsonWalk data;
1594            data.doIndent = mode==TR_FMT_JSON;
1595            data.out = buf;
1596            data.parents = NULL;
1597            bencWalk( top, &jsonWalkFuncs, &data );
1598            if( EVBUFFER_LENGTH( buf ) )
1599                evbuffer_add_printf( buf, "\n" );
1600            break;
1601        }
1602    }
1603}
1604
1605char*
1606tr_bencToStr( const tr_benc * top, tr_fmt_mode mode, int * len )
1607{
1608    char * ret;
1609    struct evbuffer * buf = evbuffer_new( );
1610    tr_bencToBuf( top, mode, buf );
1611    ret = tr_strndup( EVBUFFER_DATA( buf ), EVBUFFER_LENGTH( buf ) );
1612    if( len != NULL )
1613        *len = (int) EVBUFFER_LENGTH( buf );
1614    evbuffer_free( buf );
1615    return ret;
1616}
1617
1618int
1619tr_bencToFile( const tr_benc * top, tr_fmt_mode mode, const char * filename )
1620{
1621    char * tmp;
1622    int fd;
1623    int err = 0;
1624
1625    /* if the file already exists, try to move it out of the way & keep it as a backup */
1626    tmp = tr_strdup_printf( "%s.tmp.XXXXXX", filename );
1627    fd = mkstemp( tmp );
1628    if( fd >= 0 )
1629    {
1630        int len;
1631        char * str = tr_bencToStr( top, mode, &len );
1632        tr_dbg( "Writing %d bytes to temporary file \"%s\"", (int)len, tmp );
1633
1634        if( write( fd, str, len ) == (ssize_t)len )
1635        {
1636            fsync( fd );
1637            close( fd );
1638
1639            if( !unlink( filename ) || ( errno == ENOENT ) )
1640            {
1641                tr_dbg( "Renaming \"%s\" as \"%s\"", tmp, filename );
1642
1643                if( !rename( tmp, filename ) )
1644                {
1645                    tr_inf( _( "Saved \"%s\"" ), filename );
1646                }
1647                else
1648                {
1649                    err = errno;
1650                    tr_err( _( "Couldn't save file \"%1$s\": %2$s" ), filename, tr_strerror( err ) );
1651                    unlink( tmp );
1652                }
1653            }
1654            else
1655            {
1656                err = errno;
1657                tr_err( _( "Couldn't save file \"%1$s\": %2$s" ), filename, tr_strerror( err ) );
1658                unlink( tmp );
1659            }
1660        }
1661        else
1662        {
1663            err = errno;
1664            tr_err( _( "Couldn't save temporary file \"%1$s\": %2$s" ), tmp, tr_strerror( err ) );
1665            close( fd );
1666            unlink( tmp );
1667        }
1668
1669        tr_free( str );
1670    }
1671    else
1672    {
1673        err = errno;
1674        tr_err( _( "Couldn't save temporary file \"%1$s\": %2$s" ), tmp, tr_strerror( err ) );
1675    }
1676
1677    tr_free( tmp );
1678    return err;
1679}
1680
1681/***
1682****
1683***/
1684
1685int
1686tr_bencLoadFile( tr_benc * setme, tr_fmt_mode mode, const char * filename )
1687{
1688    int err;
1689    size_t contentLen;
1690    uint8_t * content;
1691
1692    content = tr_loadFile( filename, &contentLen );
1693    if( !content && errno )
1694        err = errno;
1695    else if( !content )
1696        err = ENODATA;
1697    else {
1698        if( mode == TR_FMT_BENC )
1699            err = tr_bencLoad( content, contentLen, setme, NULL );
1700        else
1701            err = tr_jsonParse( filename, content, contentLen, setme, NULL );
1702    }
1703
1704    tr_free( content );
1705    return err;
1706}
Note: See TracBrowser for help on using the repository browser.