bool CrashHandlerImpl::addAttachedFile(const fs::path & file) {
	
	if(file.is_relative()) {
		fs::path absolute = fs::current_path() / file;
		if(absolute.is_relative()) {
			return false;
		}
		return addAttachedFile(absolute);
	}
	
	Autolock autoLock(&m_Lock);

	if(m_pCrashInfo->nbFilesAttached == CrashInfo::MaxNbFiles) {
		LogError << "Too much files already attached to the crash report (" << m_pCrashInfo->nbFilesAttached << ").";
		return false;
	}

	if(file.string().size() >= CrashInfo::MaxFilenameLen) {
		LogError << "File name is too long.";
		return false;
	}

	for(u32 i = 0; i < m_pCrashInfo->nbFilesAttached; i++) {
		if(strcmp(m_pCrashInfo->attachedFiles[i], file.string().c_str()) == 0) {
			LogWarning << "File \"" << file << "\" is already attached.";
			return false;
		}
	}
	
	util::storeStringTerminated(m_pCrashInfo->attachedFiles[m_pCrashInfo->nbFilesAttached], file.string());
	m_pCrashInfo->nbFilesAttached++;

	return true;
}
void CrashHandlerImpl::processCrash() {
	
	if(m_pCrashInfo) {
		m_pCrashInfo->processorProcessId = platform::getProcessId();
	}
	
	// Launch crash reporter GUI
	platform::process_handle reporter = 0;
	{
		fs::path executable = platform::getHelperExecutable("arxcrashreporter");
		std::string arg = "--crashinfo=" + m_SharedMemoryName;
		const char * args[] = { executable.string().c_str(), arg.c_str(), NULL };
		reporter = platform::runAsync(args);
	}
	
	if(m_pCrashInfo) {
		
		std::time_t timestamp = std::time(NULL);
		{
			fs::path crashReportDir = util::loadString(m_pCrashInfo->crashReportFolder);
			std::tm * time = std::gmtime(&timestamp);
			for(int count = 0; ; count++) {
				std::ostringstream oss;
				oss << (time->tm_year + 1900) << '-'
				    << std::setfill('0') << std::setw(2) << (time->tm_mon + 1) << '-'
				    << std::setfill('0') << std::setw(2) << time->tm_mday << '-'
				    << std::setfill('0') << std::setw(2) << time->tm_hour << '-'
				    << std::setfill('0') << std::setw(2) << time->tm_min << '-'
				    << std::setfill('0') << std::setw(2) << time->tm_sec << '-'
				    << std::setfill('0') << std::setw(2) << count;
				m_crashReportDir = crashReportDir / oss.str();
				if(!fs::exists(m_crashReportDir)) {
					break;
				}
			}
			fs::create_directories(m_crashReportDir);
			util::storeStringTerminated(m_pCrashInfo->crashReportFolder, m_crashReportDir.string());
		}
		
		processCrashInfo();
		processCrashSignal();
		processCrashRegisters();
		processCrashTrace();
		processCrashDump();
		
		{
			size_t nfiles = std::min(size_t(m_pCrashInfo->nbFilesAttached),
			                         size_t(CrashInfo::MaxNbFiles));
			for(size_t i = 0; i < nfiles; i++) {
				fs::path file = util::loadString(m_pCrashInfo->attachedFiles[i]);
				if(file.empty() || !fs::is_regular_file(file)) {
					continue;
				}
				fs::path copy = m_crashReportDir / file.filename();
				if(copy == file || !fs::copy_file(file, copy)) {
					continue;
				}
				util::storeStringTerminated(m_pCrashInfo->attachedFiles[i], copy.string());
			}
		}
		
		// Terminate the crashed process - we collected all the information we could
		if(m_pCrashInfo->processId != m_pCrashInfo->processorProcessId) {
			m_pCrashInfo->exitLock.post();
			platform::killProcess(m_pCrashInfo->processId);
		}
		
		// Write the crash description to a file
		fs::path crashinfo = m_crashReportDir / "crash.txt";
		fs::ofstream ofs(crashinfo, fs::fstream::out | fs::fstream::trunc);
		if(ofs.is_open()) {
			
			ofs.write(m_pCrashInfo->description, m_textLength);
			
			ofs << '\n';
			
			ofs << "\nProcess information:\n";
			ofs << "- path: " << util::loadString(m_pCrashInfo->executablePath) << '\n';
			ofs << "- version: " << util::loadString(m_pCrashInfo->executableVersion) << '\n';
			if(m_pCrashInfo->memoryUsage != 0) {
				ofs << "- memory usage: " << m_pCrashInfo->memoryUsage << " bytes" << '\n';
			}
			const char * arch = platform::getArchitectureName(m_pCrashInfo->architecture);
			ofs << "- architecture: " << arch << '\n';
			if(m_pCrashInfo->runningTime > 0.0) {
				ofs << "- runnig time: " << m_pCrashInfo->runningTime << " seconds" << '\n';
			}
			std::tm * time = std::gmtime(&timestamp);
			ofs << "- crash time: " << (time->tm_year + 1900) << '-'
			    << std::setfill('0') << std::setw(2) << (time->tm_mon + 1) << '-'
			    << std::setfill('0') << std::setw(2) << time->tm_mday << ' '
			    << std::setfill('0') << std::setw(2) << time->tm_hour << ':'
			    << std::setfill('0') << std::setw(2) << time->tm_min << ':'
			    << std::setfill('0') << std::setw(2) << time->tm_sec << '\n';
			
			ofs << "\nSystem information:\n";
			std::string os = platform::getOSName();
			if(!os.empty()) {
				ofs << "- operating system: " << os << '\n';
			}
			std::string osarch = platform::getOSArchitecture();
			if(!osarch.empty()) {
				ofs << "- architecture: " << osarch << '\n';
			}
			std::string distro = platform::getOSDistribution();
			if(!distro.empty()) {
				ofs << "- distribution: " << distro << '\n';
			}
			std::string libc = platform::getCLibraryVersion();
			if(!libc.empty()) {
				ofs << "- libc: " << libc << '\n';
			}
			std::string threading = platform::getThreadLibraryVersion();
			if(!threading.empty()) {
				ofs << "- threading: " << threading << '\n';
			}
			std::string cpu = platform::getCPUName();
			if(!cpu.empty()) {
				ofs << "- cpu: " << cpu << '\n';
			}
			platform::MemoryInfo memory = platform::getMemoryInfo();
			if(memory.total) {
				ofs << "- total physical memory: " << memory.total << " bytes" << '\n';
			}
			if(memory.available) {
				ofs << "- free physical memory: " << memory.available << " bytes" << '\n';
			}
			
			ofs << "\nVariables:\n";
			size_t nbVariables = std::min(size_t(m_pCrashInfo->nbVariables),
			                              size_t(CrashInfo::MaxNbVariables));
			for(size_t i = 0; i < nbVariables; ++i) {
				ofs << "- " << util::loadString(m_pCrashInfo->variables[i].name) << ": "
				    << util::loadString(m_pCrashInfo->variables[i].value) << '\n';
			}
			
			ofs << "\nAdditional files:\n";
			size_t nfiles = std::min(size_t(m_pCrashInfo->nbFilesAttached),
			                         size_t(CrashInfo::MaxNbFiles));
			for(size_t i = 0; i < nfiles; i++) {
				fs::path file = util::loadString(m_pCrashInfo->attachedFiles[i]);
				if(fs::exists(file) && fs::file_size(file) != 0) {
					ofs << "- " << file.filename() << '\n';
				}
			}
			
			addAttachedFile(crashinfo);
		}
		
	}
	
	// Wait for the crash reporter to start
	while(reporter) {
		if(platform::getProcessExitCode(reporter, false) != platform::StillRunning) {
			reporter = 0;
			break;
		}
		boost::posix_time::ptime timeout
		 = boost::posix_time::microsec_clock::universal_time()
		 + boost::posix_time::milliseconds(100);
		if(m_pCrashInfo && m_pCrashInfo->reporterStarted.timed_wait(timeout)) {
			break;
		}
	}
	
	// Tell the crash reporter we are done
	if(m_pCrashInfo) {
		m_pCrashInfo->processorDone.post();
	}
	
	// If the crash reporter started successfully, we are done here
	if(reporter) {
		return;
	}
	
	// The crash reporter is not available or failed to start - provide our own dialog
	{
		std::ostringstream oss;
		oss << arx_name + " crashed!\n\n";
		if(m_pCrashInfo) {
			oss << "Please install arxcrashreporter or manually report the crash to "
			    << url::bug_report << "\n\n";
			oss << "Include the files contained in the following directory in your report:\n";
			oss << " " << m_crashReportDir;
		} else {
			oss << "Additionally, we encountered an unexpected error while collecting"
			       " crash information!\n\n";
		}
		std::cout << "\n\n" << oss.str() << '\n';
		if(m_pCrashInfo) {
			oss << "\n\nClick OK to open that directory now.";
		}
		platform::showErrorDialog(oss.str(), "Fatal Error - " + arx_name);
		if(m_pCrashInfo) {
			platform::launchDefaultProgram(m_crashReportDir.string());
		}
	}
	
}