mirror of
https://github.com/transmission/transmission
synced 2024-12-25 17:17:31 +00:00
(trunk libT) #4016 "blocklists don't handle overlapping/unsorted rules" -- fixed.
This commit is contained in:
parent
5c14353398
commit
e187ae58a9
1 changed files with 60 additions and 12 deletions
|
@ -11,7 +11,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h> /* free() */
|
#include <stdlib.h> /* qsort(), free() */
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
|
@ -306,16 +306,27 @@ parseLine( const char * line, struct tr_ipv4_range * range )
|
||||||
|| parseLine2( line, range );
|
|| parseLine2( line, range );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
compareAddressRangesByFirstAddress( const void * va, const void * vb )
|
||||||
|
{
|
||||||
|
const struct tr_ipv4_range * a = va;
|
||||||
|
const struct tr_ipv4_range * b = vb;
|
||||||
|
if( a->begin != b->begin )
|
||||||
|
return a->begin < b->begin ? -1 : 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
_tr_blocklistSetContent( tr_blocklist * b,
|
_tr_blocklistSetContent( tr_blocklist * b, const char * filename )
|
||||||
const char * filename )
|
|
||||||
{
|
{
|
||||||
FILE * in;
|
FILE * in;
|
||||||
FILE * out;
|
FILE * out;
|
||||||
int inCount = 0;
|
int inCount = 0;
|
||||||
int outCount = 0;
|
|
||||||
char line[2048];
|
char line[2048];
|
||||||
const char * err_fmt = _( "Couldn't read \"%1$s\": %2$s" );
|
const char * err_fmt = _( "Couldn't read \"%1$s\": %2$s" );
|
||||||
|
struct tr_ipv4_range * ranges = NULL;
|
||||||
|
size_t ranges_alloc = 0;
|
||||||
|
size_t ranges_count = 0;
|
||||||
|
|
||||||
if( !filename )
|
if( !filename )
|
||||||
{
|
{
|
||||||
|
@ -340,6 +351,7 @@ _tr_blocklistSetContent( tr_blocklist * b,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* load the rules into memory */
|
||||||
while( fgets( line, sizeof( line ), in ) != NULL )
|
while( fgets( line, sizeof( line ), in ) != NULL )
|
||||||
{
|
{
|
||||||
char * walk;
|
char * walk;
|
||||||
|
@ -358,27 +370,63 @@ _tr_blocklistSetContent( tr_blocklist * b,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( fwrite( &range, sizeof( struct tr_ipv4_range ), 1, out ) != 1 )
|
if( ranges_alloc == ranges_count )
|
||||||
{
|
{
|
||||||
tr_err( _( "Couldn't save file \"%1$s\": %2$s" ), b->filename,
|
ranges_alloc += 4096; /* arbitrary */
|
||||||
tr_strerror( errno ) );
|
ranges = tr_renew( struct tr_ipv4_range, ranges, ranges_alloc );
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
++outCount;
|
ranges[ranges_count++] = range;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( ranges_count > 0 ) /* sort and merge */
|
||||||
{
|
{
|
||||||
|
struct tr_ipv4_range * r;
|
||||||
|
struct tr_ipv4_range * keep = ranges;
|
||||||
|
const struct tr_ipv4_range * end;
|
||||||
|
|
||||||
|
/* sort */
|
||||||
|
qsort( ranges, ranges_count, sizeof( struct tr_ipv4_range ),
|
||||||
|
compareAddressRangesByFirstAddress );
|
||||||
|
|
||||||
|
/* merge */
|
||||||
|
for( r=ranges+1, end=ranges+ranges_count; r!=end; ++r ) {
|
||||||
|
if( keep->end < r->begin )
|
||||||
|
*++keep = *r;
|
||||||
|
else if( keep->end < r->end )
|
||||||
|
keep->end = r->end;
|
||||||
|
}
|
||||||
|
|
||||||
|
ranges_count = keep + 1 - ranges;
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
/* sanity checks: make sure the rules are sorted
|
||||||
|
* in ascending order and don't overlap */
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for( i=0; i<ranges_count; ++i )
|
||||||
|
assert( ranges[i].begin <= ranges[i].end );
|
||||||
|
|
||||||
|
for( i=1; i<ranges_count; ++i )
|
||||||
|
assert( ranges[i-1].end < ranges[i].begin );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if( fwrite( ranges, sizeof( struct tr_ipv4_range ), ranges_count, out ) != ranges_count )
|
||||||
|
tr_err( _( "Couldn't save file \"%1$s\": %2$s" ), b->filename, tr_strerror( errno ) );
|
||||||
|
else {
|
||||||
char * base = tr_basename( b->filename );
|
char * base = tr_basename( b->filename );
|
||||||
tr_inf( _( "Blocklist \"%s\" updated with %d entries" ), base, outCount );
|
tr_inf( _( "Blocklist \"%s\" updated with %zu entries" ), base, ranges_count );
|
||||||
tr_free( base );
|
tr_free( base );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tr_free( ranges );
|
||||||
fclose( out );
|
fclose( out );
|
||||||
fclose( in );
|
fclose( in );
|
||||||
|
|
||||||
blocklistLoad( b );
|
blocklistLoad( b );
|
||||||
|
|
||||||
return outCount;
|
return ranges_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue