diff --git a/src/engine/builtins.c b/src/engine/builtins.c index 22485ceb1..f96a32de8 100644 --- a/src/engine/builtins.c +++ b/src/engine/builtins.c @@ -627,7 +627,6 @@ static void builtin_glob_back( void * closure, OBJECT * file, int status, PROFILE_ENTER( BUILTIN_GLOB_BACK ); struct globbing * const globbing = (struct globbing *)closure; - LIST * l; PATHNAME f; string buf[ 1 ]; LISTITER iter; diff --git a/src/engine/filent.c b/src/engine/filent.c index 2cb000d4b..af3f719f6 100644 --- a/src/engine/filent.c +++ b/src/engine/filent.c @@ -15,7 +15,6 @@ * filent.c - scan directories and archives on NT * * External routines: - * * file_dirscan() - scan a directory for files * file_time() - get timestamp of file, if not done by file_dirscan() * file_archscan() - scan an archive for files @@ -77,25 +76,17 @@ void file_dirscan( OBJECT * dir, scanback func, void * closure ) PATHNAME f; string filespec[ 1 ]; string filename[ 1 ]; - long handle; - int ret; struct _finddata_t finfo[ 1 ]; LIST * files = L0; - int d_length; - - dir = short_path_to_long_path( dir ); - - d_length = strlen( object_str( dir ) ); + OBJECT * const long_dir = short_path_to_long_path( dir ); + int const d_length = strlen( object_str( long_dir ) ); memset( (char *)&f, '\0', sizeof( f ) ); - f.f_dir.ptr = object_str( dir ); - f.f_dir.len = d_length; - /* Now enter contents of directory */ /* Prepare file search specification for the findfirst() API. */ - if ( d_length == 0 ) + if ( !d_length ) string_copy( filespec, ".\\*" ); else { @@ -103,85 +94,82 @@ void file_dirscan( OBJECT * dir, scanback func, void * closure ) * its trailing path separator or otherwise we would not support the * Windows root folder specified without its drive letter, i.e. '\'. */ - char const trailingChar = object_str( dir )[ d_length - 1 ] ; - string_copy( filespec, object_str( dir ) ); + char const trailingChar = object_str( long_dir )[ d_length - 1 ] ; + string_copy( filespec, object_str( long_dir ) ); if ( ( trailingChar != '\\' ) && ( trailingChar != '/' ) ) string_append( filespec, "\\" ); string_append( filespec, "*" ); } if ( DEBUG_BINDSCAN ) - printf( "scan directory %s\n", dir ); + printf( "scan directory %s\n", long_dir ); + + object_free( long_dir ); #if defined(__BORLANDC__) && __BORLANDC__ < 0x550 - if ( ret = findfirst( filespec->value, finfo, FA_NORMAL | FA_DIREC ) ) + if ( findfirst( filespec->value, finfo, FA_NORMAL | FA_DIREC ) ) { string_free( filespec ); - object_free( dir ); PROFILE_EXIT( FILE_DIRSCAN ); return; } string_new( filename ); - while ( !ret ) + do { - file_info_t * ff; - f.f_base.ptr = finfo->ff_name; f.f_base.len = strlen( finfo->ff_name ); - string_truncate( filename, 0 ); path_build( &f, filename ); files = list_push_back( files, object_new( filename->value ) ); - ff = file_info( filename->value ); - ff->is_file = finfo->ff_attrib & FA_DIREC ? 0 : 1; - ff->is_dir = !ff->is_file; - ff->size = finfo->ff_fsize; - ff->time = ( finfo->ff_ftime << 16 ) | finfo->ff_ftime; - - ret = findnext( finfo ); + { + file_info_t * const ff = file_info( filename->value ); + ff->is_file = finfo->ff_attrib & FA_DIREC ? 0 : 1; + ff->is_dir = !ff->is_file; + ff->size = finfo->ff_fsize; + ff->time = ( finfo->ff_ftime << 16 ) | finfo->ff_ftime; + } } + while ( !findnext( finfo ) ); #else - handle = _findfirst( filespec->value, finfo ); - - if ( ret = ( handle < 0L ) ) { - string_free( filespec ); - object_free( dir ); - PROFILE_EXIT( FILE_DIRSCAN ); - return; + long const handle = _findfirst( filespec->value, finfo ); + if ( handle < 0L ) + { + string_free( filespec ); + PROFILE_EXIT( FILE_DIRSCAN ); + return; + } + + string_new( filename ); + do + { + OBJECT * filename_obj; + + f.f_base.ptr = finfo->name; + f.f_base.len = strlen( finfo->name ); + string_truncate( filename, 0 ); + path_build( &f, filename, 0 ); + + filename_obj = object_new( filename->value ); + path_key__register_long_path( filename_obj ); + files = list_push_back( files, filename_obj ); + { + file_info_t * const ff = file_info( filename_obj ); + ff->is_file = finfo->attrib & _A_SUBDIR ? 0 : 1; + ff->is_dir = !ff->is_file; + ff->size = finfo->size; + ff->time = finfo->time_write; + } + } + while ( !_findnext( handle, finfo ) ); + + _findclose( handle ); } - - string_new( filename ); - while ( !ret ) - { - OBJECT * filename_obj; - file_info_t * ff; - - f.f_base.ptr = finfo->name; - f.f_base.len = strlen( finfo->name ); - - string_truncate( filename, 0 ); - path_build( &f, filename, 0 ); - - filename_obj = object_new( filename->value ); - path_key__register_long_path( filename_obj ); - files = list_push_back( files, filename_obj ); - ff = file_info( filename_obj ); - ff->is_file = finfo->attrib & _A_SUBDIR ? 0 : 1; - ff->is_dir = !ff->is_file; - ff->size = finfo->size; - ff->time = finfo->time_write; - - ret = _findnext( handle, finfo ); - } - - _findclose( handle ); #endif string_free( filename ); string_free( filespec ); - object_free( dir ); d->files = files; } @@ -191,16 +179,12 @@ void file_dirscan( OBJECT * dir, scanback func, void * closure ) unsigned long len = strlen( object_str( d->name ) ); if ( len == 1 && object_str( d->name )[ 0 ] == '\\' ) { - OBJECT * const dir = short_path_to_long_path( d->name ); - (*func)( closure, dir, 1 /* stat()'ed */, d->time ); - object_free( dir ); + OBJECT * const long_dir = short_path_to_long_path( d->name ); + (*func)( closure, long_dir, 1 /* stat()'ed */, d->time ); + object_free( long_dir ); } else if ( len == 3 && object_str( d->name )[ 1 ] == ':' ) { - char buf[ 4 ]; - OBJECT * const dir1 = short_path_to_long_path( d->name ); - OBJECT * dir2; - (*func)( closure, dir1, 1 /* stat()'ed */, d->time ); /* We have just entered a 3-letter drive name spelling (with a * trailing slash), into the hash table. Now enter its two-letter * variant, without the trailing slash, so that if we try to check @@ -213,9 +197,14 @@ void file_dirscan( OBJECT * dir, scanback func, void * closure ) * There will be no trailing slash in $(p), but there will be one in * $(p2). But, that seems rather fragile. */ - strcpy( buf, object_str( dir1 ) ); + OBJECT * const dir1 = short_path_to_long_path( d->name ); + OBJECT * dir2; + char buf[ 3 ]; + buf[ 0 ] = object_str( dir1 )[ 0 ]; + buf[ 1 ] = object_str( dir1 )[ 1 ]; buf[ 2 ] = 0; dir2 = object_new( buf ); + (*func)( closure, dir1, 1 /* stat()'ed */, d->time ); (*func)( closure, dir2, 1 /* stat()'ed */, d->time ); object_free( dir2 ); object_free( dir1 ); diff --git a/src/engine/filesys.c b/src/engine/filesys.c index f9dde2828..15807208e 100644 --- a/src/engine/filesys.c +++ b/src/engine/filesys.c @@ -37,30 +37,28 @@ void file_build1( PATHNAME * f, string * file ) static struct hash * filecache_hash = 0; -static file_info_t filecache_finfo; file_info_t * file_info( OBJECT * filename ) { - file_info_t * finfo = &filecache_finfo; + OBJECT * const path_key = path_as_key( filename ); + file_info_t * finfo; int found; if ( !filecache_hash ) filecache_hash = hashinit( sizeof( file_info_t ), "file_info" ); - filename = path_as_key( filename ); - - finfo = (file_info_t *)hash_insert( filecache_hash, filename, &found ); + finfo = (file_info_t *)hash_insert( filecache_hash, path_key, &found ); if ( !found ) { - finfo->name = object_copy( filename ); + finfo->name = path_key; finfo->is_file = 0; finfo->is_dir = 0; finfo->size = 0; finfo->time = 0; finfo->files = L0; } - - object_free( filename ); + else + object_free( path_key ); return finfo; } diff --git a/src/engine/filesys.h b/src/engine/filesys.h index 2eb76ccc1..4182f09f4 100644 --- a/src/engine/filesys.h +++ b/src/engine/filesys.h @@ -34,8 +34,7 @@ void file_build1( PATHNAME * f, string * file ) ; int file_is_file( OBJECT * filename ); int file_mkdir( char const * pathname ); -typedef struct file_info_t file_info_t ; -struct file_info_t +typedef struct file_info_t { OBJECT * name; short is_file; @@ -43,15 +42,17 @@ struct file_info_t unsigned long size; time_t time; LIST * files; -}; +} file_info_t; -/* Creates a pointer to information about file 'filename', creating it as +/* Returns a pointer to information about file 'filename', creating it as * necessary. If created, the structure will be default initialized. */ file_info_t * file_info( OBJECT * filename ); -/* Returns information about a file, queries the OS if needed. */ +/* Returns information about a file, queries the OS if needed. Will return 0 if + * the file does not exist. + */ file_info_t * file_query( OBJECT * filename ); void file_done(); diff --git a/src/engine/pathunix.c b/src/engine/pathunix.c index be7c6049d..0d54e4487 100644 --- a/src/engine/pathunix.c +++ b/src/engine/pathunix.c @@ -300,14 +300,21 @@ static int may_be_a_valid_short_name( char const * const n, int const n_length ) /* - * Expects the path to be already normalized, i.e. contain only '\\' path - * separators. + * ShortPathToLongPath() - convert a given path into its long format + * + * In the process, automatically registers long paths for all of the parent + * folders on the path, if they have not already been registered. + * + * Prerequisites: + * - Path to given in normalized form, i.e. all of its folder separators have + * already been converted into '\\'. + * - path_key_cache path/key mapping cache object has already been initialized. */ static void ShortPathToLongPath( char const * const path, int const path_length, string * const out ) { - char const * new_element; + char const * last_element; unsigned long saved_size; char const * p; @@ -335,7 +342,7 @@ static void ShortPathToLongPath( char const * const path, int const path_length, /* Find last '\\'. */ for ( p = path + path_length - 1; p >= path && *p != '\\'; --p ); - new_element = p + 1; + last_element = p + 1; /* Special case '\' && 'D:\' - include trailing '\'. */ if ( p == path || @@ -368,7 +375,7 @@ static void ShortPathToLongPath( char const * const path, int const path_length, string_push_back( out, '\\' ); saved_size = out->size; - string_append_range( out, new_element, path + path_length ); + string_append_range( out, last_element, path + path_length ); /* If we have a name that can not be a valid short name then it must be a * valid long name and we are done. If there is a chance this is not the @@ -380,7 +387,7 @@ static void ShortPathToLongPath( char const * const path, int const path_length, * short name. */ { - char const * const n = new_element; + char const * const n = last_element; int const n_length = path + path_length - n; if ( !( n_length == 1 && n[ 0 ] == '.' ) && !( n_length == 2 && n[ 0 ] == '.' && n[ 1 ] == '.' )