source: branches/0.8x/libtransmission/utils.c @ 2999

Last change on this file since 2999 was 2999, checked in by charles, 15 years ago

(0.8x) fix loooong-standing off-by-one memory allocation bug in the bitfield code

  • Property svn:keywords set to Date Rev Author Id
File size: 15.9 KB
Line 
1/******************************************************************************
2 * $Id: utils.c 2999 2007-09-09 16:56:48Z charles $
3 *
4 * Copyright (c) 2005-2007 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>
27#include <errno.h>
28#include <stdarg.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32
33#include <sys/time.h>
34#include <sys/types.h>
35#include <sys/stat.h>
36#include <unistd.h> /* usleep, stat */
37
38#ifdef WIN32
39    #include <windows.h> /* for Sleep */
40#elif defined(__BEOS__)
41    #include <kernel/OS.h>
42    extern int vasprintf( char **, const char *, va_list );
43#endif
44
45#include "transmission.h"
46#include "trcompat.h"
47#include "utils.h"
48#include "platform.h"
49
50#define SPRINTF_BUFSIZE         100
51
52static tr_lock_t      * messageLock = NULL;
53static int              messageLevel = 0;
54static int              messageQueuing = FALSE;
55static tr_msg_list_t *  messageQueue = NULL;
56static tr_msg_list_t ** messageQueueTail = &messageQueue;
57
58void tr_msgInit( void )
59{
60    if( !messageLock )
61         messageLock = tr_lockNew( );
62}
63
64void tr_setMessageLevel( int level )
65{
66    tr_msgInit();
67    tr_lockLock( messageLock );
68    messageLevel = MAX( 0, level );
69    tr_lockUnlock( messageLock );
70}
71
72int tr_getMessageLevel( void )
73{
74    int ret;
75
76    tr_msgInit();
77    tr_lockLock( messageLock );
78    ret = messageLevel;
79    tr_lockUnlock( messageLock );
80
81    return ret;
82}
83
84void tr_setMessageQueuing( int enabled )
85{
86    tr_msgInit();
87    tr_lockLock( messageLock );
88    messageQueuing = enabled;
89    tr_lockUnlock( messageLock );
90}
91
92tr_msg_list_t * tr_getQueuedMessages( void )
93{
94    tr_msg_list_t * ret;
95
96    assert( NULL != messageLock );
97    tr_lockLock( messageLock );
98    ret = messageQueue;
99    messageQueue = NULL;
100    messageQueueTail = &messageQueue;
101    tr_lockUnlock( messageLock );
102
103    return ret;
104}
105
106void tr_freeMessageList( tr_msg_list_t * list )
107{
108    tr_msg_list_t * next;
109
110    while( NULL != list )
111    {
112        next = list->next;
113        free( list->message );
114        free( list );
115        list = next;
116    }
117}
118
119void tr_msg( int level, char * msg, ... )
120{
121    va_list         args1, args2;
122    tr_msg_list_t * newmsg;
123    int             len1, len2;
124
125    assert( NULL != messageLock );
126    tr_lockLock( messageLock );
127
128    if( !messageLevel )
129    {
130        char * env;
131        env          = getenv( "TR_DEBUG" );
132        messageLevel = ( env ? atoi( env ) : 0 ) + 1;
133        messageLevel = MAX( 1, messageLevel );
134    }
135
136    if( messageLevel >= level )
137    {
138        va_start( args1, msg );
139        if( messageQueuing )
140        {
141            newmsg = calloc( 1, sizeof( *newmsg ) );
142            if( NULL != newmsg )
143            {
144                newmsg->level = level;
145                newmsg->when = time( NULL );
146                len1 = len2 = 0;
147                va_start( args2, msg );
148                tr_vsprintf( &newmsg->message, &len1, &len2, msg,
149                             args1, args2 );
150                va_end( args2 );
151                if( NULL == newmsg->message )
152                {
153                    free( newmsg );
154                }
155                else
156                {
157                    *messageQueueTail = newmsg;
158                    messageQueueTail = &newmsg->next;
159                }
160            }
161        }
162        else
163        {
164            vfprintf( stderr, msg, args1 );
165            fputc( '\n', stderr );
166            fflush( stderr );
167        }
168        va_end( args1 );
169    }
170
171    tr_lockUnlock( messageLock );
172}
173
174int tr_rand( int sup )
175{
176    static int init = 0;
177
178    assert( sup > 0 );
179
180    if( !init )
181    {
182        srand( tr_date() );
183        init = 1;
184    }
185    return rand() % sup;
186}
187
188
189#if 0
190void*
191tr_memmem( const void* haystack, size_t hl,
192           const void* needle,   size_t nl)
193{
194    const char *walk, *end;
195
196    if( !nl )
197        return (void*) haystack;
198
199    if( hl < nl )
200        return NULL;
201
202    for (walk=(const char*)haystack, end=walk+hl-nl; walk!=end; ++walk)
203        if( !memcmp( walk, needle, nl ) )
204            return (void*) walk;
205
206    return NULL;
207}
208#else
209void * tr_memmem ( const void *vbig, size_t big_len,
210                   const void *vlittle, size_t little_len )
211{
212    const char *big = vbig;
213    const char *little = vlittle;
214    size_t ii, jj;
215
216    if( 0 == big_len || 0 == little_len )
217    {
218        return NULL;
219    }
220
221    for( ii = 0; ii + little_len <= big_len; ii++ )
222    {
223        for( jj = 0; jj < little_len; jj++ )
224        {
225            if( big[ii + jj] != little[jj] )
226            {
227                break;
228            }
229        }
230        if( jj == little_len )
231        {
232            return (char*)big + ii;
233        }
234    }
235
236    return NULL;
237}
238#endif
239
240
241int
242tr_mkdir( const char * path, int permissions
243#ifdef WIN32
244                                             UNUSED
245#endif
246                                                    )
247{
248#ifdef WIN32
249    return mkdir( path );
250#else
251    return mkdir( path, permissions );
252#endif
253}
254
255int
256tr_mkdirp( char * path, int permissions )
257{
258    char      * p, * pp;
259    struct stat sb;
260    int done;
261
262    p = path;
263    while( '/' == *p )
264      p++;
265    pp = p;
266    done = 0;
267    while( ( p = strchr( pp, '/' ) ) || ( p = strchr( pp, '\0' ) ) )
268    {
269        if( '\0' == *p)
270        {
271            done = 1;
272        }
273        else
274        {
275            *p = '\0';
276        }
277        if( stat( path, &sb ) )
278        {
279            /* Folder doesn't exist yet */
280            if( tr_mkdir( path, permissions ) )
281            {
282                tr_err( "Could not create directory %s (%s)", path,
283                        strerror( errno ) );
284                *p = '/';
285                return 1;
286            }
287        }
288        else if( ( sb.st_mode & S_IFMT ) != S_IFDIR )
289        {
290            /* Node exists but isn't a folder */
291            tr_err( "Remove %s, it's in the way.", path );
292            *p = '/';
293            return 1;
294        }
295        if( done )
296        {
297            break;
298        }
299        *p = '/';
300        p++;
301        pp = p;
302    }
303
304    return 0;
305}
306
307int
308tr_strncasecmp( const char * s1, const char * s2, size_t n )
309{
310    if ( !n )
311        return 0;
312
313    while( n-- != 0 && tolower( *s1 ) == tolower( *s2 ) ) {
314        if( !n || !*s1 || !*s2 )
315            break;
316        ++s1;
317        ++s2;
318    }
319
320    return tolower(*(unsigned char *) s1) - tolower(*(unsigned char *) s2);
321}
322
323int tr_sprintf( char ** buf, int * used, int * max, const char * format, ... )
324{
325    va_list ap1, ap2;
326    int     ret;
327
328    va_start( ap1, format );
329    va_start( ap2, format );
330    ret = tr_vsprintf( buf, used, max, format, ap1, ap2 );
331    va_end( ap2 );
332    va_end( ap1 );
333
334    return ret;
335}
336
337int tr_vsprintf( char ** buf, int * used, int * max, const char * fmt,
338                 va_list ap1, va_list ap2 )
339{
340    int     want;
341
342    want = vsnprintf( NULL, 0, fmt, ap1 );
343
344    if( tr_concat( buf, used, max, NULL, want ) )
345    {
346        return 1;
347    }
348    assert( *used + want + 1 <= *max );
349
350    *used += vsnprintf( *buf + *used, *max - *used, fmt, ap2 );
351
352    return 0;
353}
354
355#ifndef HAVE_ASPRINTF
356
357int
358asprintf( char ** buf, const char * format, ... )
359{
360    va_list ap;
361    int     ret;
362
363    va_start( ap, format );
364    ret = vasprintf( buf, format, ap );
365    va_end( ap );
366
367    return ret;
368}
369
370int
371vasprintf( char ** buf, const char * format, va_list ap )
372{
373    va_list ap2;
374    int     used, max;
375
376    va_copy( ap2, ap );
377
378    *buf = NULL;
379    used = 0;
380    max  = 0;
381
382    if( tr_vsprintf( buf, &used, &max, format, ap, ap2 ) )
383    {
384        free( *buf );
385        return -1;
386    }
387
388    return used;
389}
390
391#endif /* HAVE_ASPRINTF */
392
393int tr_concat( char ** buf, int * used, int * max, const char * data, int len )
394{
395    int     newmax;
396    char  * newbuf;
397
398    newmax = *max;
399    while( *used + len + 1 > newmax )
400    {
401        newmax += SPRINTF_BUFSIZE;
402    }
403    if( newmax > *max )
404    {
405        newbuf = realloc( *buf, newmax );
406        if( NULL == newbuf )
407        {
408            return 1;
409        }
410        *buf = newbuf;
411        *max = newmax;
412    }
413
414    if( NULL != data )
415    {
416        memcpy( *buf + *used, data, len );
417        *used += len;
418    }
419
420    return 0;
421}
422
423void
424tr_buildPath ( char *buf, size_t buflen, const char *first_element, ... )
425{
426    va_list vl;
427    char* walk = buf;
428    const char * element = first_element;
429
430    if( first_element == NULL )
431        return;
432
433    va_start( vl, first_element );
434    for( ;; ) {
435        const size_t n = strlen( element );
436        memcpy( walk, element, n );
437        walk += n;
438        element = (const char*) va_arg( vl, const char* );
439        if( element == NULL )
440            break;
441        *walk++ = TR_PATH_DELIMITER;
442    }
443    *walk = '\0';
444    assert( walk-buf <= (int)buflen );
445}
446
447int
448tr_ioErrorFromErrno( void )
449{
450    switch( errno )
451    {
452        case EACCES:
453        case EROFS:
454            return TR_ERROR_IO_PERMISSIONS;
455        case ENOSPC:
456            return TR_ERROR_IO_SPACE;
457        case EMFILE:
458            return TR_ERROR_IO_OPEN_FILES;
459        case EFBIG:
460            return TR_ERROR_IO_FILE_TOO_BIG;
461        default:
462            tr_dbg( "generic i/o errno from errno: %s", strerror( errno ) );
463            return TR_ERROR_IO_OTHER;
464    }
465}
466
467char *
468tr_errorString( int code )
469{
470    switch( code )
471    {
472        case TR_OK:
473            return "No error";
474        case TR_ERROR:
475            return "Generic error";
476        case TR_ERROR_ASSERT:
477            return "Assert error";
478        case TR_ERROR_IO_PARENT:
479            return "Download folder does not exist";
480        case TR_ERROR_IO_PERMISSIONS:
481            return "Insufficient permissions";
482        case TR_ERROR_IO_SPACE:
483            return "Insufficient free space";
484        case TR_ERROR_IO_DUP_DOWNLOAD:
485            return "Already active transfer with same name and download folder";
486        case TR_ERROR_IO_FILE_TOO_BIG:
487            return "File too large";
488        case TR_ERROR_IO_OPEN_FILES:
489            return "Too many open files";
490        case TR_ERROR_IO_OTHER:
491            return "Generic I/O error";
492    }
493    return "Unknown error";
494}
495
496/****
497*****
498****/
499
500char*
501tr_strdup( const char * in )
502{
503    return tr_strndup( in, in ? strlen(in) : 0 );
504}
505
506char*
507tr_strndup( const char * in, int len )
508{
509    char * out = NULL;
510
511    if( in != NULL )
512    {
513        out = tr_malloc( len+1 );
514        memcpy( out, in, len );
515        out[len] = '\0';
516    }
517    return out;
518}
519
520void*
521tr_calloc( size_t nmemb, size_t size )
522{
523    return nmemb && size ? calloc( nmemb, size ) : NULL;
524}
525
526void*
527tr_malloc( size_t size )
528{
529    return size ? malloc( size ) : NULL;
530}
531
532void*
533tr_malloc0( size_t size )
534{
535    void * ret = tr_malloc( size );
536    memset( ret, 0, size );
537    return ret;
538}
539
540void tr_free( void * p )
541{
542    if( p )
543        free( p );
544}
545
546/****
547*****
548****/
549
550/* note that the argument is how many bits are needed, not bytes */
551tr_bitfield_t*
552tr_bitfieldNew( size_t bitcount )
553{
554    tr_bitfield_t * ret = calloc( 1, sizeof(tr_bitfield_t) );
555    if( NULL == ret )
556        return NULL;
557
558    ret->len = bitcount/8u + 1;
559    ret->bits = calloc( ret->len, 1 );
560    if( NULL == ret->bits ) {
561        free( ret );
562        return NULL;
563    }
564
565    return ret;
566}
567
568tr_bitfield_t*
569tr_bitfieldDup( const tr_bitfield_t * in )
570{
571    tr_bitfield_t * ret = calloc( 1, sizeof(tr_bitfield_t) );
572    ret->len = in->len;
573    ret->bits = malloc( ret->len );
574    memcpy( ret->bits, in->bits, ret->len );
575    return ret;
576}
577
578void tr_bitfieldFree( tr_bitfield_t * bitfield )
579{
580    if( bitfield )
581    {
582        free( bitfield->bits );
583        free( bitfield );
584    }
585}
586
587void
588tr_bitfieldClear( tr_bitfield_t * bitfield )
589{
590    memset( bitfield->bits, 0, bitfield->len );
591}
592
593int
594tr_bitfieldIsEmpty( const tr_bitfield_t * bitfield )
595{
596    unsigned int i;
597
598    for( i=0; i<bitfield->len; ++i )
599        if( bitfield->bits[i] )
600            return 0;
601
602    return 1;
603}
604
605#define BIN(nth) ((nth>>3))
606#define BIT(nth) (1<<(7-(nth%8)))
607
608void
609tr_bitfieldAdd( tr_bitfield_t  * bitfield, size_t nth )
610{
611    assert( bitfield != NULL );
612    assert( BIN(nth) < bitfield->len );
613    bitfield->bits[ BIN(nth) ] |= BIT(nth);
614}
615
616void
617tr_bitfieldAddRange( tr_bitfield_t  * bitfield,
618                     size_t           begin,
619                     size_t           end )
620{
621    /* TODO: there are faster ways to do this */
622    unsigned int i;
623    for( i=begin; i<end; ++i )
624        tr_bitfieldAdd( bitfield, i );
625}
626
627void
628tr_bitfieldRem( tr_bitfield_t   * bitfield,
629                size_t            nth )
630{
631    if( bitfield != NULL )
632    {
633        const size_t bin = BIN(nth);
634        assert( bin < bitfield->len );
635        bitfield->bits[bin] &= ~BIT(nth);
636    }
637}
638
639void
640tr_bitfieldRemRange ( tr_bitfield_t  * b,
641                      size_t           begin,
642                      size_t           end )
643{
644    /* TODO: there are faster ways to do this */
645    unsigned int i;
646    for( i=begin; i<end; ++i )
647        tr_bitfieldRem( b, i );
648}
649
650tr_bitfield_t*
651tr_bitfieldNegate( tr_bitfield_t * b )
652{
653    uint8_t *it;
654    const uint8_t *end;
655
656    for( it=b->bits, end=it+b->len; it!=end; ++it )
657        *it = ~*it;
658
659    return b;
660}
661
662tr_bitfield_t*
663tr_bitfieldAnd( tr_bitfield_t * a, const tr_bitfield_t * b )
664{
665    uint8_t *ait;
666    const uint8_t *aend, *bit;
667
668    assert( a->len == b->len );
669
670    for( ait=a->bits, bit=b->bits, aend=ait+a->len; ait!=aend; ++ait, ++bit )
671        *ait &= *bit;
672
673    return a;
674}
675
676size_t
677tr_bitfieldCountTrueBits( const tr_bitfield_t* b )
678{
679    size_t ret = 0;
680    const uint8_t *it, *end;
681    static const int trueBitCount[512] = {
682        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,
683        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,
684        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,
685        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,
686        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,
687        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,
688        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,
689        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,
690        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,
691        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,
692        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,
693        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,
694        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,
695        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,
696        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,
697        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
698    };
699
700    if( !b )
701        return 0;
702
703    for( it=b->bits, end=it+b->len; it!=end; ++it )
704        ret += trueBitCount[*it];
705
706    return ret;
707}
708
709/***
710****
711***/
712
713uint64_t
714tr_date( void )
715{
716    struct timeval tv;
717    gettimeofday( &tv, NULL );
718    return (uint64_t) tv.tv_sec * 1000 + ( tv.tv_usec / 1000 );
719}
720
721void
722tr_wait( uint64_t delay_milliseconds )
723{
724#ifdef __BEOS__
725    snooze( 1000 * delay_milliseconds );
726#elif defined(WIN32)
727    Sleep( (DWORD)delay_milliseconds );
728#else
729    usleep( 1000 * delay_milliseconds );
730#endif
731}
Note: See TracBrowser for help on using the repository browser.