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
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
2002-04-12 07:26:19 +04:00
( 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
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2002-04-12 07:26:19 +04:00
*/
# include "includes.h"
2011-02-26 01:20:06 +03:00
# include "system/filesys.h"
2009-11-24 13:43:56 +03:00
# include "torture/proto.h"
2011-05-06 13:47:43 +04:00
# include "libsmb/libsmb.h"
2011-02-24 12:46:55 +03:00
# include "libsmb/clirap.h"
2011-05-05 13:25:29 +04:00
# include "util_tdb.h"
2002-04-12 07:26:19 +04:00
2005-05-02 21:49:43 +04:00
extern int torture_numops ;
2002-04-12 07:26:19 +04:00
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
2007-10-19 04:40:25 +04:00
static bool test_one ( struct cli_state * cli , const char * name )
2002-04-12 07:26:19 +04:00
{
2009-05-01 02:26:43 +04:00
uint16_t fnum ;
2002-04-12 07:26:19 +04:00
fstring shortname ;
fstring name2 ;
NTSTATUS status ;
TDB_DATA data ;
total + + ;
2011-02-01 13:27:55 +03:00
status = cli_open ( cli , name , O_RDWR | O_CREAT | O_EXCL , DENY_NONE , & fnum ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " open of %s failed (%s) \n " , name , nt_errstr ( status ) ) ;
2002-04-12 07:26:19 +04:00
return False ;
}
2011-02-01 13:27:55 +03:00
status = cli_close ( cli , fnum ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " close of %s failed (%s) \n " , name , nt_errstr ( status ) ) ;
2002-04-12 07:26:19 +04:00
return False ;
}
/* get the short name */
status = cli_qpathinfo_alt_name ( cli , name , shortname ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-02-01 13:27:55 +03:00
printf ( " query altname of %s failed (%s) \n " , name , nt_errstr ( status ) ) ;
2002-04-12 07:26:19 +04:00
return False ;
}
2003-07-23 16:33:59 +04:00
fstr_sprintf ( name2 , " \\ mangle_test \\ %s " , shortname ) ;
2011-02-01 13:27:55 +03:00
status = cli_unlink ( cli , name2 , FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2002-04-12 07:26:19 +04:00
printf ( " unlink of %s (%s) failed (%s) \n " ,
2011-02-01 13:27:55 +03:00
name2 , name , nt_errstr ( status ) ) ;
2002-04-12 07:26:19 +04:00
return False ;
}
2002-04-12 07:42:44 +04:00
/* recreate by short name */
2011-02-01 13:27:55 +03:00
status = cli_open ( cli , name2 , O_RDWR | O_CREAT | O_EXCL , DENY_NONE , & fnum ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " open2 of %s failed (%s) \n " , name2 , nt_errstr ( status ) ) ;
2002-04-12 07:42:44 +04:00
return False ;
}
2011-02-01 13:27:55 +03:00
status = cli_close ( cli , fnum ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " close of %s failed (%s) \n " , name , nt_errstr ( status ) ) ;
2002-04-12 07:42:44 +04:00
return False ;
}
/* and unlink by long name */
2011-02-01 13:27:55 +03:00
status = cli_unlink ( cli , name , FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2002-04-12 07:42:44 +04:00
printf ( " unlink2 of %s (%s) failed (%s) \n " ,
2011-02-01 13:27:55 +03:00
name , name2 , nt_errstr ( status ) ) ;
2002-04-12 07:54:13 +04:00
failures + + ;
2011-04-29 07:23:14 +04:00
cli_unlink ( cli , name2 , FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN ) ;
2002-04-12 07:54:13 +04:00
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? */
2007-03-29 13:35:51 +04:00
if ( ! strequal ( name , ( const char * ) data . dptr ) ) {
2002-04-12 07:26:19 +04:00
/* 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 */
2011-05-06 03:19:49 +04:00
namedata . dptr = discard_const_p ( uint8 , name ) ;
2002-11-07 18:32:48 +03:00
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 ;
}
}
2004-07-08 16:42:01 +04:00
/* ..... and a 100% proability of a file not ending in "." */
if ( p [ strlen ( p ) - 1 ] = = ' . ' )
2004-07-11 15:33:25 +04:00
p [ strlen ( p ) - 1 ] = ' _ ' ;
2002-04-12 07:26:19 +04:00
}
2007-10-19 04:40:25 +04:00
bool torture_mangle ( int dummy )
2002-04-12 07:26:19 +04:00
{
2003-04-23 12:12:34 +04:00
static struct cli_state * cli ;
2002-04-12 07:26:19 +04:00
int i ;
2007-10-19 04:40:25 +04:00
bool ret = True ;
2002-04-12 07:26:19 +04:00
printf ( " starting mangle test \n " ) ;
2006-07-31 13:41:25 +04:00
if ( ! torture_open_connection ( & cli , 0 ) ) {
2002-04-12 07:26:19 +04:00
return False ;
}
/* we will use an internal tdb to store the names we have used */
2011-06-20 13:10:32 +04:00
tdb = tdb_open_compat ( NULL , 100000 , TDB_INTERNAL , 0 , 0 , NULL , NULL ) ;
2002-04-12 07:26:19 +04:00
if ( ! tdb ) {
printf ( " ERROR: Failed to open tdb \n " ) ;
return False ;
}
2011-04-29 07:23:14 +04:00
cli_unlink ( cli , " \\ mangle_test \\ * " , FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN ) ;
2003-04-23 12:12:34 +04:00
cli_rmdir ( cli , " \\ mangle_test " ) ;
2002-04-12 07:26:19 +04:00
2009-04-21 16:52:34 +04:00
if ( ! NT_STATUS_IS_OK ( 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
}
}
2011-04-29 07:23:14 +04:00
cli_unlink ( cli , " \\ mangle_test \\ * " , FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN ) ;
2009-04-21 17:52:54 +04:00
if ( ! NT_STATUS_IS_OK ( 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
}