// 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)); } }
bool CCharacterScanJob::getFileList(CFileDescriptionContainer& result) const { bool isOK=true; result.clear(); for (uint32 i=0;i<_FileListBuilders.size();++i) { isOK &= _FileListBuilders[i]->execute(result); } return isOK; }
bool CCharScanScriptFile::applyToJob(CCharacterScanJob& job) { bool result=true; // apply the file names CFileDescriptionContainer fdc; for (uint32 i=0;i<_InputFiles.size();++i) { fdc.addFileSpec(_InputFiles[i]); } job.addFiles(fdc); // apply the filters for (uint32 i=0;i<_Filters.size();++i) { ICharFilter* filter= CCharFilterFactory::getInstance()->build(_Filters[i]); if (filter==NULL) { nlwarning("Failed to build filter description from line: %s",_Filters[i].c_str()); result=false; continue; } job.addFilter(filter); } // apply the info extractors for (uint32 i=0;i<_InfoExtractors.size();++i) { ICharInfoExtractor* infoExtractor= CCharInfoExtractorFactory::getInstance()->build(_InfoExtractors[i]); if (infoExtractor==NULL) { nlwarning("Failed to build filter description from line: %s",_InfoExtractors[i].c_str()); result=false; continue; } job.addInfoExtractor(infoExtractor); } // apply the output path job.setOutputPath(_OutputPath); return result; }
static void addToFdc(const NLMISC::CSString& filespec, CFileDescriptionContainer& result) { if (filespec.left(1)=="@") { readFileList(filespec.leftCrop(1),result); } else { result.addFileSpec(filespec); } }
// 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]; } }
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); } }
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(); }
static void readFileList(const NLMISC::CSString& fileListName, CFileDescriptionContainer& result) { // read the file list from disk (the result will be empty if the file list didn't exist) NLMISC::CSString fileList; fileList.readFromFile(fileListName); // split the file list text block into lines NLMISC::CVectorSString files; fileList.splitLines(files); // iterate over the lies in the input file for(uint32 i=0;i<files.size();++i) { // clean lines up, stripping spaces and quotes NLMISC::CSString theFile= files[i].strip().unquoteIfQuoted(); // skip empty lines and comments if (theFile.empty() || theFile.left(1)=="#") continue; // add the file name to the result result.addFile(theFile); } }
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()); }
void CCharacterScanJob::listFilesOnly(CFileDescriptionContainer& result) { result.clear(); _FileList= &result; _ListFilesOnly=true; }
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); }