2002-04-12 07:26:19 +04:00
/*
Unix SMB / CIFS implementation .
SMB torture tester - mangling test
Copyright ( C ) Andrew Tridgell 2002
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
static TDB_CONTEXT * tdb ;
2002-04-12 07:42:44 +04:00
# define NAME_LENGTH 20
2002-04-12 07:26:19 +04:00
2002-04-12 07:54:13 +04:00
static unsigned total , collisions , failures ;
2002-04-12 07:26:19 +04:00
static BOOL test_one ( struct cli_state * cli , const char * name )
{
int fnum ;
fstring shortname ;
fstring name2 ;
NTSTATUS status ;
TDB_DATA data ;
total + + ;
fnum = cli_open ( cli , name , O_RDWR | O_CREAT | O_EXCL , DENY_NONE ) ;
if ( fnum = = - 1 ) {
printf ( " open of %s failed (%s) \n " , name , cli_errstr ( cli ) ) ;
return False ;
}
if ( ! cli_close ( cli , fnum ) ) {
printf ( " close of %s failed (%s) \n " , name , cli_errstr ( cli ) ) ;
return False ;
}
/* get the short name */
status = cli_qpathinfo_alt_name ( cli , name , shortname ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " query altname of %s failed (%s) \n " , name , cli_errstr ( cli ) ) ;
return False ;
}
2003-07-23 16:33:59 +04:00
fstr_sprintf ( name2 , " \\ mangle_test \\ %s " , shortname ) ;
2002-04-12 07:26:19 +04:00
if ( ! cli_unlink ( cli , name2 ) ) {
printf ( " unlink of %s (%s) failed (%s) \n " ,
name2 , name , cli_errstr ( cli ) ) ;
return False ;
}
2002-04-12 07:42:44 +04:00
/* recreate by short name */
fnum = cli_open ( cli , name2 , O_RDWR | O_CREAT | O_EXCL , DENY_NONE ) ;
if ( fnum = = - 1 ) {
printf ( " open2 of %s failed (%s) \n " , name2 , cli_errstr ( cli ) ) ;
return False ;
}
if ( ! cli_close ( cli , fnum ) ) {
printf ( " close of %s failed (%s) \n " , name , cli_errstr ( cli ) ) ;
return False ;
}
/* and unlink by long name */
if ( ! cli_unlink ( cli , name ) ) {
printf ( " unlink2 of %s (%s) failed (%s) \n " ,
name , name2 , cli_errstr ( cli ) ) ;
2002-04-12 07:54:13 +04:00
failures + + ;
cli_unlink ( cli , name2 ) ;
return True ;
2002-04-12 07:42:44 +04:00
}
2002-04-12 07:26:19 +04:00
/* see if the short name is already in the tdb */
2003-07-11 00:37:01 +04:00
data = tdb_fetch_bystring ( tdb , shortname ) ;
2002-04-12 07:26:19 +04:00
if ( data . dptr ) {
/* maybe its a duplicate long name? */
if ( strcasecmp ( name , data . dptr ) ! = 0 ) {
/* we have a collision */
collisions + + ;
2002-07-15 14:35:28 +04:00
printf ( " Collision between %s and %s -> %s "
" (coll/tot: %u/%u) \n " ,
name , data . dptr , shortname , collisions , total ) ;
2002-04-12 07:26:19 +04:00
}
free ( data . dptr ) ;
} else {
2002-11-07 18:32:48 +03:00
TDB_DATA namedata ;
2002-04-12 07:26:19 +04:00
/* store it for later */
2002-11-07 18:32:48 +03:00
namedata . dptr = name ;
namedata . dsize = strlen ( name ) + 1 ;
2003-07-11 00:37:01 +04:00
tdb_store_bystring ( tdb , shortname , namedata , TDB_REPLACE ) ;
2002-04-12 07:26:19 +04:00
}
return True ;
}
static void gen_name ( char * name )
{
2003-04-23 12:12:34 +04:00
const char * chars = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._-$~... " ;
2002-04-12 07:26:19 +04:00
unsigned max_idx = strlen ( chars ) ;
unsigned len ;
int i ;
char * p ;
fstrcpy ( name , " \\ mangle_test \\ " ) ;
p = name + strlen ( name ) ;
len = 1 + random ( ) % NAME_LENGTH ;
for ( i = 0 ; i < len ; i + + ) {
p [ i ] = chars [ random ( ) % max_idx ] ;
}
p [ i ] = 0 ;
if ( strcmp ( p , " . " ) = = 0 | | strcmp ( p , " .. " ) = = 0 ) {
p [ 0 ] = ' _ ' ;
}
2002-04-12 07:42:44 +04:00
/* have a high probability of a common lead char */
if ( random ( ) % 2 = = 0 ) {
p [ 0 ] = ' A ' ;
}
2002-04-12 07:54:13 +04:00
/* and a medium probability of a common lead string */
if ( random ( ) % 10 = = 0 ) {
2003-04-23 12:12:34 +04:00
if ( strlen ( p ) < = 5 ) {
fstrcpy ( p , " ABCDE " ) ;
} else {
/* try not to kill off the null termination */
memcpy ( p , " ABCDE " , 5 ) ;
}
2002-04-12 07:54:13 +04:00
}
2002-04-12 07:42:44 +04:00
/* and a high probability of a good extension length */
if ( random ( ) % 2 = = 0 ) {
char * s = strrchr ( p , ' . ' ) ;
if ( s ) {
s [ 4 ] = 0 ;
}
}
2002-04-12 07:26:19 +04:00
}
BOOL torture_mangle ( int dummy )
{
extern int torture_numops ;
2003-04-23 12:12:34 +04:00
static struct cli_state * cli ;
2002-04-12 07:26:19 +04:00
int i ;
2003-04-23 12:12:34 +04:00
BOOL ret = True ;
2002-04-12 07:26:19 +04:00
printf ( " starting mangle test \n " ) ;
if ( ! torture_open_connection ( & cli ) ) {
return False ;
}
/* we will use an internal tdb to store the names we have used */
tdb = tdb_open ( NULL , 100000 , TDB_INTERNAL , 0 , 0 ) ;
if ( ! tdb ) {
printf ( " ERROR: Failed to open tdb \n " ) ;
return False ;
}
2003-04-23 12:12:34 +04:00
cli_unlink ( cli , " \\ mangle_test \\ * " ) ;
cli_rmdir ( cli , " \\ mangle_test " ) ;
2002-04-12 07:26:19 +04:00
2003-04-23 12:12:34 +04:00
if ( ! cli_mkdir ( cli , " \\ mangle_test " ) ) {
2002-04-12 07:26:19 +04:00
printf ( " ERROR: Failed to make directory \n " ) ;
return False ;
}
for ( i = 0 ; i < torture_numops ; i + + ) {
fstring name ;
2003-04-23 12:12:34 +04:00
ZERO_STRUCT ( name ) ;
2002-04-12 07:26:19 +04:00
gen_name ( name ) ;
2003-04-23 12:12:34 +04:00
if ( ! test_one ( cli , name ) ) {
ret = False ;
2002-04-12 07:26:19 +04:00
break ;
}
if ( total & & total % 100 = = 0 ) {
2002-04-12 07:54:13 +04:00
printf ( " collisions %u/%u - %.2f%% (%u failures) \r " ,
collisions , total , ( 100.0 * collisions ) / total , failures ) ;
2002-04-12 07:26:19 +04:00
}
}
2003-04-23 12:12:34 +04:00
cli_unlink ( cli , " \\ mangle_test \\ * " ) ;
if ( ! cli_rmdir ( cli , " \\ mangle_test " ) ) {
2002-04-12 07:26:19 +04:00
printf ( " ERROR: Failed to remove directory \n " ) ;
return False ;
}
2002-04-12 07:54:13 +04:00
printf ( " \n Total collisions %u/%u - %.2f%% (%u failures) \n " ,
collisions , total , ( 100.0 * collisions ) / total , failures ) ;
2002-04-12 07:26:19 +04:00
2003-04-23 12:12:34 +04:00
torture_close_connection ( cli ) ;
2002-04-12 07:26:19 +04:00
printf ( " mangle test finished \n " ) ;
2003-04-23 12:12:34 +04:00
return ( ret & & ( failures = = 0 ) ) ;
2002-04-12 07:26:19 +04:00
}