source: trunk/libtransmission/utils.c @ 8681

Last change on this file since 8681 was 8681, checked in by charles, 13 years ago

(trunk libT) possible fix for #2078: Assertion failed: (tv->tv_usec >= 0)

  • Property svn:keywords set to Date Rev Author Id
File size: 36.9 KB
Line 
1/*
2 * This file Copyright (C) 2009 Charles Kerr <charles@transmissionbt.com>
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: utils.c 8681 2009-06-12 23:01:35Z charles $
11 */
12
13#ifdef HAVE_MEMMEM
14 #define _GNU_SOURCE /* glibc's string.h needs this to pick up memmem */
15#endif
16
17#include <assert.h>
18#include <ctype.h> /* isalpha, tolower */
19#include <errno.h>
20#include <stdarg.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h> /* strerror, memset, memmem */
24
25#include <libgen.h> /* basename */
26#include <sys/time.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <unistd.h> /* usleep, stat, getcwd */
30
31#include "event.h"
32
33#ifdef WIN32
34 #include <direct.h> /* _getcwd */
35 #include <windows.h> /* Sleep */
36#endif
37
38#include "transmission.h"
39#include "fdlimit.h"
40#include "ConvertUTF.h"
41#include "list.h"
42#include "utils.h"
43#include "platform.h"
44#include "version.h"
45
46static tr_lock *      messageLock = NULL;
47static int            messageLevel = 0;
48static tr_bool        messageQueuing = FALSE;
49static tr_msg_list *  messageQueue = NULL;
50static tr_msg_list ** messageQueueTail = &messageQueue;
51
52#ifndef WIN32
53    /* make null versions of these win32 functions */
54    static int IsDebuggerPresent( void ) { return FALSE; }
55    static void OutputDebugString( const void * unused UNUSED ) { }
56#endif
57
58static void
59tr_msgInit( void )
60{
61    static tr_bool initialized = FALSE;
62
63    if( !initialized )
64    {
65        char * env = getenv( "TR_DEBUG" );
66        messageLevel = ( env ? atoi( env ) : 0 ) + 1;
67        messageLevel = MAX( 1, messageLevel );
68
69        messageLock = tr_lockNew( );
70
71        initialized = TRUE;
72    }
73}
74
75FILE*
76tr_getLog( void )
77{
78    static int    initialized = FALSE;
79    static FILE * file = NULL;
80
81    if( !initialized )
82    {
83        const char * str = getenv( "TR_DEBUG_FD" );
84        int          fd = 0;
85        if( str && *str )
86            fd = atoi( str );
87        switch( fd )
88        {
89            case 1:
90                file = stdout; break;
91
92            case 2:
93                file = stderr; break;
94
95            default:
96                file = NULL; break;
97        }
98        initialized = TRUE;
99    }
100
101    return file;
102}
103
104void
105tr_setMessageLevel( int level )
106{
107    tr_msgInit( );
108    tr_lockLock( messageLock );
109
110    messageLevel = MAX( 0, level );
111
112    tr_lockUnlock( messageLock );
113}
114
115int
116tr_getMessageLevel( void )
117{
118    int ret;
119    tr_msgInit( );
120    tr_lockLock( messageLock );
121
122    ret = messageLevel;
123
124    tr_lockUnlock( messageLock );
125    return ret;
126}
127
128void
129tr_setMessageQueuing( tr_bool enabled )
130{
131    tr_msgInit( );
132    tr_lockLock( messageLock );
133
134    messageQueuing = enabled;
135
136    tr_lockUnlock( messageLock );
137}
138
139tr_bool
140tr_getMessageQueuing( void )
141{
142    int ret;
143    tr_msgInit( );
144    tr_lockLock( messageLock );
145
146    ret = messageQueuing;
147
148    tr_lockUnlock( messageLock );
149    return ret;
150}
151
152tr_msg_list *
153tr_getQueuedMessages( void )
154{
155    tr_msg_list * ret;
156    tr_msgInit( );
157    tr_lockLock( messageLock );
158
159    ret = messageQueue;
160    messageQueue = NULL;
161    messageQueueTail = &messageQueue;
162
163    tr_lockUnlock( messageLock );
164    return ret;
165}
166
167void
168tr_freeMessageList( tr_msg_list * list )
169{
170    tr_msg_list * next;
171
172    while( NULL != list )
173    {
174        next = list->next;
175        free( list->message );
176        free( list->name );
177        free( list );
178        list = next;
179    }
180}
181
182/**
183***
184**/
185
186struct tm *
187tr_localtime_r( const time_t *_clock, struct tm *_result )
188{
189#ifdef HAVE_LOCALTIME_R
190    return localtime_r( _clock, _result );
191#else
192    struct tm *p = localtime( _clock );
193    if( p )
194        *(_result) = *p;
195    return p;
196#endif
197}
198
199char*
200tr_getLogTimeStr( char * buf, int buflen )
201{
202    char           tmp[64];
203    time_t         now;
204    struct tm      now_tm;
205    struct timeval tv;
206    int            milliseconds;
207
208    now = time( NULL );
209    gettimeofday( &tv, NULL );
210
211    tr_localtime_r( &now, &now_tm );
212    strftime( tmp, sizeof( tmp ), "%H:%M:%S", &now_tm );
213    milliseconds = (int)( tv.tv_usec / 1000 );
214    tr_snprintf( buf, buflen, "%s.%03d", tmp, milliseconds );
215
216    return buf;
217}
218
219void
220tr_assertImpl( const char * file, int line, const char * test, const char * fmt, ... )
221{
222    char buf[64];
223    fprintf( stderr, "[%s] Transmission %s Assertion \"%s\" failed at %s:%d.  ",
224                     tr_getLogTimeStr( buf, sizeof( buf ) ),
225                      LONG_VERSION_STRING, test, file, line );
226    if( fmt && *fmt ) {
227        va_list args;
228        fputc( '(', stderr );
229        va_start( args, fmt );
230        vfprintf( stderr, fmt, args );
231        va_end( args );
232        fputs( ")  ", stderr );
233    }
234    fputs( "Please report this bug at <http://trac.transmissionbt.com/newticket>; Thank you.\n", stderr );
235    abort( );
236}
237
238
239tr_bool
240tr_deepLoggingIsActive( void )
241{
242    static int8_t deepLoggingIsActive = -1;
243
244    if( deepLoggingIsActive < 0 )
245        deepLoggingIsActive = IsDebuggerPresent() || (tr_getLog()!=NULL);
246
247    return deepLoggingIsActive != 0;
248}
249
250void
251tr_deepLog( const char  * file,
252            int           line,
253            const char  * name,
254            const char  * fmt,
255            ... )
256{
257    FILE * fp = tr_getLog( );
258    if( fp || IsDebuggerPresent( ) )
259    {
260        va_list           args;
261        char              timestr[64];
262        struct evbuffer * buf = tr_getBuffer( );
263        char *            base = tr_basename( file );
264
265        evbuffer_add_printf( buf, "[%s] ",
266                            tr_getLogTimeStr( timestr, sizeof( timestr ) ) );
267        if( name )
268            evbuffer_add_printf( buf, "%s ", name );
269        va_start( args, fmt );
270        evbuffer_add_vprintf( buf, fmt, args );
271        va_end( args );
272        evbuffer_add_printf( buf, " (%s:%d)\n", base, line );
273        /* FIXME(libevent2) ifdef this out for nonwindows platforms */
274        OutputDebugString( EVBUFFER_DATA( buf ) );
275        if(fp) /* FIXME(libevent2) tr_getLog() should return an fd, then use evbuffer_write() here ) */
276            (void) fwrite( EVBUFFER_DATA( buf ), 1, EVBUFFER_LENGTH( buf ), fp );
277
278        tr_free( base );
279        tr_releaseBuffer( buf );
280    }
281}
282
283/***
284****
285***/
286   
287
288int
289tr_msgLoggingIsActive( int level )
290{
291    tr_msgInit( );
292
293    return messageLevel >= level;
294}
295
296void
297tr_msg( const char * file, int line,
298        int level, const char * name,
299        const char * fmt, ... )
300{
301    const int err = errno; /* message logging shouldn't affect errno */
302    FILE * fp;
303    tr_msgInit( );
304    tr_lockLock( messageLock );
305
306    fp = tr_getLog( );
307
308    if( messageLevel >= level )
309    {
310        char buf[MAX_STACK_ARRAY_SIZE];
311        va_list ap;
312
313        /* build the text message */
314        *buf = '\0';
315        va_start( ap, fmt );
316        evutil_vsnprintf( buf, sizeof( buf ), fmt, ap );
317        va_end( ap );
318
319        OutputDebugString( buf );
320
321        if( *buf )
322        {
323            if( messageQueuing )
324            {
325                tr_msg_list * newmsg;
326                newmsg = tr_new0( tr_msg_list, 1 );
327                newmsg->level = level;
328                newmsg->when = time( NULL );
329                newmsg->message = tr_strdup( buf );
330                newmsg->file = file;
331                newmsg->line = line;
332                newmsg->name = tr_strdup( name );
333
334                *messageQueueTail = newmsg;
335                messageQueueTail = &newmsg->next;
336            }
337            else
338            {
339                char timestr[64];
340
341                if( fp == NULL )
342                    fp = stderr;
343
344                tr_getLogTimeStr( timestr, sizeof( timestr ) );
345
346                if( name )
347                    fprintf( fp, "[%s] %s: %s\n", timestr, name, buf );
348                else
349                    fprintf( fp, "[%s] %s\n", timestr, buf );
350                fflush( fp );
351            }
352        }
353    }
354
355    tr_lockUnlock( messageLock );
356    errno = err;
357}
358
359/***
360****
361***/
362
363void
364tr_set_compare( const void * va,
365                size_t aCount,
366                const void * vb,
367                size_t bCount,
368                int compare( const void * a, const void * b ),
369                size_t elementSize,
370                tr_set_func in_a_cb,
371                tr_set_func in_b_cb,
372                tr_set_func in_both_cb,
373                void * userData )
374{
375    const uint8_t * a = (const uint8_t *) va;
376    const uint8_t * b = (const uint8_t *) vb;
377    const uint8_t * aend = a + elementSize * aCount;
378    const uint8_t * bend = b + elementSize * bCount;
379
380    while( a != aend || b != bend )
381    {
382        if( a == aend )
383        {
384            ( *in_b_cb )( (void*)b, userData );
385            b += elementSize;
386        }
387        else if( b == bend )
388        {
389            ( *in_a_cb )( (void*)a, userData );
390            a += elementSize;
391        }
392        else
393        {
394            const int val = ( *compare )( a, b );
395
396            if( !val )
397            {
398                ( *in_both_cb )( (void*)a, userData );
399                a += elementSize;
400                b += elementSize;
401            }
402            else if( val < 0 )
403            {
404                ( *in_a_cb )( (void*)a, userData );
405                a += elementSize;
406            }
407            else if( val > 0 )
408            {
409                ( *in_b_cb )( (void*)b, userData );
410                b += elementSize;
411            }
412        }
413    }
414}
415
416/***
417****
418***/
419
420#ifdef DISABLE_GETTEXT
421
422const char*
423tr_strip_positional_args( const char* str )
424{
425    static size_t bufsize = 0;
426    static char * buf = NULL;
427    const size_t  len = strlen( str );
428    char *        out;
429
430    if( bufsize < len )
431    {
432        bufsize = len * 2;
433        buf = tr_renew( char, buf, bufsize );
434    }
435
436    for( out = buf; *str; ++str )
437    {
438        *out++ = *str;
439        if( ( *str == '%' ) && isdigit( str[1] ) )
440        {
441            const char * tmp = str + 1;
442            while( isdigit( *tmp ) )
443                ++tmp;
444
445            if( *tmp == '$' )
446                str = tmp;
447        }
448    }
449    *out = '\0';
450
451    return buf;
452}
453
454#endif
455
456/**
457***
458**/
459
460tr_bool
461tr_isTimeval( const struct timeval * tv )
462{
463    return tv && ( tv->tv_sec >= 0 )
464              && ( tv->tv_usec >= 0 )
465              && ( tv->tv_usec < 1000000 );
466}
467
468void
469tr_timevalMsec( uint64_t milliseconds, struct timeval * setme )
470{
471    const uint64_t microseconds = milliseconds * 1000;
472    assert( setme != NULL );
473    setme->tv_sec  = microseconds / 1000000;
474    setme->tv_usec = microseconds % 1000000;
475    assert( tr_isTimeval( setme ) );
476}
477
478void
479tr_timevalSet( struct timeval * setme, int seconds, int microseconds )
480{
481    setme->tv_sec = seconds;
482    setme->tv_usec = microseconds;
483    assert( tr_isTimeval( setme ) );
484}
485
486
487/**
488***
489**/
490
491uint8_t *
492tr_loadFile( const char * path,
493             size_t *     size )
494{
495    uint8_t * buf;
496    struct stat  sb;
497    int fd;
498    ssize_t n;
499    const char * err_fmt = _( "Couldn't read \"%1$s\": %2$s" );
500
501    /* try to stat the file */
502    errno = 0;
503    if( stat( path, &sb ) )
504    {
505        const int err = errno;
506        tr_dbg( err_fmt, path, tr_strerror( errno ) );
507        errno = err;
508        return NULL;
509    }
510
511    if( ( sb.st_mode & S_IFMT ) != S_IFREG )
512    {
513        tr_err( err_fmt, path, _( "Not a regular file" ) );
514        errno = EISDIR;
515        return NULL;
516    }
517
518    /* Load the torrent file into our buffer */
519    fd = tr_open_file_for_scanning( path );
520    if( fd < 0 )
521    {
522        const int err = errno;
523        tr_err( err_fmt, path, tr_strerror( errno ) );
524        errno = err;
525        return NULL;
526    }
527    buf = malloc( sb.st_size + 1 );
528    if( !buf )
529    {
530        const int err = errno;
531        tr_err( err_fmt, path, _( "Memory allocation failed" ) );
532        tr_close_file( fd );
533        errno = err;
534        return NULL;
535    }
536    n = read( fd, buf, sb.st_size );
537    if( n == -1 )
538    {
539        const int err = errno;
540        tr_err( err_fmt, path, tr_strerror( errno ) );
541        tr_close_file( fd );
542        free( buf );
543        errno = err;
544        return NULL;
545    }
546
547    tr_close_file( fd );
548    buf[ sb.st_size ] = '\0';
549    *size = sb.st_size;
550    return buf;
551}
552
553char*
554tr_basename( const char * path )
555{
556    char * tmp = tr_strdup( path );
557    char * ret = tr_strdup( basename( tmp ) );
558    tr_free( tmp );
559    return ret;
560}
561
562char*
563tr_dirname( const char * path )
564{
565    char * tmp = tr_strdup( path );
566    char * ret = tr_strdup( dirname( tmp ) );
567    tr_free( tmp );
568    return ret;
569}
570
571int
572tr_mkdir( const char * path,
573          int permissions
574#ifdef WIN32
575                       UNUSED
576#endif
577        )
578{
579#ifdef WIN32
580    if( path && isalpha( path[0] ) && path[1] == ':' && !path[2] )
581        return 0;
582    return mkdir( path );
583#else
584    return mkdir( path, permissions );
585#endif
586}
587
588int
589tr_mkdirp( const char * path_in,
590           int          permissions )
591{
592    char *      path = tr_strdup( path_in );
593    char *      p, * pp;
594    struct stat sb;
595    int         done;
596
597    /* walk past the root */
598    p = path;
599    while( *p == TR_PATH_DELIMITER )
600        ++p;
601
602    pp = p;
603    done = 0;
604    while( ( p =
605                strchr( pp, TR_PATH_DELIMITER ) ) || ( p = strchr( pp, '\0' ) ) )
606    {
607        if( !*p )
608            done = 1;
609        else
610            *p = '\0';
611
612        if( stat( path, &sb ) )
613        {
614            /* Folder doesn't exist yet */
615            if( tr_mkdir( path, permissions ) )
616            {
617                const int err = errno;
618                tr_err( _(
619                           "Couldn't create \"%1$s\": %2$s" ), path,
620                       tr_strerror( err ) );
621                tr_free( path );
622                errno = err;
623                return -1;
624            }
625        }
626        else if( ( sb.st_mode & S_IFMT ) != S_IFDIR )
627        {
628            /* Node exists but isn't a folder */
629            char * buf = tr_strdup_printf( _( "File \"%s\" is in the way" ), path );
630            tr_err( _( "Couldn't create \"%1$s\": %2$s" ), path_in, buf );
631            tr_free( buf );
632            tr_free( path );
633            errno = ENOTDIR;
634            return -1;
635        }
636
637        if( done )
638            break;
639
640        *p = TR_PATH_DELIMITER;
641        p++;
642        pp = p;
643    }
644
645    tr_free( path );
646    return 0;
647}
648
649char*
650tr_buildPath( const char *first_element, ... )
651{
652    size_t bufLen = 0;
653    const char * element;
654    char * buf;
655    char * pch;
656    va_list vl;
657
658    /* pass 1: allocate enough space for the string */
659    va_start( vl, first_element );
660    element = first_element;
661    while( element ) {
662        bufLen += strlen( element ) + 1;
663        element = (const char*) va_arg( vl, const char* );
664    }
665    pch = buf = tr_new( char, bufLen );
666    va_end( vl );
667
668    /* pass 2: build the string piece by piece */
669    va_start( vl, first_element );
670    element = first_element;
671    while( element ) {
672        const size_t elementLen = strlen( element );
673        memcpy( pch, element, elementLen );
674        pch += elementLen;
675        *pch++ = TR_PATH_DELIMITER;
676        element = (const char*) va_arg( vl, const char* );
677    }
678    va_end( vl );
679
680    /* terminate the string.  if nonempty, eat the unwanted trailing slash */
681    if( pch != buf )
682        --pch;
683    *pch++ = '\0';
684
685    /* sanity checks & return */
686    assert( pch - buf == (off_t)bufLen );
687    return buf;
688}
689
690/****
691*****
692****/
693
694char*
695tr_strndup( const void * in, int len )
696{
697    char * out = NULL;
698
699    if( len < 0 )
700    {
701        out = tr_strdup( in );
702    }
703    else if( in )
704    {
705        out = tr_malloc( len + 1 );
706        memcpy( out, in, len );
707        out[len] = '\0';
708    }
709
710    return out;
711}
712
713const char*
714tr_memmem( const char * haystack, size_t haystacklen,
715           const char * needle, size_t needlelen )
716{
717#ifdef HAVE_MEMMEM
718    return memmem( haystack, haystacklen, needle, needlelen );
719#else
720    size_t i;
721    if( !needlelen )
722        return haystack;
723    if( needlelen > haystacklen || !haystack || !needle )
724        return NULL;
725    for( i=0; i<=haystacklen-needlelen; ++i )
726        if( !memcmp( haystack+i, needle, needlelen ) )
727            return haystack+i;
728    return NULL;
729#endif
730}
731
732char*
733tr_strdup_printf( const char * fmt, ... )
734{
735    char *            ret = NULL;
736    struct evbuffer * buf;
737    va_list           ap;
738
739    buf = tr_getBuffer( );
740    va_start( ap, fmt );
741
742    if( evbuffer_add_vprintf( buf, fmt, ap ) != -1 )
743        ret = tr_strdup( EVBUFFER_DATA( buf ) );
744
745    va_end( ap );
746    tr_releaseBuffer( buf );
747    return ret;
748}
749
750const char*
751tr_strerror( int i )
752{
753    const char * ret = strerror( i );
754
755    if( ret == NULL )
756        ret = "Unknown Error";
757    return ret;
758}
759
760/****
761*****
762****/
763
764char*
765tr_strstrip( char * str )
766{
767    if( str != NULL )
768    {
769        size_t pos;
770        size_t len = strlen( str );
771
772        while( len && isspace( str[len - 1] ) )
773            --len;
774
775        str[len] = '\0';
776
777        for( pos = 0; pos < len && isspace( str[pos] ); )
778            ++pos;
779
780        len -= pos;
781        memmove( str, str + pos, len );
782        str[len] = '\0';
783    }
784
785    return str;
786}
787
788/****
789*****
790****/
791
792tr_bitfield*
793tr_bitfieldConstruct( tr_bitfield * b, size_t bitCount )
794{
795    b->bitCount = bitCount;
796    b->byteCount = ( bitCount + 7u ) / 8u;
797    b->bits = tr_new0( uint8_t, b->byteCount );
798    return b;
799}
800
801tr_bitfield*
802tr_bitfieldDestruct( tr_bitfield * b )
803{
804    if( b )
805        tr_free( b->bits );
806    return b;
807}
808
809tr_bitfield*
810tr_bitfieldDup( const tr_bitfield * in )
811{
812    tr_bitfield * ret = tr_new0( tr_bitfield, 1 );
813
814    ret->bitCount = in->bitCount;
815    ret->byteCount = in->byteCount;
816    ret->bits = tr_memdup( in->bits, in->byteCount );
817    return ret;
818}
819
820void
821tr_bitfieldClear( tr_bitfield * bitfield )
822{
823    memset( bitfield->bits, 0, bitfield->byteCount );
824}
825
826int
827tr_bitfieldIsEmpty( const tr_bitfield * bitfield )
828{
829    size_t i;
830
831    for( i = 0; i < bitfield->byteCount; ++i )
832        if( bitfield->bits[i] )
833            return 0;
834
835    return 1;
836}
837
838int
839tr_bitfieldAdd( tr_bitfield * bitfield,
840                size_t        nth )
841{
842    assert( bitfield );
843    assert( bitfield->bits );
844
845    if( nth >= bitfield->bitCount )
846        return -1;
847
848    bitfield->bits[nth >> 3u] |= ( 0x80 >> ( nth & 7u ) );
849    return 0;
850}
851
852/* Sets bit range [begin, end) to 1 */
853int
854tr_bitfieldAddRange( tr_bitfield * b,
855                     size_t        begin,
856                     size_t        end )
857{
858    size_t        sb, eb;
859    unsigned char sm, em;
860
861    end--;
862
863    if( ( end >= b->bitCount ) || ( begin > end ) )
864        return -1;
865
866    sb = begin >> 3;
867    sm = ~( 0xff << ( 8 - ( begin & 7 ) ) );
868    eb = end >> 3;
869    em = 0xff << ( 7 - ( end & 7 ) );
870
871    if( sb == eb )
872    {
873        b->bits[sb] |= ( sm & em );
874    }
875    else
876    {
877        b->bits[sb] |= sm;
878        b->bits[eb] |= em;
879        if( ++sb < eb )
880            memset ( b->bits + sb, 0xff, eb - sb );
881    }
882
883    return 0;
884}
885
886int
887tr_bitfieldRem( tr_bitfield * bitfield,
888                size_t        nth )
889{
890    assert( bitfield );
891    assert( bitfield->bits );
892
893    if( nth >= bitfield->bitCount )
894        return -1;
895
896    bitfield->bits[nth >> 3u] &= ( 0xff7f >> ( nth & 7u ) );
897    return 0;
898}
899
900/* Clears bit range [begin, end) to 0 */
901int
902tr_bitfieldRemRange( tr_bitfield * b,
903                     size_t        begin,
904                     size_t        end )
905{
906    size_t        sb, eb;
907    unsigned char sm, em;
908
909    end--;
910
911    if( ( end >= b->bitCount ) || ( begin > end ) )
912        return -1;
913
914    sb = begin >> 3;
915    sm = 0xff << ( 8 - ( begin & 7 ) );
916    eb = end >> 3;
917    em = ~( 0xff << ( 7 - ( end & 7 ) ) );
918
919    if( sb == eb )
920    {
921        b->bits[sb] &= ( sm | em );
922    }
923    else
924    {
925        b->bits[sb] &= sm;
926        b->bits[eb] &= em;
927        if( ++sb < eb )
928            memset ( b->bits + sb, 0, eb - sb );
929    }
930
931    return 0;
932}
933
934tr_bitfield*
935tr_bitfieldOr( tr_bitfield *       a,
936               const tr_bitfield * b )
937{
938    uint8_t *      ait;
939    const uint8_t *aend, *bit;
940
941    assert( a->bitCount == b->bitCount );
942
943    for( ait = a->bits, bit = b->bits, aend = ait + a->byteCount;
944         ait != aend; )
945        *ait++ |= *bit++;
946
947    return a;
948}
949
950/* set 'a' to all the flags that were in 'a' but not 'b' */
951void
952tr_bitfieldDifference( tr_bitfield *       a,
953                       const tr_bitfield * b )
954{
955    uint8_t *      ait;
956    const uint8_t *aend, *bit;
957
958    assert( a->bitCount == b->bitCount );
959
960    for( ait = a->bits, bit = b->bits, aend = ait + a->byteCount;
961         ait != aend; )
962        *ait++ &= ~( *bit++ );
963}
964
965size_t
966tr_bitfieldCountTrueBits( const tr_bitfield* b )
967{
968    size_t           ret = 0;
969    const uint8_t *  it, *end;
970    static const int trueBitCount[512] = {
971        0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3,
972        4, 2, 3, 3, 4, 3, 4, 4, 5,
973        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
974        5, 3, 4, 4, 5, 4, 5, 5, 6,
975        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
976        5, 3, 4, 4, 5, 4, 5, 5, 6,
977        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
978        6, 4, 5, 5, 6, 5, 6, 6, 7,
979        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
980        5, 3, 4, 4, 5, 4, 5, 5, 6,
981        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
982        6, 4, 5, 5, 6, 5, 6, 6, 7,
983        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
984        6, 4, 5, 5, 6, 5, 6, 6, 7,
985        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
986        7, 5, 6, 6, 7, 6, 7, 7, 8,
987        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
988        5, 3, 4, 4, 5, 4, 5, 5, 6,
989        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
990        6, 4, 5, 5, 6, 5, 6, 6, 7,
991        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
992        6, 4, 5, 5, 6, 5, 6, 6, 7,
993        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
994        7, 5, 6, 6, 7, 6, 7, 7, 8,
995        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5,
996        6, 4, 5, 5, 6, 5, 6, 6, 7,
997        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
998        7, 5, 6, 6, 7, 6, 7, 7, 8,
999        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6,
1000        7, 5, 6, 6, 7, 6, 7, 7, 8,
1001        4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, 5, 6, 6, 7, 6, 7, 7,
1002        8, 6, 7, 7, 8, 7, 8, 8, 9
1003    };
1004
1005    if( !b )
1006        return 0;
1007
1008    for( it = b->bits, end = it + b->byteCount; it != end; ++it )
1009        ret += trueBitCount[*it];
1010
1011    return ret;
1012}
1013
1014/***
1015****
1016***/
1017
1018uint64_t
1019tr_date( void )
1020{
1021    struct timeval tv;
1022
1023    gettimeofday( &tv, NULL );
1024    return (uint64_t) tv.tv_sec * 1000 + ( tv.tv_usec / 1000 );
1025}
1026
1027void
1028tr_wait( uint64_t delay_milliseconds )
1029{
1030#ifdef WIN32
1031    Sleep( (DWORD)delay_milliseconds );
1032#else
1033    usleep( 1000 * delay_milliseconds );
1034#endif
1035}
1036
1037/***
1038****
1039***/
1040
1041int
1042tr_snprintf( char *       buf,
1043             size_t       buflen,
1044             const char * fmt,
1045             ... )
1046{
1047    int     len;
1048    va_list args;
1049
1050    va_start( args, fmt );
1051    len = evutil_vsnprintf( buf, buflen, fmt, args );
1052    va_end( args );
1053    return len;
1054}
1055
1056/*
1057 * Copy src to string dst of size siz.  At most siz-1 characters
1058 * will be copied.  Always NUL terminates (unless siz == 0).
1059 * Returns strlen(src); if retval >= siz, truncation occurred.
1060 */
1061size_t
1062tr_strlcpy( char *       dst,
1063            const void * src,
1064            size_t       siz )
1065{
1066#ifdef HAVE_STRLCPY
1067    return strlcpy( dst, src, siz );
1068#else
1069    char *      d = dst;
1070    const char *s = src;
1071    size_t      n = siz;
1072
1073    assert( s );
1074    assert( d );
1075
1076    /* Copy as many bytes as will fit */
1077    if( n != 0 )
1078    {
1079        while( --n != 0 )
1080        {
1081            if( ( *d++ = *s++ ) == '\0' )
1082                break;
1083        }
1084    }
1085
1086    /* Not enough room in dst, add NUL and traverse rest of src */
1087    if( n == 0 )
1088    {
1089        if( siz != 0 )
1090            *d = '\0'; /* NUL-terminate dst */
1091        while( *s++ )
1092            ;
1093    }
1094
1095    return s - (char*)src - 1;  /* count does not include NUL */
1096#endif
1097}
1098
1099/***
1100****
1101***/
1102
1103double
1104tr_getRatio( double numerator,
1105             double denominator )
1106{
1107    double ratio;
1108
1109    if( denominator )
1110        ratio = numerator / denominator;
1111    else if( numerator )
1112        ratio = TR_RATIO_INF;
1113    else
1114        ratio = TR_RATIO_NA;
1115
1116    return ratio;
1117}
1118
1119void
1120tr_sha1_to_hex( char *          out,
1121                const uint8_t * sha1 )
1122{
1123    static const char hex[] = "0123456789abcdef";
1124    int               i;
1125
1126    for( i = 0; i < 20; i++ )
1127    {
1128        unsigned int val = *sha1++;
1129        *out++ = hex[val >> 4];
1130        *out++ = hex[val & 0xf];
1131    }
1132    *out = '\0';
1133}
1134
1135/***
1136****
1137***/
1138
1139int
1140tr_httpIsValidURL( const char * url )
1141{
1142    const char *        c;
1143    static const char * rfc2396_valid_chars =
1144        "abcdefghijklmnopqrstuvwxyz" /* lowalpha */
1145        "ABCDEFGHIJKLMNOPQRSTUVWXYZ" /* upalpha */
1146        "0123456789"                 /* digit */
1147        "-_.!~*'()"                  /* mark */
1148        ";/?:@&=+$,"                 /* reserved */
1149        "<>#%<\""                    /* delims */
1150        "{}|\\^[]`";                 /* unwise */
1151
1152    if( url == NULL )
1153        return FALSE;
1154
1155    for( c = url; c && *c; ++c )
1156        if( !strchr( rfc2396_valid_chars, *c ) )
1157            return FALSE;
1158
1159    return !tr_httpParseURL( url, -1, NULL, NULL, NULL );
1160}
1161
1162int
1163tr_httpParseURL( const char * url_in,
1164                 int          len,
1165                 char **      setme_host,
1166                 int *        setme_port,
1167                 char **      setme_path )
1168{
1169    int          err;
1170    int          port = 0;
1171    int          n;
1172    char *       tmp;
1173    char *       pch;
1174    const char * protocol = NULL;
1175    const char * host = NULL;
1176    const char * path = NULL;
1177
1178    tmp = tr_strndup( url_in, len );
1179    if( ( pch = strstr( tmp, "://" ) ) )
1180    {
1181        *pch = '\0';
1182        protocol = tmp;
1183        pch += 3;
1184/*fprintf( stderr, "protocol is [%s]... what's left is [%s]\n", protocol, pch
1185  );*/
1186        if( ( n = strcspn( pch, ":/" ) ) )
1187        {
1188            const int havePort = pch[n] == ':';
1189            host = pch;
1190            pch += n;
1191            *pch++ = '\0';
1192/*fprintf( stderr, "host is [%s]... what's left is [%s]\n", host, pch );*/
1193            if( havePort )
1194            {
1195                char * end;
1196                port = strtol( pch, &end, 10 );
1197                pch = end;
1198/*fprintf( stderr, "port is [%d]... what's left is [%s]\n", port, pch );*/
1199            }
1200            path = pch;
1201/*fprintf( stderr, "path is [%s]\n", path );*/
1202        }
1203    }
1204
1205    err = !host || !path || !protocol
1206          || ( strcmp( protocol, "http" ) && strcmp( protocol, "https" ) );
1207
1208    if( !err && !port )
1209    {
1210        if( !strcmp( protocol, "http" ) ) port = 80;
1211        if( !strcmp( protocol, "https" ) ) port = 443;
1212    }
1213
1214    if( !err )
1215    {
1216        if( setme_host ){ ( (char*)host )[-3] = ':'; *setme_host =
1217                              tr_strdup( protocol ); }
1218        if( setme_path ){ ( (char*)path )[-1] = '/'; *setme_path =
1219                              tr_strdup( path - 1 ); }
1220        if( setme_port ) *setme_port = port;
1221    }
1222
1223
1224    tr_free( tmp );
1225    return err;
1226}
1227
1228#include <string.h>
1229#include <openssl/sha.h>
1230#include <openssl/hmac.h>
1231#include <openssl/evp.h>
1232#include <openssl/bio.h>
1233#include <openssl/buffer.h>
1234
1235char *
1236tr_base64_encode( const void * input,
1237                  int          length,
1238                  int *        setme_len )
1239{
1240    char *    ret;
1241    BIO *     b64;
1242    BIO *     bmem;
1243    BUF_MEM * bptr;
1244
1245    if( length < 1 )
1246        length = strlen( input );
1247
1248    bmem = BIO_new( BIO_s_mem( ) );
1249    b64 = BIO_new( BIO_f_base64( ) );
1250    b64 = BIO_push( b64, bmem );
1251    BIO_write( b64, input, length );
1252    (void) BIO_flush( b64 );
1253    BIO_get_mem_ptr( b64, &bptr );
1254    ret = tr_strndup( bptr->data, bptr->length );
1255    if( setme_len )
1256        *setme_len = bptr->length;
1257
1258    BIO_free_all( b64 );
1259    return ret;
1260}
1261
1262char *
1263tr_base64_decode( const void * input,
1264                  int          length,
1265                  int *        setme_len )
1266{
1267    char * ret;
1268    BIO *  b64;
1269    BIO *  bmem;
1270    int    retlen;
1271
1272    if( length < 1 )
1273        length = strlen( input );
1274
1275    ret = tr_new0( char, length );
1276    b64 = BIO_new( BIO_f_base64( ) );
1277    bmem = BIO_new_mem_buf( (unsigned char*)input, length );
1278    bmem = BIO_push( b64, bmem );
1279    retlen = BIO_read( bmem, ret, length );
1280    if( !retlen )
1281    {
1282        /* try again, but with the BIO_FLAGS_BASE64_NO_NL flag */
1283        BIO_free_all( bmem );
1284        b64 = BIO_new( BIO_f_base64( ) );
1285        BIO_set_flags( b64, BIO_FLAGS_BASE64_NO_NL );
1286        bmem = BIO_new_mem_buf( (unsigned char*)input, length );
1287        bmem = BIO_push( b64, bmem );
1288        retlen = BIO_read( bmem, ret, length );
1289    }
1290
1291    if( setme_len )
1292        *setme_len = retlen;
1293
1294    BIO_free_all( bmem );
1295    return ret;
1296}
1297
1298int
1299tr_ptr2int( void* v )
1300{
1301    return (intptr_t)v;
1302}
1303
1304void*
1305tr_int2ptr( int i )
1306{
1307    return (void*)(intptr_t)i;
1308}
1309
1310/***
1311****
1312***/
1313
1314static tr_list * _bufferList = NULL;
1315
1316static tr_lock *
1317getBufferLock( void )
1318{
1319    static tr_lock * lock = NULL;
1320    if( lock == NULL )
1321        lock = tr_lockNew( );
1322    return lock;
1323}
1324
1325struct evbuffer*
1326tr_getBuffer( void )
1327{
1328    struct evbuffer * buf;
1329    tr_lock * l = getBufferLock( );
1330    tr_lockLock( l );
1331
1332    buf = tr_list_pop_front( &_bufferList );
1333    if( buf == NULL )
1334        buf = evbuffer_new( );
1335
1336    tr_lockUnlock( l );
1337    return buf;
1338}
1339
1340void
1341tr_releaseBuffer( struct evbuffer * buf )
1342{
1343    tr_lock * l = getBufferLock( );
1344    tr_lockLock( l );
1345
1346    evbuffer_drain( buf, EVBUFFER_LENGTH( buf ) );
1347    assert( EVBUFFER_LENGTH( buf ) == 0 );
1348    tr_list_prepend( &_bufferList, buf );
1349
1350    tr_lockUnlock( l );
1351}
1352
1353/***
1354****
1355***/
1356
1357int
1358tr_lowerBound( const void * key,
1359               const void * base,
1360               size_t       nmemb,
1361               size_t       size,
1362               int       (* compar)(const void* key, const void* arrayMember),
1363               tr_bool    * exact_match )
1364{
1365    size_t first = 0;
1366    const char * cbase = base;
1367
1368    while( nmemb )
1369    {
1370        const size_t half = nmemb / 2;
1371        const size_t middle = first + half;
1372        const int c = compar( key, cbase + size*middle );
1373
1374        if( c < 0 )
1375        {
1376            first = middle + 1;
1377            nmemb = nmemb - half - 1;
1378        }
1379        else if( !c )
1380        {
1381            if( exact_match )
1382                *exact_match = TRUE;
1383            return middle;
1384        }
1385        else
1386        {
1387            nmemb = half;
1388        }
1389    }
1390
1391    if( exact_match )
1392        *exact_match = FALSE;
1393
1394    return first;
1395}
1396
1397/***
1398****
1399***/
1400
1401char*
1402tr_utf8clean( const char * str, int max_len, tr_bool * err )
1403{
1404    char * ret;
1405    const char * end;
1406
1407    if( max_len < 0 )
1408        max_len = (int) strlen( str );
1409
1410    if( err != NULL )
1411        *err = FALSE;
1412
1413    if( tr_utf8_validate( str, max_len, &end  ) )
1414    {
1415        ret = tr_strndup( str, max_len );
1416    }
1417    else
1418    {
1419        const char zero = '\0';
1420        struct evbuffer * buf = evbuffer_new( );
1421
1422        while( !tr_utf8_validate ( str, max_len, &end ) )
1423        {
1424            const int good_len = end - str;
1425
1426            evbuffer_add( buf, str, good_len );
1427            max_len -= ( good_len + 1 );
1428            str += ( good_len + 1 );
1429            evbuffer_add( buf, "?", 1 );
1430
1431            if( err != NULL )
1432                *err = TRUE;
1433        }
1434
1435        evbuffer_add( buf, str, max_len );
1436        evbuffer_add( buf, &zero, 1 );
1437        ret = tr_memdup( EVBUFFER_DATA( buf ), EVBUFFER_LENGTH( buf ) );
1438        evbuffer_free( buf );
1439    }
1440
1441    assert( tr_utf8_validate( ret, -1, NULL ) );
1442    return ret;
1443}
1444
1445/***
1446****
1447***/
1448
1449struct number_range
1450{
1451    int low;
1452    int high;
1453};
1454
1455/**
1456 * This should be a single number (ex. "6") or a range (ex. "6-9").
1457 * Anything else is an error and will return failure.
1458 */
1459static tr_bool
1460parseNumberSection( const char * str, int len, struct number_range * setme )
1461{
1462    long a, b;
1463    tr_bool success;
1464    char * end;
1465    const int error = errno;
1466    char * tmp = tr_strndup( str, len );
1467
1468    errno = 0;
1469    a = b = strtol( tmp, &end, 10 );
1470    if( errno || ( end == tmp ) ) {
1471        success = FALSE;
1472    } else if( *end != '-' ) {
1473        b = a;
1474        success = TRUE;
1475    } else {
1476        const char * pch = end + 1;
1477        b = strtol( pch, &end, 10 );
1478        if( errno || ( pch == end ) )
1479            success = FALSE;
1480        else if( *end ) /* trailing data */
1481            success = FALSE;
1482        else
1483            success = TRUE;
1484    }
1485    tr_free( tmp );
1486
1487    setme->low = MIN( a, b );
1488    setme->high = MAX( a, b );
1489
1490    errno = error;
1491    return success;
1492}
1493
1494static int
1495compareInt( const void * va, const void * vb )
1496{
1497    const int a = *(const int *)va;
1498    const int b = *(const int *)vb;
1499    return a - b;
1500}
1501
1502/**
1503 * Given a string like "1-4" or "1-4,6,9,14-51", this allocates and returns an
1504 * array of setmeCount ints of all the values in the array.
1505 * For example, "5-8" will return [ 5, 6, 7, 8 ] and setmeCount will be 4.
1506 * It's the caller's responsibility to call tr_free() on the returned array.
1507 * If a fragment of the string can't be parsed, NULL is returned.
1508 */
1509int*
1510tr_parseNumberRange( const char * str_in, int len, int * setmeCount )
1511{
1512    int n = 0;
1513    int * uniq = NULL;
1514    char * str = tr_strndup( str_in, len );
1515    const char * walk;
1516    tr_list * ranges = NULL;
1517    tr_bool success = TRUE;
1518
1519    walk = str;
1520    while( walk && *walk && success ) {
1521        struct number_range range;
1522        const char * pch = strchr( walk, ',' );
1523        if( pch ) {
1524            success = parseNumberSection( walk, pch-walk, &range );
1525            walk = pch + 1;
1526        } else {
1527            success = parseNumberSection( walk, strlen( walk ), &range );
1528            walk += strlen( walk );
1529        }
1530        if( success )
1531            tr_list_append( &ranges, tr_memdup( &range, sizeof( struct number_range ) ) );
1532    }
1533
1534    if( !success )
1535    {
1536        *setmeCount = 0;
1537        uniq = NULL;
1538    }
1539    else
1540    {
1541        int i;
1542        int n2;
1543        tr_list * l;
1544        int * sorted = NULL;
1545
1546        /* build a sorted number array */
1547        n = n2 = 0;
1548        for( l=ranges; l!=NULL; l=l->next ) {
1549            const struct number_range * r = l->data;
1550            n += r->high + 1 - r->low;
1551        }
1552        sorted = tr_new( int, n );
1553        for( l=ranges; l!=NULL; l=l->next ) {
1554            const struct number_range * r = l->data;
1555            int i;
1556            for( i=r->low; i<=r->high; ++i )
1557                sorted[n2++] = i;
1558        }
1559        qsort( sorted, n, sizeof( int ), compareInt );
1560        assert( n == n2 );
1561
1562        /* remove duplicates */
1563        uniq = tr_new( int, n );
1564        for( i=n=0; i<n2; ++i )
1565            if( !n || uniq[n-1] != sorted[i] )
1566                uniq[n++] = sorted[i];
1567
1568        tr_free( sorted );
1569    }
1570
1571    /* cleanup */
1572    tr_list_free( &ranges, tr_free );
1573    tr_free( str );
1574
1575    /* return the result */
1576    *setmeCount = n;
1577    return uniq;
1578}
1579
1580/***
1581****
1582***/
1583
1584static void
1585printf_double_without_rounding( char * buf, int buflen, double d, int places )
1586{
1587    char * pch;
1588    char tmp[128];
1589    int len;
1590    tr_snprintf( tmp, sizeof( tmp ), "%'.64f", d );
1591    pch = tmp;
1592    while( isdigit( *pch ) ) ++pch; /* walk to the decimal point */
1593    ++pch; /* walk over the decimal point */
1594    pch += places;
1595    len = MIN( buflen - 1, pch - tmp );
1596    memcpy( buf, tmp, len );
1597    buf[len] = '\0';
1598}
1599
1600char*
1601tr_strratio( char * buf, size_t buflen, double ratio, const char * infinity )
1602{
1603    if( (int)ratio == TR_RATIO_NA )
1604        tr_strlcpy( buf, _( "None" ), buflen );
1605    else if( (int)ratio == TR_RATIO_INF )
1606        tr_strlcpy( buf, infinity, buflen );
1607    else if( ratio < 10.0 )
1608        printf_double_without_rounding( buf, buflen, ratio, 2 );
1609    else if( ratio < 100.0 )
1610        printf_double_without_rounding( buf, buflen, ratio, 1 );
1611    else
1612        tr_snprintf( buf, buflen, "%'.0f", ratio );
1613    return buf;
1614}
1615
1616/***
1617****
1618***/
1619
1620int
1621tr_moveFile( const char * oldpath, const char * newpath )
1622{
1623    int in;
1624    int out;
1625    char * buf;
1626    struct stat st;
1627    size_t bytesLeft;
1628    size_t buflen;
1629
1630    /* make sure the old file exists */
1631    if( stat( oldpath, &st ) ) {
1632        const int err = errno;
1633        errno = err;
1634        return -1;
1635    }
1636    if( !S_ISREG( st.st_mode ) ) {
1637        errno = ENOENT;
1638        return -1;
1639    }
1640    bytesLeft = st.st_size;
1641
1642    /* make sure the target directory exists */
1643    {
1644        char * newdir = tr_dirname( newpath );
1645        int i = tr_mkdirp( newdir, 0777 );
1646        tr_free( newdir );
1647        if( i )
1648            return i;
1649    }
1650
1651    /* they  might be on the same filesystem... */
1652    if( !rename( oldpath, newpath ) )
1653        return 0;
1654
1655    /* copy the file */
1656    in = tr_open_file_for_scanning( oldpath );
1657    tr_preallocate_file( newpath, bytesLeft );
1658    out = tr_open_file_for_writing( newpath );
1659    buflen = stat( newpath, &st ) ? 4096 : st.st_blksize;
1660    buf = tr_new( char, buflen );
1661    while( bytesLeft > 0 )
1662    {
1663        ssize_t bytesWritten;
1664        const size_t bytesThisPass = MIN( bytesLeft, buflen );
1665        const int numRead = read( in, buf, bytesThisPass );
1666        if( numRead < 0 )
1667            break;
1668        bytesWritten = write( out, buf, numRead );
1669        if( bytesWritten < 0 )
1670            break;
1671        bytesLeft -= bytesWritten;
1672    }
1673
1674    /* cleanup */
1675    tr_free( buf );
1676    tr_close_file( out );
1677    tr_close_file( in );
1678    if( bytesLeft != 0 )
1679        return -1;
1680
1681    unlink( oldpath );
1682    return 0;
1683}
Note: See TracBrowser for help on using the repository browser.