bool C4Network2Res::SetLoad(const C4Network2ResCore &nCore) // by main thread
{
	Clear();
	CStdLock FileLock(&FileCSec);
	// must be loadable
	if (!nCore.isLoadable()) return false;
	// save core, set chunks
	Core = nCore;
	Chunks.SetIncomplete(Core.getChunkCnt());
	// create temporary file
	if (!pParent->FindTempResFileName(Core.getFileName(), szFile))
		return false;
#ifdef C4NET2RES_DEBUG_LOG
	// log
	Application.InteractiveThread.ThreadLogS("Network: Resource: loading %d:%s to file %s", Core.getID(), Core.getFileName(), szFile);
#endif
	// set standalone (result is going to be binary-compatible)
	SCopy(szFile, szStandalone, sizeof(szStandalone) - 1);
	// set flags
	fDirty = false;
	fTempFile = true;
	fStandaloneFailed = false;
	fRemoved = false;
	iLastReqTime = time(NULL);
	fLoading = true;
	// No discovery yet
	iDiscoverStartTime = 0;
	return true;
}
bool C4Network2Res::FinishDerive() // by main thread
{
	// All changes have been made. Register this resource with a new ID.

	// security
	if (!isAnonymous()) return false;

	CStdLock FileLock(&FileCSec);
	// Save back data
	int32_t iDerID = Core.getDerID();
	char szName[_MAX_PATH+1]; SCopy(Core.getFileName(), szName, _MAX_PATH);
	char szFileC[_MAX_PATH+1]; SCopy(szFile, szFileC, _MAX_PATH);
	// Set by file
	if (!SetByFile(szFileC, fTempFile, getType(), pParent->nextResID(), szName))
		return false;
	// create standalone
	if (!GetStandalone(NULL, 0, true))
		return false;
	// Set ID
	Core.SetDerived(iDerID);
	// announce derive
	pParent->getIOClass()->BroadcastMsg(MkC4NetIOPacket(PID_NetResDerive, Core));
	// derivation is dirty bussines
	fDirty = true;
	// ok
	return true;
}
Beispiel #3
0
int mtFile::runRead( mtThreadWork::DataUser* pkDataUser )
{
	char*	pcFile	= getFileName(pkDataUser->pcAccount);

	if (NULL == pcFile)
	{
		return	mtProtocol::E_RESULT_FALT_FILE_INVALIDE_PATH;
	}

	if (0 == FileOpen(&pkDataUser->hFile, pcFile))
	{
		return	mtProtocol::E_RESULT_FALT_FILE_NOT_EXIST;
	}

	pkDataUser->iFileOffset			= getFileOffset(pkDataUser->pcAccount);
	pkDataUser->ulTransferBytes		= getDataFileBytes();

	pkDataUser->kOverlapped.Offset	= pkDataUser->iFileOffset;
	pkDataUser->eOverlappedType		= mtThread::E_OLT_LOCKFILEEx;
	pkDataUser->iFileRunType		= E_FILE_RUN_READ_FILE;
	
	if (0 == FileLock(pkDataUser->hFile, pkDataUser->ulTransferBytes, &pkDataUser->kOverlapped))
	{
		FileClose(&pkDataUser->hFile);
		return	mtProtocol::E_RESULT_FALT_FILE_LOCK;
	}

	return	mtProtocol::E_RESULT_SUCCESS;
}
bool C4Network2Res::SetByFile(const char *strFilePath, bool fTemp, C4Network2ResType eType, int32_t iResID, const char *szResName, bool fSilent)
{
	CStdLock FileLock(&FileCSec);
	// default resource name: relative path
	if (!szResName) szResName = Config.AtRelativePath(strFilePath);
	SCopy(strFilePath, szFile, sizeof(szFile)-1);
	// group?
	C4Group Grp;
	if (Reloc.Open(Grp, strFilePath))
		return SetByGroup(&Grp, fTemp, eType, iResID, szResName, fSilent);
	// so it needs to be a file
	StdStrBuf szFullFile;
	if (!Reloc.LocateItem(szFile, szFullFile))
		{ if (!fSilent) LogF("SetByFile: file %s not found!", strFilePath); return false; }
	// calc checksum
	uint32_t iCRC32;
	if (!GetFileCRC(szFullFile.getData(), &iCRC32)) return false;
#ifdef C4NET2RES_DEBUG_LOG
	// log
	LogSilentF("Network: Resource: complete %d:%s is file %s (%s)", iResID, szResName, szFile, fTemp ? "temp" : "static");
#endif
	// set core
	Core.Set(eType, iResID, Config.AtRelativePath(szFullFile.getData()), iCRC32);
	// set own data
	fDirty = true;
	fTempFile = fTemp;
	fStandaloneFailed = false;
	fRemoved = false;
	iLastReqTime = time(NULL);
	fLoading = false;
	// ok
	return true;
}
bool C4Network2Res::SetByGroup(C4Group *pGrp, bool fTemp, C4Network2ResType eType, int32_t iResID, const char *szResName, bool fSilent) // by main thread
{
	Clear();
	CStdLock FileLock(&FileCSec);
	// default resource name: relative path
	StdStrBuf sResName;
	if (szResName)
		sResName = szResName;
	else
	{
		StdStrBuf sFullName = pGrp->GetFullName();
		sResName.Copy(Config.AtRelativePath(sFullName.getData()));
	}
	SCopy(pGrp->GetFullName().getData(), szFile, sizeof(szFile)-1);
	// set core
	Core.Set(eType, iResID, sResName.getData(), pGrp->EntryCRC32());
#ifdef C4NET2RES_DEBUG_LOG
	// log
	LogSilentF("Network: Resource: complete %d:%s is file %s (%s)", iResID, sResName.getData(), szFile, fTemp ? "temp" : "static");
#endif
	// set data
	fDirty = true;
	fTempFile = fTemp;
	fStandaloneFailed = false;
	fRemoved = false;
	iLastReqTime = time(NULL);
	fLoading = false;
	// ok
	return true;
}
bool C4Network2Res::OptimizeStandalone(bool fSilent)
{
	CStdLock FileLock(&FileCSec);
	// for now: player files only
	if (Core.getType() == NRT_Player)
	{
		// log - this may take a few seconds
		if (!fSilent) LogF(LoadResStr("IDS_PRC_NETPREPARING"), GetFilename(szFile));
		// copy to temp file, if needed
		if (!fTempFile && SEqual(szFile, szStandalone))
		{
			char szNewStandalone[_MAX_PATH + 1];
			if (!pParent->FindTempResFileName(szStandalone, szNewStandalone))
				{ if (!fSilent) Log("OptimizeStandalone: could not find free name for temporary file!"); return false; }
			if (!C4Group_CopyItem(szStandalone, szNewStandalone))
				{ if (!fSilent) Log("OptimizeStandalone: could not copy to temporary file!"); return false; } /* TODO: Test failure */
			SCopy(szNewStandalone, szStandalone, sizeof(szStandalone) - 1);
		}
		// open as group
		C4Group Grp;
		if (!Grp.Open(szStandalone))
			{ if (!fSilent) Log("OptimizeStandalone: could not open player file!"); return false; }
		// remove bigicon, if the file size is too large
		size_t iBigIconSize=0;
		if (Grp.FindEntry(C4CFN_BigIcon, NULL, &iBigIconSize))
			if (iBigIconSize > C4NetResMaxBigicon*1024)
				Grp.Delete(C4CFN_BigIcon);
		Grp.Close();
	}
	return true;
}
void C4Network2Res::OnChunk(const C4Network2ResChunk &rChunk)
{
	if (!fLoading) return;
	// correct resource?
	if (rChunk.getResID() != getResID()) return;
	// add resource data
	CStdLock FileLock(&FileCSec);
	bool fSuccess = rChunk.AddTo(this, pParent->getIOClass());
#ifdef C4NET2RES_DEBUG_LOG
	// log
	Application.InteractiveThread.ThreadLogS("Network: Res: %s chunk %d to resource %s (%s)%s", fSuccess ? "added" : "could not add", rChunk.getChunkNr(), Core.getFileName(), szFile, fSuccess ? "" : "!");
#endif
	if (fSuccess)
	{
		// status changed
		fDirty = true;
		// remove load waits
		for (C4Network2ResLoad *pLoad = pLoads, *pNext; pLoad; pLoad = pNext)
		{
			pNext = pLoad->Next();
			if (static_cast<uint32_t>(pLoad->getChunk()) == rChunk.getChunkNr())
				RemoveLoad(pLoad);
		}
	}
	// complete?
	if (Chunks.isComplete())
		EndLoad();
	// check: start new loads?
	else
		StartNewLoads();
}
int32_t C4Network2Res::OpenFileWrite()
{
	CStdLock FileLock(&FileCSec);
	// FIXME: Use standard OC file access api here
#ifdef _WIN32
	return _wopen(GetWideChar(szStandalone), _O_BINARY | O_CREAT | O_WRONLY, S_IREAD | S_IWRITE);
#else
	return open(szStandalone, _O_BINARY | O_CLOEXEC | O_CREAT | O_WRONLY, S_IREAD | S_IWRITE);
#endif
}
C4Network2Res::Ref C4Network2Res::Derive()
{
	// Called before the file is changed. Rescues all files and creates a
	// new resource for the file. This resource is flagged as "anonymous", as it
	// has no official core (no res ID, to be exact).
	// The resource gets its final core when FinishDerive() is called.

	// For security: This doesn't make much sense if the resource is currently being
	// loaded. So better assume the caller doesn't know what he's doing and check.
	if (isLoading()) return NULL;

	CStdLock FileLock(&FileCSec);
	// Save back original file name
	char szOrgFile[_MAX_PATH+1];
	SCopy(szFile, szOrgFile, _MAX_PATH);
	bool fOrgTempFile = fTempFile;

	// Create a copy of the file, if neccessary
	if (!*szStandalone || SEqual(szStandalone, szFile))
	{
		if (!pParent->FindTempResFileName(szOrgFile, szFile))
			{ Log("Derive: could not find free name for temporary file!"); return NULL; }
		if (!C4Group_CopyItem(szOrgFile, szFile))
			{ Log("Derive: could not copy to temporary file!"); return NULL; }
		// set standalone
		if (*szStandalone)
			SCopy(szFile, szStandalone, _MAX_PATH);
		fTempFile = true;
	}
	else
	{
		// Standlone exists: Just set szFile to point on the standlone. It's
		// assumed that the original file isn't of intrest after this point anyway.
		SCopy(szStandalone, szFile, _MAX_PATH);
		fTempFile = true;
	}

	Application.InteractiveThread.ThreadLogS("Network: Resource: deriving from %d:%s, original at %s", getResID(), Core.getFileName(), szFile);

	// (note: should remove temp file if something fails after this point)

	// create new resource
	C4Network2Res::Ref pDRes = new C4Network2Res(pParent);
	if (!pDRes) return NULL;

	// initialize
	if (!pDRes->SetDerived(Core.getFileName(), szOrgFile, fOrgTempFile, getType(), getResID()))
		return NULL;

	// add to list
	pParent->Add(pDRes);

	// return new resource
	return pDRes;
}
int32_t C4Network2Res::OpenFileRead()
{
	CStdLock FileLock(&FileCSec);
	if (!GetStandalone(NULL, 0, false, false, true)) return -1;
	// FIXME: Use standard OC file access api here
#ifdef _WIN32
	return _wopen(GetWideChar(szStandalone), _O_BINARY | O_RDONLY);
#else
	return open(szStandalone, _O_BINARY | O_CLOEXEC | O_RDONLY);
#endif
}
bool C4Network2Res::IsBinaryCompatible()
{
	// returns wether the standalone of this resource is binary compatible
	// to the official version (means: matches the file checksum)

	CStdLock FileLock(&FileCSec);
	// standalone set? ok then (see GetStandalone)
	if (szStandalone[0]) return true;
	// is a directory?
	if (DirectoryExists(szFile))
		// forget it - if the file is packed now, the creation time and author
		// won't match.
		return false;
	// try to create the standalone
	return GetStandalone(NULL, 0, false, false, true);
}
Beispiel #12
0
int mtFile::completeWriteCreate( mtThreadWork::DataUser* pkDataUser )
{
	pkDataUser->iFileOffset			= getFileOffset(pkDataUser->pcAccount);
	pkDataUser->ulTransferBytes		= getDataFileBytes();
	pkDataUser->iFileRunType		= E_FILE_RUN_WRITE_FILE;

	pkDataUser->kOverlapped.Offset	= pkDataUser->iFileOffset;
	pkDataUser->eOverlappedType		= mtThread::E_OLT_LOCKFILEEx;
	if (0 == FileLock(pkDataUser->hFile, pkDataUser->ulTransferBytes, &pkDataUser->kOverlapped, LOCKFILE_EXCLUSIVE_LOCK))
	{
		FileClose(&pkDataUser->hFile);
		return	mtProtocol::E_RESULT_FALT_FILE_LOCK;
	}

	return	mtProtocol::E_RESULT_SUCCESS;

}
bool C4Network2Res::SendChunk(uint32_t iChunk, int32_t iToClient)
{
	assert(pParent && pParent->getIOClass());
	if (!szStandalone[0] || iChunk >= Core.getChunkCnt()) return false;
	// find connection for given client (one of the rare uses of the data connection)
	C4Network2IOConnection *pConn = pParent->getIOClass()->GetDataConnection(iToClient);
	if (!pConn) return false;
	// save last request time
	iLastReqTime = time(NULL);
	// create packet
	CStdLock FileLock(&FileCSec);
	C4Network2ResChunk ResChunk;
	ResChunk.Set(this, iChunk);
	// send
	bool fSuccess = pConn->Send(MkC4NetIOPacket(PID_NetResData, ResChunk));
	pConn->DelRef();
	return fSuccess;
}
void C4Network2Res::Clear()
{
	CStdLock FileLock(&FileCSec);
	// delete files
	if (fTempFile)
		if (FileExists(szFile))
			if (!EraseFile(szFile))
				LogSilentF("Network: Could not delete temporary resource file (%s)", strerror(errno));
	if (szStandalone[0] && !SEqual(szFile, szStandalone))
		if (FileExists(szStandalone))
			if (!EraseFile(szStandalone))
				LogSilentF("Network: Could not delete temporary resource file (%s)", strerror(errno));
	szFile[0] = szStandalone[0] = '\0';
	fDirty = false;
	fTempFile = false;
	Core.Clear();
	Chunks.Clear();
	fRemoved = false;
	ClearLoad();
}
bool C4Network2Res::SetDerived(const char *strName, const char *strFilePath, bool fTemp, C4Network2ResType eType, int32_t iDResID)
{
	Clear();
	CStdLock FileLock(&FileCSec);
	// set core
	Core.Set(eType, C4NetResIDAnonymous, strName, ~0);
	Core.SetDerived(iDResID);
	// save file path
	SCopy(strFilePath, szFile, _MAX_PATH);
	*szStandalone = '\0';
	// set flags
	fDirty = false;
	fTempFile = fTemp;
	fStandaloneFailed = false;
	fRemoved = false;
	iLastReqTime = time(NULL);
	fLoading = false;
	// Do not set any chunk data - anonymous resources are very likely to change.
	// Wait for FinishDerived()-call.
	return true;
}
Beispiel #16
0
int mtFile::runWrite( mtThreadWork::DataUser* pkDataUser )
{
	char*	pcFile	= getFileName(pkDataUser->pcAccount);

	if (NULL == pcFile)
	{
		return	mtProtocol::E_RESULT_FALT_FILE_INVALIDE_PATH;
	}

	if (FileOpen(&pkDataUser->hFile, pcFile))
	{
 		pkDataUser->iFileOffset			= getFileOffset(pkDataUser->pcAccount);
 		pkDataUser->ulTransferBytes		= getDataFileBytes();
		pkDataUser->iFileRunType		= E_FILE_RUN_WRITE_FILE;
	}
	else 
	{
		/// ╢╢╫╗нд╪Ч
		if (FileCreate(&pkDataUser->hFile, pcFile, getFolderBytes()))
		{
			pkDataUser->iFileOffset			= 0;
			pkDataUser->ulTransferBytes		= getCreateFileBytes();
			pkDataUser->iFileRunType		= E_FILE_RUN_WRITE_FILE_CREATE;
		}
		else
		{
			return	mtProtocol::E_RESULT_FALT_FILE_CREATE_FUNCTION;
		}
	}

	pkDataUser->kOverlapped.Offset	= pkDataUser->iFileOffset;
	pkDataUser->eOverlappedType		= mtThread::E_OLT_LOCKFILEEx;
	if (0 == FileLock(pkDataUser->hFile, pkDataUser->ulTransferBytes, &pkDataUser->kOverlapped, LOCKFILE_EXCLUSIVE_LOCK))
	{
		FileClose(&pkDataUser->hFile);
		return	mtProtocol::E_RESULT_FALT_FILE_LOCK;
	}

	return	mtProtocol::E_RESULT_SUCCESS;
}
bool C4Network2Res::GetStandalone(char *pTo, int32_t iMaxL, bool fSetOfficial, bool fAllowUnloadable, bool fSilent)
{
	// already set?
	if (szStandalone[0])
	{
		if (pTo) SCopy(szStandalone, pTo, iMaxL);
		return true;
	}
	// already tried and failed? No point in retrying
	if (fStandaloneFailed) return false;
	// not loadable? Wo won't be able to check the standalone as the core will lack the needed information.
	// the standalone won't be interesting in this case, anyway.
	if (!fSetOfficial && !Core.isLoadable()) return false;
	// set flag, so failure below will let future calls fail
	fStandaloneFailed = true;
	// lock file
	CStdLock FileLock(&FileCSec);

	// directory?
	SCopy(szFile, szStandalone, sizeof(szStandalone)-1);
	if (DirectoryExists(szFile))
	{
		// size check for the directory, if allowed
		if (fAllowUnloadable)
		{
			uint32_t iDirSize;
			if (!DirSizeHelper::GetDirSize(szFile, &iDirSize, Config.Network.MaxLoadFileSize))
				{ if (!fSilent) LogF("Network: could not get directory size of %s!", szFile); szStandalone[0] = '\0'; return false; }
			if (iDirSize > uint32_t(Config.Network.MaxLoadFileSize))
				{ if (!fSilent) LogSilentF("Network: %s over size limit, will be marked unloadable!", szFile); szStandalone[0] = '\0'; return false; }
		}
		// log - this may take a few seconds
		if (!fSilent) LogF(LoadResStr("IDS_PRC_NETPACKING"), GetFilename(szFile));
		// pack inplace?
		if (!fTempFile)
		{
			if (!pParent->FindTempResFileName(szFile, szStandalone))
				{ if (!fSilent) Log("GetStandalone: could not find free name for temporary file!"); szStandalone[0] = '\0'; return false; }
			if (!C4Group_PackDirectoryTo(szFile, szStandalone))
				{ if (!fSilent) Log("GetStandalone: could not pack directory!"); szStandalone[0] = '\0'; return false; }
		}
		else if (!C4Group_PackDirectory(szStandalone))
			{ if (!fSilent) Log("GetStandalone: could not pack directory!"); if (!SEqual(szFile, szStandalone)) EraseDirectory(szStandalone); szStandalone[0] = '\0'; return false; }
		// make sure directory is packed
		if (DirectoryExists(szStandalone))
			{ if (!fSilent) Log("GetStandalone: directory hasn't been packed!"); if (!SEqual(szFile, szStandalone)) EraseDirectory(szStandalone); szStandalone[0] = '\0'; return false; }
		// fallthru
	}

	// doesn't exist physically?
	if (!FileExists(szStandalone))
	{
		// try C4Group (might be packed)
		if (!pParent->FindTempResFileName(szFile, szStandalone))
			{ if (!fSilent) Log("GetStandalone: could not find free name for temporary file!"); szStandalone[0] = '\0'; return false; }
		if (!C4Group_CopyItem(szFile, szStandalone))
			{ if (!fSilent) Log("GetStandalone: could not copy to temporary file!"); szStandalone[0] = '\0'; return false; }
	}

	// remains missing? give up.
	if (!FileExists(szStandalone))
		{ if (!fSilent) Log("GetStandalone: file not found!"); szStandalone[0] = '\0'; return false; }

	// do optimizations (delete unneeded entries)
	if (!OptimizeStandalone(fSilent))
		{ if (!SEqual(szFile, szStandalone)) EraseItem(szStandalone); szStandalone[0] = '\0'; return false; }

	// get file size
	size_t iSize = FileSize(szStandalone);
	// size limit
	if (fAllowUnloadable)
		if (iSize > uint32_t(Config.Network.MaxLoadFileSize))
			{ if (!fSilent) LogSilentF("Network: %s over size limit, will be marked unloadable!", szFile); szStandalone[0] = '\0'; return false; }
	// check
	if (!fSetOfficial && iSize != Core.getFileSize())
	{
		// remove file
		if (!SEqual(szFile, szStandalone)) EraseItem(szStandalone); szStandalone[0] = '\0';
		// sorry, this version isn't good enough :(
		return false;
	}

	// calc checksum
	uint32_t iCRC32;
	if (!GetFileCRC(szStandalone, &iCRC32))
		{ if (!fSilent) Log("GetStandalone: could not calculate checksum!"); return false; }
	// set / check
	if (!fSetOfficial && iCRC32 != Core.getFileCRC())
	{
		// remove file, return
		if (!SEqual(szFile, szStandalone)) EraseItem(szStandalone); szStandalone[0] = '\0';
		return false;
	}

	// we didn't fail
	fStandaloneFailed = false;
	// mark resource as loadable and safe file information
	Core.SetLoadable(iSize, iCRC32);
	// set up chunk data
	Chunks.SetComplete(Core.getChunkCnt());
	// ok
	return true;
}