source: trunk/libtransmission/utils.c @ 5185

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

harden the bitfield handling to handle corrupt messages from peers. This is in response to Ryoujin's crash report in the forums (http://forum.transmissionbt.com/viewtopic.php?p=20414#20414)

  • Property svn:keywords set to Date Rev Author Id
File size: 20.4 KB
Line 
1/******************************************************************************
2 * $Id: utils.c 5185 2008-03-02 23:44:34Z charles $
3 *
4 * Copyright (c) 2005-2008 Transmission authors and contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25#include <assert.h>
26#include <ctype.h> /* isalpha */
27#include <errno.h>
28#include <stdarg.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h> /* strerror */
32
33#include <sys/time.h>
34#include <sys/types.h>
35#include <sys/stat.h>
36#include <unistd.h> /* usleep, stat */
37
38#include "event.h"
39
40#ifdef WIN32
41    #include <windows.h> /* for Sleep */
42#elif defined(__BEOS__)
43    #include <kernel/OS.h>
44#endif
45
46#include "transmission.h"
47#include "trcompat.h"
48#include "utils.h"
49#include "platform.h"
50
51static tr_lock      * messageLock = NULL;
52static int            messageLevel = 0;
53static int            messageQueuing = FALSE;
54static tr_msg_list *  messageQueue = NULL;
55static tr_msg_list ** messageQueueTail = &messageQueue;
56
57void tr_msgInit( void )
58{
59    if( !messageLock )
60         messageLock = tr_lockNew( );
61}
62
63FILE*
64tr_getLog( void )
65{
66    static int initialized = FALSE;
67    static FILE * file= NULL;
68
69    if( !initialized )
70    {
71        const char * str = getenv( "TR_DEBUG_FD" );
72        int fd = 0;
73        if( str && *str )
74            fd = atoi( str );
75        switch( fd ) {
76            case 1: file = stdout; break;
77            case 2: file = stderr; break;
78            default: file = NULL; break;
79        }
80        initialized = TRUE;
81    }
82
83    return file;
84}
85
86char*
87tr_getLogTimeStr( char * buf, int buflen )
88{
89    char tmp[64];
90    time_t now;
91    struct tm now_tm;
92    struct timeval tv;
93    int milliseconds;
94
95    now = time( NULL );
96    gettimeofday( &tv, NULL );
97
98#ifdef WIN32
99    now_tm = *localtime( &now );
100#else
101    localtime_r( &now, &now_tm );
102#endif
103    strftime( tmp, sizeof(tmp), "%H:%M:%S", &now_tm );
104    milliseconds = (int)(tv.tv_usec / 1000);
105    snprintf( buf, buflen, "%s.%03d", tmp, milliseconds );
106
107    return buf;
108}
109
110void
111tr_setMessageLevel( int level )
112{
113    tr_msgInit();
114    tr_lockLock( messageLock );
115    messageLevel = MAX( 0, level );
116    tr_lockUnlock( messageLock );
117}
118
119int tr_getMessageLevel( void )
120{
121    int ret;
122
123    tr_msgInit();
124    tr_lockLock( messageLock );
125    ret = messageLevel;
126    tr_lockUnlock( messageLock );
127
128    return ret;
129}
130
131void tr_setMessageQueuing( int enabled )
132{
133    tr_msgInit();
134    tr_lockLock( messageLock );
135    messageQueuing = enabled;
136    tr_lockUnlock( messageLock );
137}
138
139tr_msg_list * tr_getQueuedMessages( void )
140{
141    tr_msg_list * ret;
142
143    assert( NULL != messageLock );
144    tr_lockLock( messageLock );
145    ret = messageQueue;
146    messageQueue = NULL;
147    messageQueueTail = &messageQueue;
148    tr_lockUnlock( messageLock );
149
150    return ret;
151}
152
153void tr_freeMessageList( tr_msg_list * list )
154{
155    tr_msg_list * next;
156
157    while( NULL != list )
158    {
159        next = list->next;
160        free( list->message );
161        free( list );
162        list = next;
163    }
164}
165
166int
167tr_vasprintf( char **strp, const char *fmt, va_list ap )
168{
169    int ret;
170    struct evbuffer * buf = evbuffer_new( );
171    *strp = NULL;
172    if( evbuffer_add_vprintf( buf, fmt, ap ) < 0 )
173        ret = -1;
174    else {
175        ret = EVBUFFER_LENGTH( buf );
176        *strp = tr_strndup( (char*)EVBUFFER_DATA(buf), ret );
177    }
178    evbuffer_free( buf );
179    return ret;
180
181}
182
183int
184tr_asprintf( char **strp, const char *fmt, ...)
185{
186    int ret;
187    va_list ap;
188    va_start( ap, fmt );
189    ret = tr_vasprintf( strp, fmt, ap );
190    va_end( ap );
191    return ret;
192}
193
194void
195tr_msg( const char * file, int line, int level, const char * fmt, ... )
196{
197    FILE * fp;
198
199    if( messageLock )
200        tr_lockLock( messageLock );
201
202    fp = tr_getLog( );
203
204    if( !messageLevel )
205    {
206        char * env = getenv( "TR_DEBUG" );
207        messageLevel = ( env ? atoi( env ) : 0 ) + 1;
208        messageLevel = MAX( 1, messageLevel );
209    }
210
211    if( messageLevel >= level )
212    {
213        va_list ap;
214        char * text;
215
216        /* build the text message */
217        va_start( ap, fmt );
218        tr_vasprintf( &text, fmt, ap );
219        va_end( ap );
220
221        if( text != NULL )
222        {
223            if( messageQueuing )
224            {
225                tr_msg_list * newmsg;
226                newmsg = tr_new0( tr_msg_list, 1 );
227                newmsg->level = level;
228                newmsg->when = time( NULL );
229                newmsg->message = text;
230                newmsg->file = file;
231                newmsg->line = line;
232
233                *messageQueueTail = newmsg;
234                messageQueueTail = &newmsg->next;
235            }
236            else
237            {
238                if( fp == NULL )
239                    fp = stderr;
240                fprintf( stderr, "%s\n", text );
241                tr_free( text );
242                fflush( fp );
243            }
244        }
245    }
246
247    if( messageLock )
248        tr_lockUnlock( messageLock );
249}
250
251int tr_rand( int sup )
252{
253    static int init = 0;
254
255    assert( sup > 0 );
256
257    if( !init )
258    {
259        srand( tr_date() );
260        init = 1;
261    }
262    return rand() % sup;
263}
264
265/***
266****
267***/
268
269void
270tr_set_compare( const void * va, size_t aCount,
271                const void * vb, size_t bCount,
272                int compare( const void * a, const void * b ),
273                size_t elementSize,
274                tr_set_func in_a_cb,
275                tr_set_func in_b_cb,
276                tr_set_func in_both_cb,
277                void * userData )
278{
279    const uint8_t * a = (const uint8_t *) va;
280    const uint8_t * b = (const uint8_t *) vb;
281    const uint8_t * aend = a + elementSize*aCount;
282    const uint8_t * bend = b + elementSize*bCount;
283
284    while( a!=aend || b!=bend )
285    {
286        if( a==aend )
287        {
288            (*in_b_cb)( (void*)b, userData );
289            b += elementSize;
290        }
291        else if ( b==bend )
292        {
293            (*in_a_cb)( (void*)a, userData );
294            a += elementSize;
295        }
296        else
297        {
298            const int val = (*compare)( a, b );
299
300            if( !val )
301            {
302                (*in_both_cb)( (void*)a, userData );
303                a += elementSize;
304                b += elementSize;
305            }
306            else if( val < 0 )
307            {
308                (*in_a_cb)( (void*)a, userData );
309                a += elementSize;
310            }
311            else if( val > 0 )
312            {
313                (*in_b_cb)( (void*)b, userData );
314                b += elementSize;
315            }
316        }
317    }
318}
319
320/***
321****
322***/
323
324int
325tr_compareUint16( uint16_t a, uint16_t b )
326{
327    if( a < b ) return -1;
328    if( a > b ) return 1;
329    return 0;
330}
331
332int
333tr_compareUint32( uint32_t a, uint32_t b )
334{
335    if( a < b ) return -1;
336    if( a > b ) return 1;
337    return 0;
338}
339
340/**
341***
342**/
343
344struct timeval
345timevalMsec( uint64_t milliseconds )
346{
347    struct timeval ret;
348    const uint64_t microseconds = milliseconds * 1000;
349    ret.tv_sec  = microseconds / 1000000;
350    ret.tv_usec = microseconds % 1000000;
351    return ret;
352}
353
354uint8_t *
355tr_loadFile( const char * path, size_t * size )
356{
357    uint8_t    * buf;
358    struct stat  sb;
359    FILE       * file;
360
361    /* try to stat the file */
362    errno = 0;
363    if( stat( path, &sb ) )
364    {
365        tr_err( "Couldn't get information for file \"%s\" %s", path, tr_strerror(errno) );
366        return NULL;
367    }
368
369    if( ( sb.st_mode & S_IFMT ) != S_IFREG )
370    {
371        tr_err( "Not a regular file (%s)", path );
372        return NULL;
373    }
374
375    /* Load the torrent file into our buffer */
376    file = fopen( path, "rb" );
377    if( !file )
378    {
379        tr_err( "Couldn't open file \"%s\" %s", path, tr_strerror(errno) );
380        return NULL;
381    }
382    buf = malloc( sb.st_size );
383    if( NULL == buf )
384    {
385        tr_err( "Couldn't allocate memory (%"PRIu64" bytes)",
386                ( uint64_t )sb.st_size );
387        fclose( file );
388    }
389    fseek( file, 0, SEEK_SET );
390    if( fread( buf, sb.st_size, 1, file ) != 1 )
391    {
392        tr_err( "Error reading \"%s\" %s", path, tr_strerror(errno) );
393        free( buf );
394        fclose( file );
395        return NULL;
396    }
397    fclose( file );
398
399    *size = sb.st_size;
400
401    return buf;
402}
403
404int
405tr_mkdir( const char * path, int permissions
406#ifdef WIN32
407                                             UNUSED
408#endif
409                                                    )
410{
411#ifdef WIN32
412    if( path && isalpha(path[0]) && path[1]==':' && !path[2] )
413        return 0;
414    return mkdir( path );
415#else
416    return mkdir( path, permissions );
417#endif
418}
419
420int
421tr_mkdirp( const char * path_in, int permissions )
422{
423    char * path = tr_strdup( path_in );
424    char * p, * pp;
425    struct stat sb;
426    int done;
427
428    /* walk past the root */
429    p = path;
430    while( *p == TR_PATH_DELIMITER )
431        ++p;
432
433    pp = p;
434    done = 0;
435    while( ( p = strchr( pp, TR_PATH_DELIMITER ) ) || ( p = strchr( pp, '\0' ) ) )
436    {
437        if( !*p )
438            done = 1;
439        else
440            *p = '\0';
441
442        if( stat( path, &sb ) )
443        {
444            /* Folder doesn't exist yet */
445            if( tr_mkdir( path, permissions ) ) {
446                const int err = errno;
447                tr_err( "Couldn't create directory %s (%s)", path, tr_strerror( err ) );
448                tr_free( path );
449                errno = err;
450                return -1;
451            }
452        }
453        else if( ( sb.st_mode & S_IFMT ) != S_IFDIR )
454        {
455            /* Node exists but isn't a folder */
456            tr_err( "Remove %s, it's in the way.", path );
457            tr_free( path );
458            errno = ENOTDIR;
459            return -1;
460        }
461
462        if( done )
463            break;
464
465        *p = TR_PATH_DELIMITER;
466        p++;
467        pp = p;
468    }
469
470    tr_free( path );
471    return 0;
472}
473
474void
475tr_buildPath ( char *buf, size_t buflen, const char *first_element, ... )
476{
477    struct evbuffer * evbuf = evbuffer_new( );
478    const char * element = first_element;
479    va_list vl;
480    va_start( vl, first_element );
481    while( element ) {
482        if( EVBUFFER_LENGTH(evbuf) )
483            evbuffer_add_printf( evbuf, "%c", TR_PATH_DELIMITER );
484        evbuffer_add_printf( evbuf, "%s", element );
485        element = (const char*) va_arg( vl, const char* );
486    }
487    if( EVBUFFER_LENGTH(evbuf) )
488        strlcpy( buf, (char*)EVBUFFER_DATA(evbuf), buflen );
489    else
490        *buf = '\0';
491    evbuffer_free( evbuf );
492}
493
494int
495tr_ioErrorFromErrno( int err )
496{
497    switch( err )
498    {
499        case 0:
500            return TR_OK;
501        case EACCES:
502        case EROFS:
503            return TR_ERROR_IO_PERMISSIONS;
504        case ENOSPC:
505            return TR_ERROR_IO_SPACE;
506        case EMFILE:
507            return TR_ERROR_IO_OPEN_FILES;
508        case EFBIG:
509            return TR_ERROR_IO_FILE_TOO_BIG;
510        default:
511            tr_dbg( "generic i/o errno from errno: %s", tr_strerror( errno ) );
512            return TR_ERROR_IO_OTHER;
513    }
514}
515
516const char *
517tr_errorString( int code )
518{
519    switch( code )
520    {
521        case TR_OK:
522            return "No error";
523
524        case TR_ERROR:
525            return "Generic error";
526        case TR_ERROR_ASSERT:
527            return "Assert error";
528
529        case TR_ERROR_IO_PARENT:
530            return "Download folder does not exist";
531        case TR_ERROR_IO_PERMISSIONS:
532            return "Insufficient permissions";
533        case TR_ERROR_IO_SPACE:
534            return "Insufficient free space";
535        case TR_ERROR_IO_FILE_TOO_BIG:
536            return "File too large";
537        case TR_ERROR_IO_OPEN_FILES:
538            return "Too many open files";
539        case TR_ERROR_IO_DUP_DOWNLOAD:
540            return "Already active transfer with same name and download folder";
541        case TR_ERROR_IO_OTHER:
542            return "Generic I/O error";
543
544        case TR_ERROR_TC_ERROR:
545            return "Tracker error";
546        case TR_ERROR_TC_WARNING:
547            return "Tracker warning";
548
549        case TR_ERROR_PEER_MESSAGE:
550            return "Peer sent a bad message";
551
552        default:
553            return "Unknown error";
554    }
555}
556
557/****
558*****
559****/
560
561char*
562tr_strdup( const char * in )
563{
564    return tr_strndup( in, in ? strlen(in) : 0 );
565}
566
567char*
568tr_strndup( const char * in, int len )
569{
570    char * out = NULL;
571
572    if( len < 0 )
573    {
574        out = tr_strdup( in );
575    }
576    else if( in != NULL )
577    {
578        out = tr_malloc( len+1 );
579        memcpy( out, in, len );
580        out[len] = '\0';
581    }
582    return out;
583}
584
585void*
586tr_calloc( size_t nmemb, size_t size )
587{
588    return nmemb && size ? calloc( nmemb, size ) : NULL;
589}
590
591void*
592tr_malloc( size_t size )
593{
594    return size ? malloc( size ) : NULL;
595}
596
597void*
598tr_malloc0( size_t size )
599{
600    void * ret = tr_malloc( size );
601    memset( ret, 0, size );
602    return ret;
603}
604
605void
606tr_free( void * p )
607{
608    if( p )
609        free( p );
610}
611
612const char*
613tr_strerror( int i )
614{
615    const char * ret = strerror( i );
616    if( ret == NULL )
617        ret = "Unknown Error";
618    return ret;
619}
620
621/****
622*****
623****/
624
625/* note that the argument is how many bits are needed, not bytes */
626tr_bitfield*
627tr_bitfieldNew( size_t bitcount )
628{
629    tr_bitfield * ret = calloc( 1, sizeof(tr_bitfield) );
630    if( NULL == ret )
631        return NULL;
632
633    ret->len = (bitcount+7u) / 8u;
634    ret->bits = calloc( ret->len, 1 );
635    if( NULL == ret->bits ) {
636        free( ret );
637        return NULL;
638    }
639
640    return ret;
641}
642
643tr_bitfield*
644tr_bitfieldDup( const tr_bitfield * in )
645{
646    tr_bitfield * ret = calloc( 1, sizeof(tr_bitfield) );
647    ret->len = in->len;
648    ret->bits = malloc( ret->len );
649    memcpy( ret->bits, in->bits, ret->len );
650    return ret;
651}
652
653void tr_bitfieldFree( tr_bitfield * bitfield )
654{
655    if( bitfield )
656    {
657        free( bitfield->bits );
658        free( bitfield );
659    }
660}
661
662void
663tr_bitfieldClear( tr_bitfield * bitfield )
664{
665    memset( bitfield->bits, 0, bitfield->len );
666}
667
668int
669tr_bitfieldIsEmpty( const tr_bitfield * bitfield )
670{
671    size_t i;
672
673    for( i=0; i<bitfield->len; ++i )
674        if( bitfield->bits[i] )
675            return 0;
676
677    return 1;
678}
679
680int
681tr_bitfieldHas( const tr_bitfield * bitfield, size_t nth )
682{
683    static const uint8_t ands[8] = { 128, 64, 32, 16, 8, 4, 2, 1 };
684    const size_t i = nth >> 3u;
685    return ( bitfield != NULL )
686        && ( bitfield->bits != NULL )
687        && ( i < bitfield->len )
688        && ( ( bitfield->bits[i] & ands[nth&7u] ) != 0 );
689}
690
691int
692tr_bitfieldAdd( tr_bitfield  * bitfield, size_t nth )
693{
694    static const uint8_t ands[8] = { 128, 64, 32, 16, 8, 4, 2, 1 };
695    const size_t i = nth >> 3u;
696
697    assert( bitfield != NULL );
698    assert( bitfield->bits != NULL );
699
700    if( i >= bitfield->len )
701        return -1;
702
703    bitfield->bits[i] |= ands[nth&7u];
704    assert( tr_bitfieldHas( bitfield, nth ) );
705    return 0;
706}
707
708int
709tr_bitfieldAddRange( tr_bitfield  * bitfield,
710                     size_t         begin,
711                     size_t         end )
712{
713    int err = 0;
714    size_t i;
715    for( i=begin; i<end; ++i )
716        if(( err = tr_bitfieldAdd( bitfield, i )))
717            break;
718    return err;
719}
720
721int
722tr_bitfieldRem( tr_bitfield   * bitfield,
723                size_t          nth )
724{
725    static const uint8_t rems[8] = { 127, 191, 223, 239, 247, 251, 253, 254 };
726    const size_t i = nth >> 3u;
727
728    assert( bitfield != NULL );
729    assert( bitfield->bits != NULL );
730
731    if( i >= bitfield->len )
732        return -1;
733
734    bitfield->bits[i] &= rems[nth&7u];
735    assert( !tr_bitfieldHas( bitfield, nth ) );
736    return 0;
737}
738
739int
740tr_bitfieldRemRange ( tr_bitfield  * b,
741                      size_t         begin,
742                      size_t         end )
743{
744    int err = 0;
745    size_t i;
746    for( i=begin; i<end; ++i )
747        if(( err = tr_bitfieldRem( b, i )))
748            break;
749    return err;
750}
751
752tr_bitfield*
753tr_bitfieldOr( tr_bitfield * a, const tr_bitfield * b )
754{
755    uint8_t *ait;
756    const uint8_t *aend, *bit;
757
758    assert( a->len == b->len );
759
760    for( ait=a->bits, bit=b->bits, aend=ait+a->len; ait!=aend; )
761        *ait++ |= *bit++;
762
763    return a;
764}
765
766size_t
767tr_bitfieldCountTrueBits( const tr_bitfield* b )
768{
769    size_t ret = 0;
770    const uint8_t *it, *end;
771    static const int trueBitCount[512] = {
772        0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
773        1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
774        1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
775        2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
776        1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
777        2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
778        2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
779        3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,
780        1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
781        2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
782        2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
783        3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,
784        2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
785        3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,
786        3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,
787        4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9
788    };
789
790    if( !b )
791        return 0;
792
793    for( it=b->bits, end=it+b->len; it!=end; ++it )
794        ret += trueBitCount[*it];
795
796    return ret;
797}
798
799/***
800****
801***/
802
803uint64_t
804tr_date( void )
805{
806    struct timeval tv;
807    gettimeofday( &tv, NULL );
808    return (uint64_t) tv.tv_sec * 1000 + ( tv.tv_usec / 1000 );
809}
810
811void
812tr_wait( uint64_t delay_milliseconds )
813{
814#ifdef __BEOS__
815    snooze( 1000 * delay_milliseconds );
816#elif defined(WIN32)
817    Sleep( (DWORD)delay_milliseconds );
818#else
819    usleep( 1000 * delay_milliseconds );
820#endif
821}
822
823/***
824****
825***/
826
827
828#ifndef HAVE_STRLCPY
829
830/*
831 * Copy src to string dst of size siz.  At most siz-1 characters
832 * will be copied.  Always NUL terminates (unless siz == 0).
833 * Returns strlen(src); if retval >= siz, truncation occurred.
834 */
835size_t
836strlcpy(char *dst, const char *src, size_t siz)
837{
838        char *d = dst;
839        const char *s = src;
840        size_t n = siz;
841
842        /* Copy as many bytes as will fit */
843        if (n != 0) {
844                while (--n != 0) {
845                        if ((*d++ = *s++) == '\0')
846                                break;
847                }
848        }
849
850        /* Not enough room in dst, add NUL and traverse rest of src */
851        if (n == 0) {
852                if (siz != 0)
853                        *d = '\0';              /* NUL-terminate dst */
854                while (*s++)
855                        ;
856        }
857
858        return(s - src - 1);    /* count does not include NUL */
859}
860
861#endif /* HAVE_STRLCPY */
862
863
864#ifndef HAVE_STRLCAT
865
866/*
867 * Appends src to string dst of size siz (unlike strncat, siz is the
868 * full size of dst, not space left).  At most siz-1 characters
869 * will be copied.  Always NUL terminates (unless siz <= strlen(dst)).
870 * Returns strlen(src) + MIN(siz, strlen(initial dst)).
871 * If retval >= siz, truncation occurred.
872 */
873size_t
874strlcat(char *dst, const char *src, size_t siz)
875{
876        char *d = dst;
877        const char *s = src;
878        size_t n = siz;
879        size_t dlen;
880
881        /* Find the end of dst and adjust bytes left but don't go past end */
882        while (n-- != 0 && *d != '\0')
883                d++;
884        dlen = d - dst;
885        n = siz - dlen;
886
887        if (n == 0)
888                return(dlen + strlen(s));
889        while (*s != '\0') {
890                if (n != 1) {
891                        *d++ = *s;
892                        n--;
893                }
894                s++;
895        }
896        *d = '\0';
897
898        return(dlen + (s - src));       /* count does not include NUL */
899}
900
901#endif /* HAVE_STRLCAT */
902
903/***
904****
905***/
906
907double
908tr_getRatio( double numerator, double denominator )
909{
910    double ratio;
911
912    if( denominator )
913        ratio = numerator / denominator;
914    else if( numerator )
915        ratio = TR_RATIO_INF;
916    else
917        ratio = TR_RATIO_NA;
918
919    return ratio;
920}
921
922void
923tr_sha1_to_hex( char * out, const uint8_t * sha1 )
924{
925    static const char hex[] = "0123456789abcdef";
926    int i;
927    for (i = 0; i < 20; i++) {
928        unsigned int val = *sha1++;
929        *out++ = hex[val >> 4];
930        *out++ = hex[val & 0xf];
931    }
932    *out = '\0';
933}
Note: See TracBrowser for help on using the repository browser.