Fix Sys_ListFiles() on POSIX as needed for savegames

In Sys_ListFiles() the extension was abused to match whole
filenames (of savegames), not just their extensions - that
didn't work with the POSIX backend, now it does.

Sys_ListFiles() now also supports "*" as a wildcard that matches
all files - needed for deleting savegames.
However, things like "bl*" or "*ub" don't work.

While at it, I replaced readdir() with the thread-safe readdir_r()
This commit is contained in:
Daniel Gibson 2012-12-29 05:23:06 +01:00
parent f77ca851d5
commit 1e3bc3429b

View file

@ -359,8 +359,11 @@ int Sys_ListFiles( const char* directory, const char* extension, idStrList& list
debug = cvarSystem->GetCVarBool( "fs_debug" ); debug = cvarSystem->GetCVarBool( "fs_debug" );
if( !extension ) // DG: handle "*" as special case that matches everything
// FIXME: handle * properly as a wildcase somewhere in the string?
if( !extension || ( extension[0] == '*' && extension[1] == '\0' ) )
extension = ""; extension = "";
// DG end
// passing a slash as extension will find directories // passing a slash as extension will find directories
if( extension[0] == '/' && extension[1] == 0 ) if( extension[0] == '/' && extension[1] == 0 )
@ -380,20 +383,42 @@ int Sys_ListFiles( const char* directory, const char* extension, idStrList& list
return -1; return -1;
} }
while( ( d = readdir( fdir ) ) != NULL ) // DG: use readdir_r instead of readdir for thread safety
// the following lines are from the readdir_r manpage.. fscking ugly.
int nameMax = pathconf( directory, _PC_NAME_MAX );
if( nameMax == -1 )
nameMax = 255;
int direntLen = offsetof( struct dirent, d_name ) + nameMax + 1;
struct dirent* entry = ( struct dirent* )Mem_Alloc( direntLen, TAG_CRAP );
if( entry == NULL )
{ {
common->Warning( "Sys_ListFiles: Mem_Alloc for entry failed!" );
closedir( fdir );
return 0;
}
int extLen = idStr::Length( extension );
while( readdir_r( fdir, entry, &d ) == 0 && d != NULL )
{
// DG end
idStr::snPrintf( search, sizeof( search ), "%s/%s", directory, d->d_name ); idStr::snPrintf( search, sizeof( search ), "%s/%s", directory, d->d_name );
if( stat( search, &st ) == -1 ) if( stat( search, &st ) == -1 )
continue; continue;
if( !dironly ) if( !dironly )
{ {
idStr look( search ); // DG: the original code didn't work because d3 bfg abuses the extension
idStr ext; // to match whole filenames in the savegame-code, not just file extensions...
look.ExtractFileExtension( ext ); // the extension must be the last chars of the filename
if( extension[0] != '\0' && ext.Icmp( &extension[1] ) != 0 ) // so start matching at startPos = strlen(d->d_name) - strlen(extension)
{ int startPos = idStr::Length( d->d_name ) - extLen;
// of course the extension can't match if it's longer than the filename, i.e. startPos < 0
if( startPos < 0 || idStr::FindText( d->d_name, extension, true, startPos ) < 0 )
continue; continue;
}
// DG end
} }
if( ( dironly && !( st.st_mode & S_IFDIR ) ) || if( ( dironly && !( st.st_mode & S_IFDIR ) ) ||
( !dironly && ( st.st_mode & S_IFDIR ) ) ) ( !dironly && ( st.st_mode & S_IFDIR ) ) )
@ -403,6 +428,7 @@ int Sys_ListFiles( const char* directory, const char* extension, idStrList& list
} }
closedir( fdir ); closedir( fdir );
Mem_Free( entry );
if( debug ) if( debug )
{ {