//----------------------------------------------------------------------------- // Sys_LoadFile // //----------------------------------------------------------------------------- int Sys_LoadFile( const char* filename, void** bufferptr, bool bText ) { int handle; long length; char* buffer; *bufferptr = NULL; if ( !Sys_Exists( filename ) ) return ( -1 ); handle = _open( filename, _O_RDONLY|( bText ? _O_TEXT : _O_BINARY) ); if ( handle == -1 ) Sys_Error( "Sys_LoadFile(): Error opening %s: %s", filename, strerror( errno ) ); length = Sys_FileLength( NULL, handle, bText ); buffer = ( char* )malloc( length+1 ); int bytesRead = _read( handle, buffer, length ); if ( !bText && ( bytesRead != length ) ) Sys_Error( "Sys_LoadFile(): read truncated failure" ); _close( handle ); // text mode is truncated, add null for parsing buffer[bytesRead] = '\0'; *bufferptr = ( void* )buffer; return ( length ); }
/* ============ FS_ExistsInGameDir See if a file exists in the mod directory/paks (ignores baseq2) ============ */ qboolean FS_ExistsInGameDir (char *filename) { size_t len; char *gamedir; char lowered[MAX_QPATH]; searchpath_t *search; pack_t *pak; Q_strncpy (lowered, filename, sizeof(lowered)-1); fast_strlwr (lowered); gamedir = FS_Gamedir(); len = strlen(gamedir); for (search = fs_searchpaths ; search ; search = search->next) { // is the element a pak file? if (search->pack) { packfile_t *entry; //r1: optimized btree search pak = search->pack; if (strncmp (pak->filename, gamedir, len)) continue; entry = rbfind (lowered, pak->rb); if (entry) return true; } else { char netpath[MAX_OSPATH]; if (strncmp (search->filename, gamedir, len)) continue; Com_sprintf (netpath, sizeof(netpath), "%s/%s",search->filename, filename); if (Sys_FileLength (netpath) != -1) return true; } } return false; }
DWORD EGLExceptionHandler (DWORD exceptionCode, LPEXCEPTION_POINTERS exceptionInfo) { context = *exceptionInfo->ContextRecord; // Show the mouse cursor ShowCursor (TRUE); // Continue searching? #ifdef _DEBUG if (MessageBoxA (NULL, "An unhandled exception occured in CleanCode!\n\nThis version was built with debug information. Do you have a debugger you can attach? If so, do this now, then click Yes, otherwise click No.", "Unhandled Exception", MB_ICONERROR|MB_YESNO) == IDYES) return EXCEPTION_CONTINUE_SEARCH; #endif // Load needed libraries and get the location of the needed functions hDbgHelp = LoadLibraryA ("DBGHELP"); if (!hDbgHelp) { MessageBoxA (NULL, APP_FULLNAME " has encountered an unhandled exception and must be terminated. No crash report could be generated since " APP_FULLNAME " failed to load DBGHELP.DLL. Please obtain DBGHELP.DLL and place it in your Quake II directory to enable crash dump generation.", "Unhandled Exception", MB_OK | MB_ICONEXCLAMATION); return EXCEPTION_CONTINUE_SEARCH; } hVersion = LoadLibraryA ("VERSION"); if (hVersion) { fnVerQueryValue = (VERQUERYVALUE)GetProcAddress (hVersion, "VerQueryValueA"); fnGetFileVersionInfo = (GETFILEVERSIONINFO)GetProcAddress (hVersion, "GetFileVersionInfoA"); fnGetFileVersionInfoSize = (GETFILEVERSIONINFOSIZE)GetProcAddress (hVersion, "GetFileVersionInfoSizeA"); } fnEnumerateLoadedModules64 = (ENUMERATELOADEDMODULES64)GetProcAddress (hDbgHelp, "EnumerateLoadedModules64"); fnSymSetOptions = (SYMSETOPTIONS)GetProcAddress (hDbgHelp, "SymSetOptions"); fnSymInitialize = (SYMINITIALIZE)GetProcAddress (hDbgHelp, "SymInitialize"); fnSymFunctionTableAccess64 = (SYMFUNCTIONTABLEACCESS64)GetProcAddress (hDbgHelp, "SymFunctionTableAccess64"); fnSymGetModuleBase64 = (SYMGETMODULEBASE64)GetProcAddress (hDbgHelp, "SymGetModuleBase64"); fnStackWalk64 = (STACKWALK64)GetProcAddress (hDbgHelp, "StackWalk64"); fnSymFromAddr = (SYMFROMADDR)GetProcAddress (hDbgHelp, "SymFromAddr"); fnSymCleanup = (SYMCLEANUP)GetProcAddress (hDbgHelp, "SymCleanup"); fnSymGetModuleInfo64 = (SYMGETMODULEINFO64)GetProcAddress (hDbgHelp, "SymGetModuleInfo64"); //fnSymLoadModule64 = (SYMLOADMODULE64)GetProcAddress (hDbgHelp, "SymLoadModule64"); fnMiniDumpWriteDump = (MINIDUMPWRITEDUMP)GetProcAddress (hDbgHelp, "MiniDumpWriteDump"); if (!fnEnumerateLoadedModules64 || !fnSymSetOptions || !fnSymInitialize || !fnSymFunctionTableAccess64 || !fnSymGetModuleBase64 || !fnStackWalk64 || !fnSymFromAddr || !fnSymCleanup || !fnSymGetModuleInfo64) // || !fnSymLoadModule64) { FreeLibrary (hDbgHelp); if (hVersion) FreeLibrary (hVersion); MessageBoxA (NULL, APP_FULLNAME " has encountered an unhandled exception and must be terminated. No crash report could be generated since " APP_FULLNAME " failed to load DBGHELP.DLL. Please obtain DBGHELP.DLL and place it in your Quake II directory to enable crash dump generation.", "Unhandled Exception", MB_OK | MB_ICONEXCLAMATION); return EXCEPTION_CONTINUE_SEARCH; } // Let the user know if (MessageBoxA (NULL, APP_FULLNAME " has encountered an unhandled exception and must be terminated. Would you like to generate a crash report?", "Unhandled Exception", MB_ICONEXCLAMATION | MB_YESNO) == IDNO) { FreeLibrary (hDbgHelp); if (hVersion) FreeLibrary (hVersion); return EXCEPTION_CONTINUE_SEARCH; } // Get the current process hProcess = GetCurrentProcess(); fnSymSetOptions (SYMOPT_UNDNAME | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_LOAD_ANYTHING); // Used to determine the directory for dump placement GetModuleFileNameA (NULL, searchPath, sizeof(searchPath)); tempPointer = strrchr (searchPath, '\\'); if (tempPointer) *tempPointer = '\0'; // Get the system time GetSystemTime (&timeInfo); // Find the next filename to use for this dump sint32 dumpNum = 1; for (; ; dumpNum++) { Q_snprintfz (reportPath, sizeof(reportPath), "%s\\CCCrashLog%.4d-%.2d-%.2d_%d.txt", searchPath, timeInfo.wYear, timeInfo.wMonth, timeInfo.wDay, dumpNum); if (Sys_FileLength (reportPath) == -1) break; } // Open the report dump file fhReport = fopen (reportPath, "wb"); if (!fhReport) { FreeLibrary (hDbgHelp); if (hVersion) FreeLibrary (hVersion); return EXCEPTION_CONTINUE_SEARCH; } // Initialize symbols fnSymInitialize (hProcess, searchPath, TRUE); #ifdef _M_AMD64 InstructionPtr = context.Rip; frame.AddrPC.Offset = InstructionPtr; frame.AddrFrame.Offset = context.Rbp; frame.AddrPC.Offset = context.Rsp; #else InstructionPtr = context.Eip; frame.AddrPC.Offset = InstructionPtr; frame.AddrFrame.Offset = context.Ebp; frame.AddrStack.Offset = context.Esp; #endif frame.AddrFrame.Mode = AddrModeFlat; frame.AddrPC.Mode = AddrModeFlat; frame.AddrStack.Mode = AddrModeFlat; symInfo = (SYMBOL_INFO*)LocalAlloc (LPTR, sizeof(*symInfo) + 128); symInfo->SizeOfStruct = sizeof(SYMBOL_INFO); symInfo->MaxNameLen = 128; fnOffset = 0; // Get OS info Mem_Zero (&osInfo, sizeof(osInfo)); osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); if (!GetVersionEx ((OSVERSIONINFO *)&osInfo)) { osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx ((OSVERSIONINFO *)&osInfo); } // Find out which module threw the exception Q_strncpyz (szModuleName, "<unknown>", sizeof(szModuleName)); fnEnumerateLoadedModules64 (hProcess, (PENUMLOADED_MODULES_CALLBACK64)EnumerateLoadedModulesProcInfo, (VOID *)InstructionPtr); Q_strlwr (szModuleName); if (strstr (szModuleName, "gamex86")) { upMessage = "CleanCode's Gamex86 seems to be the root problem.\r\n" "If this is not base CleanCode, send the report to the mod author,\r\n" "otherwise send it to Paril (see the log .txt for more info)\r\n"; #ifdef USE_CURL upload = false; #endif } else { upMessage = "Unable to detect where the exception occured!\r\n"; #ifdef USE_CURL upload = true; #endif } // Write out the report to file fprintf (fhReport, APP_FULLNAME " encountered an unhandled exception and was terminated. If you are\r\n" "able to reproduce this crash, please submit the crash report when prompted, or email\r\n" "the file to Paril or any CleanCode project member. Goto http://code.google.com/p/cleancodequake2 and click on\r\n" "Issues, and file a bug report, or email [email protected] with the report.\r\n" "\r\n" "*** PLEASE MAKE SURE THAT YOU ARE USING THE LATEST VERSION OF CLEANCODE BEFORE SUBMITTING ***\r\nYour Cleancode Version: "CLEANCODE_VERSION_PRINT"\r\n", CLEANCODE_VERSION_PRINT_ARGS); fprintf (fhReport, "\r\n"); // Windows information fprintf (fhReport, "Windows information:\r\n"); fprintf (fhReport, "--------------------------------------------------\r\n"); fprintf (fhReport, "String: %s\r\n", GetOSDisplayString().CString()); fprintf (fhReport, "Version: %d.%d\r\n", osInfo.dwMajorVersion, osInfo.dwMinorVersion); fprintf (fhReport, "Build: %d\r\n", osInfo.dwBuildNumber); fprintf (fhReport, "Service Pack: %s\r\n", osInfo.szCSDVersion[0] ? osInfo.szCSDVersion : "none"); fprintf (fhReport, "\r\n"); // Exception information fprintf (fhReport, "Exception information:\r\n"); fprintf (fhReport, "--------------------------------------------------\r\n"); fprintf (fhReport, "Code: "HEX_VALUE_32"\r\n", exceptionCode); fprintf (fhReport, "Address: "HEX_VALUE_64"\r\n", InstructionPtr); fprintf (fhReport, "Module: %s\r\n", szModuleName); fprintf (fhReport, "\r\n"); // Symbol information fprintf (fhReport, "Symbol information:\r\n"); fprintf (fhReport, "Name Symbol Type\r\n"); fprintf (fhReport, "-----------------------------------------------------------------------\r\n"); fnEnumerateLoadedModules64 (hProcess, (PENUMLOADED_MODULES_CALLBACK64)EEnumerateLoadedModulesProcSymInfoHeap::EnumerateLoadedModulesProcSymInfo, (VOID *)fhReport); fprintf (fhReport, "\r\n"); // Loaded modules fprintf (fhReport, "Loaded modules:\r\n"); fprintf (fhReport, "--------------------------------------------------\r\n"); fnEnumerateLoadedModules64 (hProcess, (PENUMLOADED_MODULES_CALLBACK64)EnumerateLoadedModulesProcDump, (VOID *)fhReport); fprintf (fhReport, "\r\n"); // Stack trace fprintf (fhReport, "Stack trace:\r\n"); fprintf (fhReport, "--------------------------------------------------\r\n"); fprintf (fhReport, "Stack EIP Arg0 Arg1 Arg2 Arg3 Address\r\n"); while (fnStackWalk64 (IMAGE_FILE_MACHINE_I386, hProcess, GetCurrentThread(), &frame, &context, NULL, (PFUNCTION_TABLE_ACCESS_ROUTINE64)fnSymFunctionTableAccess64, (PGET_MODULE_BASE_ROUTINE64)fnSymGetModuleBase64, NULL)) { Q_strncpyz (szModuleName, "<unknown>", sizeof(szModuleName)); fnEnumerateLoadedModules64 (hProcess, (PENUMLOADED_MODULES_CALLBACK64)EnumerateLoadedModulesProcInfo, (VOID *)(DWORD)frame.AddrPC.Offset); tempPointer = strrchr (szModuleName, '\\'); if (tempPointer) tempPointer++; else tempPointer = szModuleName; fprintf (fhReport, ""HEX_VALUE_64" "HEX_VALUE_64" "HEX_VALUE_32" "HEX_VALUE_32" "HEX_VALUE_32" "HEX_VALUE_32" %-20s ! ", frame.AddrStack.Offset, frame.AddrPC.Offset, (DWORD)frame.Params[0], (DWORD)frame.Params[1], (DWORD)frame.Params[2], (DWORD)frame.Params[3], tempPointer); if (fnSymFromAddr (hProcess, frame.AddrPC.Offset, &fnOffset, symInfo) && !(symInfo->Flags & SYMFLAG_EXPORT)) fprintf (fhReport, "%-24s + "HEX_VALUE_64" %lu\r\n", symInfo->Name, fnOffset, symInfo->Tag); else fprintf (fhReport, ""HEX_VALUE_64"\r\n", frame.AddrPC.Offset); } fprintf (fhReport, "\r\n"); // Write a minidump if (fnMiniDumpWriteDump) { HANDLE hFile; //GetTempPath (sizeof(dumpPath)-16, dumpPath); Q_snprintfz (dumpPath, sizeof(dumpPath), "%s\\CCCrashLog%.4d-%.2d-%.2d_%d.dmp", searchPath, timeInfo.wYear, timeInfo.wMonth, timeInfo.wDay, dumpNum); hFile = CreateFileA (dumpPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile != INVALID_HANDLE_VALUE) { miniInfo.ClientPointers = TRUE; miniInfo.ExceptionPointers = exceptionInfo; miniInfo.ThreadId = GetCurrentThreadId (); if (fnMiniDumpWriteDump (hProcess, GetCurrentProcessId(), hFile, (MINIDUMP_TYPE)(MiniDumpWithIndirectlyReferencedMemory|MiniDumpWithDataSegs), &miniInfo, NULL, NULL)) { CloseHandle (hFile); FILE *fh; #ifdef USE_GZ CHAR zPath[MAX_PATH]; #endif fh = fopen (dumpPath, "rb"); if (fh) #ifdef USE_GZ { gzFile gz; Q_snprintfz (zPath, sizeof(zPath)-1, "%s\\CCCrashLog%.4d-%.2d-%.2d_%d.dmp.gz", searchPath, timeInfo.wYear, timeInfo.wMonth, timeInfo.wDay, dumpNum); gz = gzopen (zPath, "wb"); if (gz) { size_t len; while ((len = fread (gzBuff, 1, sizeof(gzBuff), fh)) > 0) gzwrite (gz, gzBuff, (uint32)len); gzclose (gz); #endif fclose (fh); #ifdef USE_GZ } } #endif #ifdef USE_GZ DeleteFileA (dumpPath); Q_strncpyz (dumpPath, zPath, sizeof(dumpPath)); #endif fprintf (fhReport, "A " #ifdef USE_GZ "minidump" #else "dump" #endif " was saved to %s.\r\nPlease include this file when posting a crash report.\r\n", dumpPath); } else { CloseHandle (hFile); DeleteFileA (dumpPath); } } } else fprintf (fhReport, "A minidump could not be created. Minidumps are only available on Windows XP or later.\r\n"); // Done writing reports fclose (fhReport); LocalFree (symInfo); fnSymCleanup (hProcess); // Let the client know String temp = String::Format("Report written to: %s\r\nMini-dump written to %s\r\nPlease include both files if you submit manually!\r\n", reportPath, dumpPath); MessageBoxA (NULL, temp.CString(), "Unhandled Exception", MB_ICONEXCLAMATION | MB_OK); #ifdef USE_CURL if (upload) { ret = MessageBox (NULL, "Would you like to automatically upload this crash report for analysis?\nPlease do not submit multiple reports of the same crash as this will only delay processing.", "Unhandled Exception", MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2); if (ret == IDYES) EGLUploadCrashDump (dumpPath, reportPath); else MessageBox (NULL, "You have chosen to manually upload the crash report.\nPlease include BOTH the crash log and mini-dump when you post it on the EGL forums!\n", "Submit manually", MB_ICONEXCLAMATION|MB_OK); } else #endif MessageBoxA (NULL, upMessage, "Unhandled Exception", MB_OK|MB_ICONEXCLAMATION); // Done FreeLibrary (hDbgHelp); if (hVersion) FreeLibrary (hVersion); return EXCEPTION_EXECUTE_HANDLER; }
static VOID EGLUploadCrashDump (LPCSTR crashDump, LPCSTR crashText) { struct curl_httppost* post = NULL; struct curl_httppost* last = NULL; CURL *curl; __try { DWORD lenDmp = Sys_FileLength (crashDump); DWORD lenTxt = Sys_FileLength (crashText); if (lenTxt == -1) return; Sys_SetConsoleTitle ("EGL Crash Dump Uploader"); Sys_ConsolePrint ("Connecting...\n"); curl = curl_easy_init (); // Add simple file section if (lenDmp > 0) curl_formadd (&post, &last, CURLFORM_PTRNAME, "minidump", CURLFORM_FILE, crashDump, CURLFORM_END); curl_formadd (&post, &last, CURLFORM_PTRNAME, "report", CURLFORM_FILE, crashText, CURLFORM_END); // Set the form info curl_easy_setopt (curl, CURLOPT_HTTPPOST, post); // if (cl_http_proxy) // curl_easy_setopt (curl, CURLOPT_PROXY, cl_http_proxy->string); //curl_easy_setopt (curl, CURLOPT_UPLOAD, 1); curl_easy_setopt (curl, CURLOPT_PROGRESSFUNCTION, EGLUploadProgress); curl_easy_setopt (curl, CURLOPT_PROGRESSDATA, curl); curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 0); curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1); curl_easy_setopt (curl, CURLOPT_USERAGENT, APP_FULLNAME); curl_easy_setopt (curl, CURLOPT_URL, "http://egl.quakedev.com/reports/receiveCrashDump.php"); if (curl_easy_perform (curl) != CURLE_OK) { MessageBox (NULL, "An error occured while trying to upload the crash dump. Please post it manually on the EGL forums.", "Upload Error", MB_ICONEXCLAMATION | MB_OK); } else { long response; if (curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &response) == CURLE_OK) { switch (response) { case 200: MessageBox (NULL, "Upload completed. Thanks for submitting your crash report!\n\n" "If you would like feedback on the cause of this crash, post on the EGL forums describing what you were\n" "doing at the time the exception occured. If possible, please also attach the EGLCrashLog.txt file.", "Upload Complete", MB_ICONINFORMATION | MB_OK); break; default: MessageBox (NULL, "Upload failed, HTTP error.", "Upload Failed", MB_ICONEXCLAMATION | MB_OK); break; } } } } __except (EXCEPTION_EXECUTE_HANDLER) { MessageBox (NULL, "An exception occured while trying to upload the crash dump. Please post it manually on the EGL forums.", "Upload Error", MB_ICONEXCLAMATION | MB_OK); } }
int EXPORT FS_FOpenFile (const char *filename, FILE **file, handlestyle_t openHandle, qboolean *closeHandle) { fscache_t *cache; searchpath_t *search; pack_t *pak; filelink_t *link; char netpath[MAX_OSPATH]; char lowered[MAX_QPATH]; // check for links firstal if (!fs_noextern->intvalue) { for (link = fs_links ; link ; link=link->next) { if (!strncmp (filename, link->from, link->fromlength)) { Com_sprintf (netpath, sizeof(netpath), "%s%s",link->to, filename+link->fromlength); if (openHandle != HANDLE_NONE) { *file = fopen (netpath, "rb"); if (*file) { Com_DPrintf ("link file: %s\n",netpath); *closeHandle = true; return FS_filelength (*file); } return -1; } else { return Sys_FileLength (netpath); } } } } #ifdef BTREE_SEARCH cache = rbfind (filename, rb); if (cache) { cache = *(fscache_t **)cache; if (cache->filepath[0] == 0) { *file = NULL; return -1; } #ifdef _DEBUG Com_DPrintf ("File '%s' found in cache: %s\n", filename, cache->filepath); #endif if (openHandle != HANDLE_NONE) { if (cache->pak) { if (openHandle == HANDLE_DUPE) { *file = fopen (cache->pak->filename, "rb"); if (!*file) { Com_Printf ("WARNING: Cached pak '%s' failed to open! Did you delete it?\n", LOG_WARNING|LOG_GENERAL, cache->pak->filename); rbdelete (filename, rb); return -1; } *closeHandle = true; } else { *file = cache->pak->h.handle; *closeHandle = false; } } else { *file = fopen (cache->filepath, "rb"); if (!*file) { Com_Printf ("WARNING: Cached file '%s' failed to open! Did you delete it?\n", LOG_WARNING|LOG_GENERAL, cache->filepath); rbdelete (filename, rb); return -1; } //Com_Error (ERR_FATAL, "Couldn't open %s (cached)", cache->filepath); *closeHandle = true; } if (cache->fileseek && fseek (*file, cache->fileseek, SEEK_SET)) Com_Error (ERR_FATAL, "Couldn't seek to offset %u in %s (cached)", cache->fileseek, cache->filepath); } return cache->filelen; } #elif HASH_CACHE hash = hashify (filename); cache = &fscache; while (cache->next) { cache = cache->next; if (cache->hash == hash && !Q_stricmp (cache->filename, filename)) { Com_Printf (" (cached) ", LOG_GENERAL); if (cache->filepath[0] == 0) { *file = NULL; return -1; } *file = fopen (cache->filepath, "rb"); if (!*file) Com_Error (ERR_FATAL, "Couldn't open %s", cache->filepath); fseek (*file, cache->fileseek, SEEK_SET); return cache->filelen; } } #elif MAGIC_BTREE { magic_t *magic; hash = hashify (filename); magic = rbfind ((void *)hash, rb); if (magic) { magic = *(magic_t **)magic; do { cache = magic->entry; if (!Q_stricmp (cache->filename, filename)) { if (cache->filepath[0] == 0) { *file = NULL; return -1; } *file = fopen (cache->filepath, "rb"); if (!*file) Com_Error (ERR_FATAL, "Couldn't open %s", cache->filepath); fseek (*file, cache->fileseek, SEEK_SET); return cache->filelen; } magic = magic->next; } while (magic); } } #endif #ifdef _DEBUG Com_DPrintf ("File '%s' not found in cache, searching fs_searchpaths\n", filename); #endif Q_strncpy (lowered, filename, sizeof(lowered)-1); fast_strlwr (lowered); for (search = fs_searchpaths ; search ; search = search->next) { // is the element a pak file? if (search->pack) { // char *lower; packfile_t *entry; //r1: optimized btree search pak = search->pack; if (pak->type == PAK_QUAKE) { entry = rbfind (lowered, pak->rb); if (entry) { entry = *(packfile_t **)entry; #ifdef _DEBUG Com_DPrintf ("File '%s' found in %s, (%s)\n", filename, pak->filename, entry->name); #endif if (openHandle != HANDLE_NONE) { //*file = fopen (pak->filename, "rb"); if (openHandle == HANDLE_DUPE) { *file = fopen (pak->filename, "rb"); *closeHandle = true; } else { *file = pak->h.handle; *closeHandle = false; } //if (!*file) // Com_Error (ERR_FATAL, "Couldn't reopen pak file %s", pak->filename); if (fseek (*file, entry->filepos, SEEK_SET)) Com_Error (ERR_FATAL, "Couldn't seek to offset %u for %s in %s", entry->filepos, entry->name, pak->filename); } if (fs_cache->intvalue & 1) { #if BTREE_SEARCH FS_AddToCache (pak->filename, entry->filelen, entry->filepos, filename, pak); #elif HASH_CACHE FS_AddToCache (hash, pak->filename, entry->filelen, entry->filepos, cache, filename); #elif MAGIC_BTREE FS_AddToCache (pak->filename, entry->filelen, entry->filepos, filename, hash); #endif } return entry->filelen; } } } else if (!fs_noextern->intvalue) { struct stat statInfo; int filelen; // check a file in the directory tree Com_sprintf (netpath, sizeof(netpath), "%s/%s",search->filename, filename); if (openHandle == HANDLE_NONE) { filelen = Sys_FileLength (netpath); if (filelen == -1) continue; if (fs_cache->intvalue & 4) FS_AddToCache (netpath, filelen, 0, filename, NULL); return filelen; } //fix for moronic implementations that allow fopen (FILE OPEN) to open a directory //(this means you linux and krew) if (stat (netpath, &statInfo)) continue; if (statInfo.st_mode & S_IFDIR) { Com_Printf ("WARNING: Tried to open a directory as a file: %s\n", LOG_WARNING, netpath); continue; } *file = fopen (netpath, "rb"); if (!*file) continue; *closeHandle = true; Com_DPrintf ("FindFile: %s\n",netpath); filelen = FS_filelength (*file); if (fs_cache->intvalue & 4) { #if BTREE_SEARCH FS_AddToCache (netpath, filelen, 0, filename, NULL); #elif HASH_CACHE FS_AddToCache (hash, netpath, filelen, 0, cache, filename); #elif MAGIC_BTREE FS_AddToCache (netpath, filelen, 0, filename, hash); #endif } return filelen; } } Com_DPrintf ("FindFile: can't find %s\n", filename); if (fs_cache->intvalue & 2) { #if BTREE_SEARCH FS_AddToCache (NULL, 0, 0, filename, NULL); #elif HASH_CACHE FS_AddToCache (hash, NULL, 0, 0, cache, filename); #elif MAGIC_BTREE FS_AddToCache (NULL, 0, 0, filename, hash); #endif } *file = NULL; return -1; }
void FS_WhereIs_f (void) { char *filename; searchpath_t *search; pack_t *pak; filelink_t *link; char netpath[MAX_OSPATH]; char lowered[MAX_QPATH]; if (Cmd_Argc() != 2) { Com_Printf ("Purpose: Find where a file is being loaded from on the filesystem.\n" "Syntax : whereis <path>\n" "Example: whereis maps/q2dm1.bsp\n", LOG_GENERAL); return; } filename = Cmd_Argv(1); // check for links firstal if (!fs_noextern->intvalue) { for (link = fs_links ; link ; link=link->next) { if (!strncmp (filename, link->from, link->fromlength)) { int len; Com_sprintf (netpath, sizeof(netpath), "%s%s",link->to, filename+link->fromlength); len = Sys_FileLength (netpath); if (len != -1) { Com_Printf ("%s is found on disk as %s (using linkpath), %d bytes.\n", LOG_GENERAL, Cmd_Argv(1), netpath, len); } else { Com_Printf ("%s is not found.\n", LOG_GENERAL, Cmd_Argv(1)); } return; } } } Q_strncpy (lowered, filename, sizeof(lowered)-1); fast_strlwr (lowered); for (search = fs_searchpaths ; search ; search = search->next) { // is the element a pak file? if (search->pack) { packfile_t *entry; //r1: optimized btree search pak = search->pack; entry = rbfind (lowered, pak->rb); if (entry) { entry = *(packfile_t **)entry; Com_Printf ("%s is found in pakfile %s as %s, %d bytes.\n", LOG_GENERAL, Cmd_Argv(1), pak->filename, entry->name, entry->filelen); return; } } else if (!fs_noextern->intvalue) { int filelen; // check a file in the directory tree Com_sprintf (netpath, sizeof(netpath), "%s/%s",search->filename, filename); filelen = Sys_FileLength (netpath); if (filelen == -1) continue; Com_Printf ("%s is found on disk as %s, %d bytes.\n", LOG_GENERAL, Cmd_Argv(1), netpath, filelen); return; } } Com_Printf ("%s is not found.\n", LOG_GENERAL, Cmd_Argv(1)); }