From 1e3bc3429bded775d451999a1127473d888f5bd9 Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Sat, 29 Dec 2012 05:23:06 +0100 Subject: [PATCH] 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() --- neo/sys/posix/posix_main.cpp | 44 ++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/neo/sys/posix/posix_main.cpp b/neo/sys/posix/posix_main.cpp index 362b64d2..1c45d29e 100644 --- a/neo/sys/posix/posix_main.cpp +++ b/neo/sys/posix/posix_main.cpp @@ -359,9 +359,12 @@ int Sys_ListFiles( const char* directory, const char* extension, idStrList& list 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 = ""; - + // DG end + // passing a slash as extension will find directories if( extension[0] == '/' && extension[1] == 0 ) { @@ -380,20 +383,42 @@ int Sys_ListFiles( const char* directory, const char* extension, idStrList& list 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 ); if( stat( search, &st ) == -1 ) continue; if( !dironly ) { - idStr look( search ); - idStr ext; - look.ExtractFileExtension( ext ); - if( extension[0] != '\0' && ext.Icmp( &extension[1] ) != 0 ) - { + // DG: the original code didn't work because d3 bfg abuses the extension + // to match whole filenames in the savegame-code, not just file extensions... + // the extension must be the last chars of the filename + // 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; - } + + // DG end } if( ( 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 ); + Mem_Free( entry ); if( debug ) {