From 5079343ecd43fa30fdf15f66a436764b9807d3fb Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <icculus@icculus.org>
Date: Tue, 15 Sep 2009 00:19:22 +0000
Subject: [PATCH] Fixed infinite recursion of writing crashlog because we're
 out of file handles.

  Fixes Bugzilla #3772.
---
 code/qcommon/files.c   |  2 +-
 code/qcommon/qcommon.h |  1 +
 code/sys/sys_unix.c    | 31 ++++++++++++++++++++++++-------
 3 files changed, 26 insertions(+), 8 deletions(-)

diff --git a/code/qcommon/files.c b/code/qcommon/files.c
index 1d2ae181..7bbfc45d 100644
--- a/code/qcommon/files.c
+++ b/code/qcommon/files.c
@@ -478,7 +478,7 @@ FS_CreatePath
 Creates any directories needed to store the given filename
 ============
 */
-static qboolean FS_CreatePath (char *OSPath) {
+qboolean FS_CreatePath (char *OSPath) {
 	char	*ofs;
 	
 	// make absolutely sure that it can't back up the path
diff --git a/code/qcommon/qcommon.h b/code/qcommon/qcommon.h
index e9b90377..a2d81060 100644
--- a/code/qcommon/qcommon.h
+++ b/code/qcommon/qcommon.h
@@ -602,6 +602,7 @@ void	FS_FreeFileList( char **list );
 
 qboolean FS_FileExists( const char *file );
 
+qboolean FS_CreatePath (char *OSPath);
 char   *FS_BuildOSPath( const char *base, const char *game, const char *qpath );
 
 int		FS_LoadStack( void );
diff --git a/code/sys/sys_unix.c b/code/sys/sys_unix.c
index 470c89fd..bcbb0860 100644
--- a/code/sys/sys_unix.c
+++ b/code/sys/sys_unix.c
@@ -35,6 +35,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include <sys/time.h>
 #include <pwd.h>
 #include <libgen.h>
+#include <fcntl.h>
 
 // Used to determine where to store user-specific files
 static char homePath[ MAX_OSPATH ] = { 0 };
@@ -501,23 +502,39 @@ void Sys_ErrorDialog( const char *error )
 {
 	char buffer[ 1024 ];
 	unsigned int size;
-	fileHandle_t f;
+	int f = -1;
+	const char *homepath = Cvar_VariableString( "fs_homepath" );
+	const char *gamedir = Cvar_VariableString( "fs_gamedir" );
 	const char *fileName = "crashlog.txt";
+	char *ospath = FS_BuildOSPath( homepath, gamedir, fileName );
 
 	Sys_Print( va( "%s\n", error ) );
 
-	// Write console log to file
-	f = FS_FOpenFileWrite( fileName );
-	if( !f )
+	/* make sure the write path for the crashlog exists... */
+	if( FS_CreatePath( ospath ) ) {
+		Com_Printf( "ERROR: couldn't create path '%s' for crash log.\n", ospath );
+		return;
+	}
+
+	/* we might be crashing because we maxed out the Quake MAX_FILE_HANDLES,
+	   which will come through here, so we don't want to recurse forever by
+	   calling FS_FOpenFileWrite()...use the Unix system APIs instead. */
+	f = open(ospath, O_CREAT | O_TRUNC | O_WRONLY, 0640);
+	if( f == -1 )
 	{
 		Com_Printf( "ERROR: couldn't open %s\n", fileName );
 		return;
 	}
 
-	while( ( size = CON_LogRead( buffer, sizeof( buffer ) ) ) > 0 )
-		FS_Write( buffer, size, f );
+	/* We're crashing, so we don't care much if write() or close() fails. */
+	while( ( size = CON_LogRead( buffer, sizeof( buffer ) ) ) > 0 ) {
+		if (write( f, buffer, size ) != size) {
+			Com_Printf( "ERROR: couldn't fully write to %s\n", fileName );
+			break;
+		}
+	}
 
-	FS_FCloseFile( f );
+	close(f);
 }
 
 /*