source: branches/file_selection/libtransmission/utils.c @ 2131

Last change on this file since 2131 was 2131, checked in by charles, 15 years ago
  • if user aborts, don't physically create the torrent file. (thx BMW)
  • remove the gtk threading code that got checked in by accident in yesterday's flurry
  • slightly better error checking in makemeta
  • Property svn:keywords set to Date Rev Author Id
File size: 13.0 KB
Line 
1/******************************************************************************
2 * $Id: utils.c 2131 2007-06-17 14:37:33Z 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 <ctype.h>
26#include "transmission.h"
27
28#define SPRINTF_BUFSIZE         100
29
30static tr_lock_t      * messageLock = NULL;
31static int              messageLevel = 0;
32static int              messageQueuing = 0;
33static tr_msg_list_t *  messageQueue = NULL;
34static tr_msg_list_t ** messageQueueTail = &messageQueue;
35
36void tr_msgInit( void )
37{
38    if( NULL == messageLock )
39    {
40        messageLock = calloc( 1, sizeof( *messageLock ) );
41        tr_lockInit( messageLock );
42    }
43}
44
45void tr_setMessageLevel( int level )
46{
47    tr_msgInit();
48    tr_lockLock( messageLock );
49    messageLevel = MAX( 0, level );
50    tr_lockUnlock( messageLock );
51}
52
53int tr_getMessageLevel( void )
54{
55    int ret;
56
57    tr_msgInit();
58    tr_lockLock( messageLock );
59    ret = messageLevel;
60    tr_lockUnlock( messageLock );
61
62    return ret;
63}
64
65void tr_setMessageQueuing( int enabled )
66{
67    tr_msgInit();
68    tr_lockLock( messageLock );
69    messageQueuing = enabled;
70    tr_lockUnlock( messageLock );
71}
72
73tr_msg_list_t * tr_getQueuedMessages( void )
74{
75    tr_msg_list_t * ret;
76
77    assert( NULL != messageLock );
78    tr_lockLock( messageLock );
79    ret = messageQueue;
80    messageQueue = NULL;
81    messageQueueTail = &messageQueue;
82    tr_lockUnlock( messageLock );
83
84    return ret;
85}
86
87void tr_freeMessageList( tr_msg_list_t * list )
88{
89    tr_msg_list_t * next;
90
91    while( NULL != list )
92    {
93        next = list->next;
94        free( list->message );
95        free( list );
96        list = next;
97    }
98}
99
100void tr_msg( int level, char * msg, ... )
101{
102    va_list         args1, args2;
103    tr_msg_list_t * newmsg;
104    int             len1, len2;
105
106    assert( NULL != messageLock );
107    tr_lockLock( messageLock );
108
109    if( !messageLevel )
110    {
111        char * env;
112        env          = getenv( "TR_DEBUG" );
113        messageLevel = ( env ? atoi( env ) : 0 ) + 1;
114        messageLevel = MAX( 1, messageLevel );
115    }
116
117    if( messageLevel >= level )
118    {
119        va_start( args1, msg );
120        if( messageQueuing )
121        {
122            newmsg = calloc( 1, sizeof( *newmsg ) );
123            if( NULL != newmsg )
124            {
125                newmsg->level = level;
126                newmsg->when = time( NULL );
127                len1 = len2 = 0;
128                va_start( args2, msg );
129                tr_vsprintf( &newmsg->message, &len1, &len2, msg,
130                             args1, args2 );
131                va_end( args2 );
132                if( NULL == newmsg->message )
133                {
134                    free( newmsg );
135                }
136                else
137                {
138                    *messageQueueTail = newmsg;
139                    messageQueueTail = &newmsg->next;
140                }
141            }
142        }
143        else
144        {
145            vfprintf( stderr, msg, args1 );
146            fputc( '\n', stderr );
147        }
148        va_end( args1 );
149    }
150
151    tr_lockUnlock( messageLock );
152}
153
154int tr_rand( int sup )
155{
156    static int init = 0;
157    if( !init )
158    {
159        srand( tr_date() );
160        init = 1;
161    }
162    return rand() % sup;
163}
164
165
166void*
167tr_memmem( const void* haystack, size_t hl,
168           const void* needle,   size_t nl)
169{
170    const char *walk, *end;
171
172    if( !nl )
173        return (void*) haystack;
174
175    if( hl < nl )
176        return NULL;
177
178    for (walk=(const char*)haystack, end=walk+hl-nl; walk!=end; ++walk)
179        if( !memcmp( walk, needle, nl ) )
180            return (void*) walk;
181
182    return NULL;
183}
184
185int tr_mkdir( char * path )
186{
187    char      * p, * pp;
188    struct stat sb;
189    int done;
190
191    p = path;
192    while( '/' == *p )
193      p++;
194    pp = p;
195    done = 0;
196    while( ( p = strchr( pp, '/' ) ) || ( p = strchr( pp, '\0' ) ) )
197    {
198        if( '\0' == *p)
199        {
200            done = 1;
201        }
202        else
203        {
204            *p = '\0';
205        }
206        if( stat( path, &sb ) )
207        {
208            /* Folder doesn't exist yet */
209            if( mkdir( path, 0777 ) )
210            {
211                tr_err( "Could not create directory %s (%s)", path,
212                        strerror( errno ) );
213                *p = '/';
214                return 1;
215            }
216        }
217        else if( ( sb.st_mode & S_IFMT ) != S_IFDIR )
218        {
219            /* Node exists but isn't a folder */
220            tr_err( "Remove %s, it's in the way.", path );
221            *p = '/';
222            return 1;
223        }
224        if( done )
225        {
226            break;
227        }
228        *p = '/';
229        p++;
230        pp = p;
231    }
232
233    return 0;
234}
235
236int
237tr_strncasecmp( const char * s1, const char * s2, size_t n )
238{
239    if ( !n )
240        return 0;
241
242    while( n-- != 0 && tolower( *s1 ) == tolower( *s2 ) ) {
243        if( !n || !*s1 || !*s2 )
244            break;
245        ++s1;
246        ++s2;
247    }
248
249    return tolower(*(unsigned char *) s1) - tolower(*(unsigned char *) s2);
250}
251
252int tr_sprintf( char ** buf, int * used, int * max, const char * format, ... )
253{
254    va_list ap1, ap2;
255    int     ret;
256
257    va_start( ap1, format );
258    va_start( ap2, format );
259    ret = tr_vsprintf( buf, used, max, format, ap1, ap2 );
260    va_end( ap2 );
261    va_end( ap1 );
262
263    return ret;
264}
265
266int tr_vsprintf( char ** buf, int * used, int * max, const char * fmt,
267                 va_list ap1, va_list ap2 )
268{
269    int     want;
270
271    want = vsnprintf( NULL, 0, fmt, ap1 );
272
273    if( tr_concat( buf, used, max, NULL, want ) )
274    {
275        return 1;
276    }
277    assert( *used + want + 1 <= *max );
278
279    *used += vsnprintf( *buf + *used, *max - *used, fmt, ap2 );
280
281    return 0;
282}
283
284int tr_concat( char ** buf, int * used, int * max, const char * data, int len )
285{
286    int     newmax;
287    char  * newbuf;
288
289    newmax = *max;
290    while( *used + len + 1 > newmax )
291    {
292        newmax += SPRINTF_BUFSIZE;
293    }
294    if( newmax > *max )
295    {
296        newbuf = realloc( *buf, newmax );
297        if( NULL == newbuf )
298        {
299            return 1;
300        }
301        *buf = newbuf;
302        *max = newmax;
303    }
304
305    if( NULL != data )
306    {
307        memcpy( *buf + *used, data, len );
308        *used += len;
309    }
310
311    return 0;
312}
313
314char *
315tr_dupstr( const char * base, int len )
316{
317    char * ret;
318
319    ret = malloc( len + 1 );
320    if( NULL != ret )
321    {
322        memcpy( ret, base, len );
323        ret[len] = '\0';
324    }
325
326    return ret;
327}
328
329int
330tr_ioErrorFromErrno( void )
331{
332    switch( errno )
333    {
334        case EACCES:
335        case EROFS:
336            return TR_ERROR_IO_PERMISSIONS;
337        case ENOSPC:
338            return TR_ERROR_IO_SPACE;
339        case EMFILE:
340        case EFBIG:
341            return TR_ERROR_IO_RESOURCES;
342        default:
343            tr_dbg( "generic i/o errno from errno: %s", strerror( errno ) );
344            return TR_ERROR_IO_OTHER;
345    }
346}
347
348char *
349tr_errorString( int code )
350{
351    switch( code )
352    {
353        case TR_OK:
354            return "No error";
355        case TR_ERROR:
356            return "Generic error";
357        case TR_ERROR_ASSERT:
358            return "Assert error";
359        case TR_ERROR_IO_PARENT:
360            return "Download folder does not exist";
361        case TR_ERROR_IO_PERMISSIONS:
362            return "Insufficient permissions";
363        case TR_ERROR_IO_SPACE:
364            return "Insufficient free space";
365        case TR_ERROR_IO_DUP_DOWNLOAD:
366            return "Already active transfer with same name and download folder";
367        case TR_ERROR_IO_RESOURCES:
368            return "Insufficient resources";
369        case TR_ERROR_IO_OTHER:
370            return "Generic I/O error";
371    }
372    return "Unknown error";
373}
374
375/****
376*****
377****/
378
379char* tr_strdup( const char * in )
380{
381    char * out = NULL;
382    if( in != NULL )
383    {
384        const size_t len = strlen( in );
385        out = malloc( len + 1 );
386        memcpy( out, in, len );
387        out[len] = '\0';
388    }
389    return out;
390}
391
392void*
393tr_malloc( size_t size )
394{
395    return size ? malloc( size ) : NULL;
396}
397
398void tr_free( void * p )
399{
400    if( p )
401        free( p );
402}
403
404/****
405*****
406****/
407
408/* note that the argument is how many bits are needed, not bytes */
409tr_bitfield_t*
410tr_bitfieldNew( size_t bitcount )
411{
412    tr_bitfield_t * ret = calloc( 1, sizeof(tr_bitfield_t) );
413    if( NULL == ret )
414        return NULL;
415
416    ret->len = ( bitcount + 7u ) / 8u;
417    ret->bits = calloc( ret->len, 1 );
418    if( NULL == ret->bits ) {
419        free( ret );
420        return NULL;
421    }
422
423    return ret;
424}
425
426tr_bitfield_t*
427tr_bitfieldDup( const tr_bitfield_t * in )
428{
429    tr_bitfield_t * ret = calloc( 1, sizeof(tr_bitfield_t) );
430    ret->len = in->len;
431    ret->bits = malloc( ret->len );
432    memcpy( ret->bits, in->bits, ret->len );
433    return ret;
434}
435
436void tr_bitfieldFree( tr_bitfield_t * bitfield )
437{
438    if( bitfield )
439    {
440        free( bitfield->bits );
441        free( bitfield );
442    }
443}
444
445void
446tr_bitfieldClear( tr_bitfield_t * bitfield )
447{
448    memset( bitfield->bits, 0, bitfield->len );
449}
450
451int
452tr_bitfieldIsEmpty( const tr_bitfield_t * bitfield )
453{
454    unsigned int i;
455
456    for( i=0; i<bitfield->len; ++i )
457        if( *bitfield->bits )
458            return 0;
459
460    return 1;
461}
462
463int
464tr_bitfieldHas( const tr_bitfield_t   * bitfield,
465                size_t                  bit )
466{
467    if ( bitfield == NULL ) return 0;
468    assert( bit / 8u < bitfield->len );
469    return ( bitfield->bits[ bit / 8u ] & ( 1 << ( 7 - ( bit % 8 ) ) ) );
470}
471
472void
473tr_bitfieldAdd( tr_bitfield_t  * bitfield, size_t bit )
474{
475    assert( bit / 8u < bitfield->len );
476    bitfield->bits[ bit / 8u ] |= ( 1u << ( 7u - ( bit % 8u ) ) );
477}
478
479void
480tr_bitfieldAddRange( tr_bitfield_t  * bitfield,
481                     size_t           first,
482                     size_t           last )
483{
484    /* TODO: there are faster ways to do this */
485    unsigned int i;
486    for( i=first; i<=last; ++i )
487        tr_bitfieldAdd( bitfield, i );
488}
489
490void
491tr_bitfieldRem( tr_bitfield_t   * bitfield,
492                size_t            bit )
493{
494    assert( bit / 8u < bitfield->len );
495    bitfield->bits[ bit / 8u ] &= ~( 1u << ( 7u - ( bit % 8u ) ) );
496}
497
498void
499tr_bitfieldRemRange ( tr_bitfield_t  * b,
500                      size_t           first,
501                      size_t           last )
502{
503    /* TODO: there are faster ways to do this */
504    unsigned int i;
505    for( i=first; i<=last; ++i )
506        tr_bitfieldRem( b, i );
507}
508
509tr_bitfield_t*
510tr_bitfieldNegate( tr_bitfield_t * b )
511{
512    uint8_t *it;
513    const uint8_t *end;
514
515    for( it=b->bits, end=it+b->len; it!=end; ++it )
516        *it = ~*it;
517
518    return b;
519}
520
521tr_bitfield_t*
522tr_bitfieldAnd( tr_bitfield_t * a, const tr_bitfield_t * b )
523{
524    uint8_t *ait;
525    const uint8_t *aend, *bit;
526
527    assert( a->len == b->len );
528
529    for( ait=a->bits, bit=b->bits, aend=ait+a->len; ait!=aend; ++ait, ++bit )
530        *ait &= *bit;
531
532    return a;
533}
534
535size_t
536tr_bitfieldCountTrueBits( const tr_bitfield_t* b )
537{
538    size_t ret = 0;
539    const uint8_t *it, *end;
540    static const int trueBitCount[512] = {
541        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,
542        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,
543        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,
544        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,
545        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,
546        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,
547        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,
548        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,
549        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,
550        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,
551        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,
552        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,
553        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,
554        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,
555        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,
556        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
557    };
558
559    for( it=b->bits, end=it+b->len; it!=end; ++it )
560        ret += trueBitCount[*it];
561
562    return ret;
563}
Note: See TracBrowser for help on using the repository browser.