// The following routine sets up a map of account numbers to file sizes with the largest file size corresponding to each identified account number
// On entry accountIds must be exatly the same size as fdc
// The result is generated by comparing the file sizes of all files in fdc that share the same values in the corrsponding entries in accountIds
static void calculateAccountMaxFileSizes(const CFileDescriptionContainer& fdc, const std::vector<uint32>& accountIds, std::map<uint32,uint32>& result)
{
	// initialise the result container before we begin...
	result.clear();

	// sanity checks...
	nlassert(fdc.size()==accountIds.size());
	
	// generate the account numbers corresponding to the file names in the fdc
	// also initialise bestDate map entries for all of the account numbers found
	for (uint32 i=fdc.size();i--;)
	{
		uint32 accountId= accountIds[i];
		result[accountId]=0;
	}
	
	// setup the largest file sizes for each account
	for (uint32 i=fdc.size();i--;)
	{
		uint32 accountId= accountIds[i];
		uint32& bestSize= result[accountId];
		uint32 size= fdc[i].FileSize;
		bestSize= std::max(size,bestSize);
	}
}
// The following routine resizes the result vector to match the size of the fdc container and fills it with values corresponding to the files in the fdc
// the accountId is set to 0 for files that do not contain a recognisable account id.
// The account id is assumed to be the first integer found between 2 '_' characters. eg for file 'account_123_4_pdr.bin' the value would be 123
static void calculateAccountIdsForFiles(const CFileDescriptionContainer& fdc, std::vector<uint32>& result)
{
	// initialise the accountIds container for the array of account ids corresponding to entries in fdc
	result.clear();
	result.resize(fdc.size(),0);

	// generate the account numbers corresponding to the file names in the fdc
	// also initialise bestDate map entries for all of the account numbers found
	for (uint32 i=fdc.size();i--;)
	{
		result[i]= getAccountIdFromFileName(NLMISC::CFile::getFilename(fdc[i].FileName));
	}
}
Пример #3
0
void CServerPatchApplier::patchFromLive(uint32 liveVersion, uint32 installRequestVersion)
{
	// scan the temp directory to build a file list and delete all of the files we find there
	CFileDescriptionContainer tempFiles;
	tempFiles.addFileSpec(_Directories.installDirectoryName()+"*",true);
	for (uint32 i=0;i<tempFiles.size();++i)
	{
		NLMISC::CFile::deleteFile(tempFiles[i].FileName);
	}

	// make sure the temp directory is now empty
	tempFiles.clear();
	tempFiles.addFileSpec(_Directories.installDirectoryName()+"*",true);
	DROP_IF(!tempFiles.empty(),"Failed to delete all of the contents of the directory: "+_Directories.installDirectoryName(),return);

	// choose a patch direction depending on the whether we're patching forwards or backwards
	if (liveVersion<installRequestVersion)
	{
		_patchUpFromLive(liveVersion,installRequestVersion);
	}
	else if (liveVersion>installRequestVersion)
	{
		_patchDownFromLive(liveVersion,installRequestVersion);
	}
}
// The following routine resizes the result vector to the same size as the file description container and fills it with
// time stamps corresponding to the most recently used file belonging to the same account as the corresponding entry in the fdc
// eg: if fdc[4].FileName=="account_123_1_pdr.bin" then result[4] will contain the time stamp of the most recently accessed file for account 123
static void calculateTimestampByAccount(const CFileDescriptionContainer& fdc, std::vector<uint32>& result)
{
	// initialise the result vector before we begin...
	result.clear();
	result.resize(fdc.size(),0);

	// generate the array of account ids corresponding to entries in fdc
	std::vector<uint32> accountIds;
	calculateAccountIdsForFiles(fdc,accountIds);
	
	//generate the map of account number to most recent time stamp for files belonging to the account
	std::map<uint32,uint32> bestTimes;
	calculateMaxAccountTimeStamps(fdc,accountIds,bestTimes);
	
	// fill in the result vector...
	for (uint32 i=fdc.size();i--;)
	{
		uint32 accountId= accountIds[i];
		result[i]= bestTimes[accountId];
	}
}
Пример #5
0
bool CCharacterScanJob::deleteFilesInOutputDirectory() const
{
	CFileDescriptionContainer fdc;
	fdc.addFileSpec(STAT_GLOBALS::getOutputFilePath(getOutputPath()+"*"));
	for (uint32 i=0;i<fdc.size();++i)
	{
		NLMISC::CFile::deleteFile(fdc[i].FileName);
	}

	// make sure the directory is now empty
	fdc.clear();
	fdc.addFileSpec(STAT_GLOBALS::getOutputFilePath(getOutputPath()+"*"));
	return fdc.empty();
}
Пример #6
0
void CServerPatchApplier::_patchUpFromLive(uint32 liveVersion, uint32 installRequestVersion)
{
	nlinfo("SPA %s: Patching up from version %d to %d",_Directories.getDomainName().c_str(),liveVersion,installRequestVersion);

	// scan the patch directory to build a file list
	CFileDescriptionContainer patchFiles;
	patchFiles.addFileSpec(_Directories.patchDirectoryName()+"*",true);

	// build map of dest file name to patch vector, filtering out patches later than 'version'
	typedef std::map<NLMISC::CSString,std::vector<uint32> > TFilePatches;
	typedef std::set<NLMISC::CSString> TRequiredPaths;
	TFilePatches filePatches;
	TRequiredPaths requiredPaths;
	for (uint32 i=0;i<patchFiles.size();++i)
	{
		CSString name= patchFiles[i].FileName.leftCrop(_Directories.patchDirectoryName().size()).splitTo(".patch_");
		uint32 patchNum= patchFiles[i].FileName.splitFrom(".patch_").atoi();
		DROP_IF(patchNum==0,"Failed to identify patch number in file name: "+patchFiles[i].FileName,continue);
		if (patchNum<=installRequestVersion)
		{
			filePatches[name].push_back(patchNum);
		}
		requiredPaths.insert(NLMISC::CFile::getPath(name));
	}

	// create any paths that we're going to need
	for (TRequiredPaths::iterator it= requiredPaths.begin(); it!=requiredPaths.end(); ++it)
	{
		NLMISC::CFile::createDirectoryTree(_Directories.installDirectoryName()+*it);
	}

	// run through the file list copying or patching as required
	TFilePatches::iterator it= filePatches.begin();
	TFilePatches::iterator itEnd= filePatches.end();
	for (;it!=itEnd;++it)
	{
		// skip files that don't exist in the requested patch version
		if (it->second.empty())
		{
			continue;
		}

		// sort the patch vector
		std::sort(it->second.begin(),it->second.end());

		// identify the first patch beyond the patch in this file beyond 'liveVersion'
		uint32 patchIdx=0;
		while (patchIdx< it->second.size() && it->second[patchIdx]<=liveVersion)
		{
			++patchIdx;
		}

		// if there is no change between the live file and install file then copy the live file
		if (patchIdx==it->second.size())
		{
			nlinfo("COPY: %s from %s",(_Directories.installDirectoryName()+it->first).c_str(),(_Directories.liveDirectoryName()+it->first).c_str());
			NLMISC::CFile::copyFile((_Directories.installDirectoryName()+it->first).c_str(),(_Directories.liveDirectoryName()+it->first).c_str());
			untarIfNeeded(_Directories.installDirectoryName()+it->first);
			continue;
		}

		// setup a little boolean to flag errors
		bool ok= true;

		// try to apply the first patch in the patch vector by using the file in the current version directory
		if (patchIdx!=0)
		{
			ok=	applyPatch( NLMISC::toString("%s%s.patch_%d",_Directories.patchDirectoryName().c_str(),it->first.c_str(),it->second[patchIdx]),
							_Directories.liveDirectoryName()+it->first,
							_Directories.installDirectoryName()+it->first+((patchIdx&1)==0?".tmp0":".tmp1"));
			DROP_IF(!ok,"Failed to apply patch ... rewinding and trying to buid file from 0 for file: "+it->first,patchIdx=0);
		}

		// if the patch index is 0 then start by applying the first patch...
		if (patchIdx ==0)
		{
			ok= applyFirstPatch(NLMISC::toString("%s%s.patch_%d",_Directories.patchDirectoryName().c_str(),it->first.c_str(),it->second[0]),
							_Directories.installDirectoryName()+it->first+".tmp0");
			DROP_IF(!ok,"Error: skipping file because failed to apply fist patch: "+it->first,continue);
		}

		// run through the remaining patches aplying them iteratively...
		while(++patchIdx < it->second.size())
		{
			ok=	applyPatch( NLMISC::toString("%s%s.patch_%d",_Directories.patchDirectoryName().c_str(),it->first.c_str(),it->second[patchIdx]),
							_Directories.installDirectoryName()+it->first+((patchIdx&1)==0?".tmp1":".tmp0"),
							_Directories.installDirectoryName()+it->first+((patchIdx&1)==0?".tmp0":".tmp1"));
			DROP_IF(!ok,NLMISC::toString("Failed to apply patch %d ... for file: ",it->second[patchIdx])+it->first,break);
		}

		// if we bombed out during patch apply then skip this file and continue
		if (!ok)
			continue;

		// we're done so rename the last file generated and delete it's twin 
		finalisePatch(_Directories.installDirectoryName(), it->first, it->second.size());
	}
	virtual void callback(const CFileDescriptionContainer& fileList)
	{
		// store the list of oupost file
		for (uint i=0; i<fileList.size(); ++i)
			OutpostFiles.push_back(fileList[i].FileName);
	}