// *naka* - find a file within another file
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <sys/mman.h>
# include <ints.h>
# include <macros.h>
# include <version.h>
# include <project.h>
# include <tests.h>
# include <map.h>
# include <comp.h>
void prog_info ( FILE * out )
{
fprintf ( out , PROG_NAME " v%s - " PROG_DESCRIPTION
# ifdef DEBUG
" (debug build) "
# endif
" \n written by %s with <3 (compiled at %lu UTC (unix ts)) \n license %s. \n " ,
v_ctoss ( v_rawtoc ( PROG_VERSION ) ) ,
PROG_AUTHOUR ,
PROG_COMPILED_TIMESTAMP ,
PROG_LICENSE ) ;
}
void usage ( FILE * out , int argc , char * * argv )
{
IGNORE ( argc ) ;
prog_info ( out ) ;
fprintf ( out , " \n Usage: %s <needle> <haystack(s)...> \n " , argv [ 0 ] ? : PROG_NAME ) ;
fprintf ( out , " \n Usage: %s --help \n " , argv [ 0 ] ? : PROG_NAME ) ;
}
// err: 0 for normal exit and print to stdout.
// err: nonzero for abnormal exit and print to stderr.
noreturn void usage_then_exit ( int err , int argc , char * * argv )
{
usage ( err ? stderr : stdout , argc , argv ) ;
exit ( err ) ;
}
static int map_haystacks ( const char * const * h , map_t maps [ pOUT ] )
{
const char * path ;
usize d = 0 ;
while ( ( path = * h + + ) )
{
map_t * pOUT c = maps + + ;
INFO ( " Mapping haystack file `%s' (to map addr %p) " , path , c ) ;
debug_assert ( c ) ;
if ( ! map_handle_err ( map_file ( path , false , 0 , 0 , c ) ) ) {
//Handle unmapping previous haystacks before return
// Prep reset maps to before `c` for unwind
maps - = 1 ;
ERROR ( " Failed to map file `%s', rolling back %lu maps. (erp: %p, prev: %p) " , path , d , c , maps ) ;
while ( d - - > 0 )
if ( ! map_handle_err ( map_free ( * ( - - maps ) ) ) ) WARN ( " Failed to free map at %p (in %lu unwind) " , maps , d ) ;
return 0 ;
}
d + = 1 ;
}
return 1 ;
}
int main ( int argc , char * * argv )
{
TRACE ( " main start with %d (pn: %s, a1: %s) " , argc , argv [ 0 ] , argv [ 1 ] ? : " <null> " ) ;
if ( ! argv [ 1 ] )
inv_args :
usage_then_exit ( PROG_RET_ARGS , argc , argv ) ;
else if ( strcmp ( argv [ 1 ] , " --help " ) = = 0 )
usage_then_exit ( 0 , argc , argv ) ;
else if ( ! argv [ 2 ] )
goto inv_args ;
map_t needle ;
INFO ( " Mapping needle file `%s' " , argv [ 1 ] ) ;
if ( ! map_handle_err ( map_file ( argv [ 1 ] , false , 0 , 0 , & needle ) ) ) return PROG_RET_MAP_NEEDLE_FAILED ;
if ( ! map_handle_err ( map_preload ( & needle , false ) ) ) WARN ( " Failed to advise kernel about memory access: needle " ) ;
// Remove exe name from argv: now is (needle, haystacks...)
argv + = 1 ;
// Setup haystack maps
usize hsn = AS ( argc - 2 , usize ) ;
map_t haystacks [ hsn ] ;
TRACE ( " Attempting to map %lu haystacks " , hsn ) ;
if ( ! map_haystacks ( ( const char * * ) ( argv + 1 ) , haystacks ) ) return PROG_RET_MAP_HAYSTACK_FAILED ;
# ifdef _FEATURE_PARALLEL // Multi-threaded
//TODO: Setup thread-pool.
//TODO: Dispatch haystack maps to threadpool.
//TODO: Use either `cmp_find()` or `cmp_find_many()` to find the `needle` (mapped above) within those haystacks.
//TODO: Within the threadpool: output information regarding each match/nonmatch.
//TODO: Join the threadpool and consolidate results.
//TODO: Iterate through the haystack numbers match results, return the first non-match haystack number through `PROG_RET_MATCH_HAYSTACK_N_FAILED(n)` (haystack numbers are always nonzero). If all were matched, return 0
# else // Single-threaded
INFO ( " Computing result for %lu haystacks... " , hsn ) ;
comp_multires_t * full_result = comp_match_all ( & needle , hsn , haystacks , false ) ;
// Number of results actually computed by `comp_match_all()` may differ from `hsn` if `abort_on_fail` is true (currently its hardcoded to false but that may change.)
usize cres = full_result - > num_results ;
INFO ( " Computed result: Suc. Matched %lu / %lu hs. Full match: %s (first failure: %d) " , cres , hsn , full_result - > all_matched ? " yes " : " no " , full_result - > idx_first_failure ) ;
free ( full_result ) ;
# endif
for ( int i = 0 ; i < ( int ) hsn ; i + + ) {
INFO ( " Unmapping haystack haystack file `%s' (#%d) (map addr %p) " , argv [ i + 1 ] , i + 1 , haystacks + i ) ;
if ( ! map_handle_err ( map_free ( haystacks [ i ] ) ) ) return PROG_RET_UNMAP_HAYSTACK_N_FAILED ( i + 1 ) ;
}
INFO ( " Unmapping needle file `%s' " , * argv ) ;
if ( ! map_handle_err ( map_free ( needle ) ) ) return PROG_RET_UNMAP_NEEDLE_FAILED ;
TRACE ( " main end " ) ;
return 0 ;
}