//加入磁盘上单个文件到包中 bool PakMaker::addDiskFile(const char* szFileInDisk, const char* szFileInPak) { assert(szFileInDisk && szFileInPak); if(!szFileInDisk || !szFileInPak || szFileInDisk[0]==0 || szFileInPak[0]==0) { setLastError(AXP_ERR_PARAM); return false; } //check is file exist if(!PathFileExists(szFileInDisk)) { setLastError(AXP_ERR_FILE_NOTFOUND); return false; } FileNode newNode; newNode.bExcute = false; newNode.strFileInPak = normaliseName(szFileInPak, false, true); newNode.strFileInDisk = normaliseName(szFileInDisk, false, true); newNode.nCRC = 0; newNode.nFileSize = 0; m_AllFiles[normaliseName(szFileInPak)] = newNode; return true; }
//得到包中某个文件的大小 unsigned int PackFile::getFileSize(const char* szFileName) const { assert(szFileName); if(!szFileName || szFileName[0]==0) { setLastError(AXP_ERR_PARAM); return 0; } //在hash表中搜索 int nHashPos = getStringPosInHashTable(normaliseName(szFileName, true, true).c_str()); if(nHashPos < 0) { setLastError(AXP_ERR_FILE_NOTFOUND, "%s", szFileName); return 0; } const FILE_HASHNODE& hashNode = m_hashTable[nHashPos]; //得到Block数据 unsigned int nBlockIndex = getHashNodeBlockIndex(hashNode); assert(nBlockIndex < (unsigned int)m_blockTable.size()); const FILE_BLOCKNODE& blockNode = m_blockTable[nBlockIndex]; return blockNode.nBlockSize; }
//将磁盘上一个目录加入到包中 bool PakMaker::addDiskFold(const char* szFoldInDisk, const char* szFoldInPak, const char* szExtFilter, bool bRecursive) { assert(szFoldInDisk ); if(!szFoldInDisk || szFoldInDisk[0]==0 ) { setLastError(AXP_ERR_PARAM); return false; } //check is path exist if(!PathFileExists(szFoldInDisk)) { setLastError(AXP_ERR_FILE_NOTFOUND, "%s", szFoldInDisk); return false; } //分割后缀过滤器 std::vector< std::string > vExtFilter; convertStringToVector(szExtFilter, vExtFilter, ";", true, true); std::set< std::string > sExtFilter; for(int i=0; i<(int)vExtFilter.size(); i++) { sExtFilter.insert(normaliseName(vExtFilter[i], true, false)); } //调用内部递归函数 return _addDiskFold(szFoldInDisk, sExtFilter, szFoldInPak, bRecursive); }
bool PackFile::removeFile(const char* szFileInPak, bool bSaveAtOnce) { assert(szFileInPak); if(!szFileInPak || szFileInPak[0]==0 || !m_hPakFile) { setLastError(AXP_ERR_PARAM); return false; } //只读模式不支持 if(m_bConst) { setLastError(AXP_ERR_FILE_ACCESS); return false; } //在hash表中搜索 int nHashPos = getStringPosInHashTable(normaliseName(szFileInPak, true, true).c_str()); if(nHashPos < 0) { setLastError(AXP_ERR_FILE_NOTFOUND, "%s", szFileInPak); return false; } FILE_HASHNODE& hashNode = m_hashTable[nHashPos]; //Block Node unsigned int nBlockPos = getHashNodeBlockIndex(hashNode); FILE_BLOCKNODE& blockNode = m_blockTable[nBlockPos]; //设定值 setBlockNodeUsed(blockNode, false); setHashNodeExists(hashNode, false); //保存空闲快 m_mapFreeBlock.insert(std::make_pair(upBoundBlockSize(blockNode.nBlockSize), nBlockPos)); m_fileHead.nData_HoleSize += upBoundBlockSize(blockNode.nBlockSize); //################################### //!! 磁盘操作开始 保存文件 //################################### if(!writeBlockNode((unsigned int)nBlockPos)) return false; if(!writeHashNode((unsigned int)nHashPos)) return false; if(!writeFileHead()) return false; if(bSaveAtOnce) { FlushFileBuffers(m_hPakFile); } //################################### //!!磁盘操作结束 //################################### return true; }
//某文件在包中是否存在 bool PackFile::isFileExists(const char* szFileName) const { assert(szFileName); if(!szFileName || szFileName[0]==0) { setLastError(AXP_ERR_PARAM); return false; } //在hash表中搜索 int nHashPos = getStringPosInHashTable(normaliseName(szFileName, true, true).c_str()); return nHashPos >= 0; }
//以文件流方式打开包中的一个文件 IStream* PackFile::openFile(const char* szFileName) { //进入关键段,考虑多线程访问 AUTO_LOCK autoLock(&m_secFile); assert(szFileName && m_hPakFile); if(!szFileName || szFileName[0]==0 || m_hPakFile==0) { setLastError(AXP_ERR_PARAM); return false; } //在hash表中搜索 int nHashPos = getStringPosInHashTable(normaliseName(szFileName, true, true).c_str()); if(nHashPos < 0) { setLastError(AXP_ERR_FILE_NOTFOUND, szFileName); return 0; } const FILE_HASHNODE& hashNode = m_hashTable[nHashPos]; //得到Block数据 unsigned int nBlockIndex = getHashNodeBlockIndex(hashNode); assert(nBlockIndex < (unsigned int)m_blockTable.size()); const FILE_BLOCKNODE& blockNode = m_blockTable[nBlockIndex]; //得到当前线程id unsigned int uCurrentThread = (unsigned int)::GetCurrentThreadId(); FileHandleMap::iterator itHandle = m_mapFileHandle.find(uCurrentThread); //是否已经有句柄 if(itHandle == m_mapFileHandle.end()) { //分配一个句柄 HANDLE hFile = ::CreateFile(m_strFileName.c_str(), GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_SEQUENTIAL_SCAN, 0); if(hFile == INVALID_HANDLE_VALUE) { setLastError(AXP_ERR_FILE_ACCESS, "File=%s, WinErr=%d", m_strFileName.c_str(), ::GetLastError()); return 0; } //加入map m_mapFileHandle.insert(std::make_pair(uCurrentThread, hFile)); itHandle = m_mapFileHandle.find(uCurrentThread); assert(itHandle != m_mapFileHandle.end()); } //Alloc a datastream DataStream* pNewStream = new DataStream(this, itHandle->second, blockNode.nDataOffset, blockNode.nBlockSize, blockNode.nBlockSize<=STREAM_PREREAD_SIZE); m_listStream.push_back(pNewStream); return (IStream*)pNewStream; }
/******************************************** 添加一个Patch升级包到升级操作中,后添加的后操作 *********************************************/ bool Updater::addPatchFile(const char* szPatchFile) { //参数检查 assert(szPatchFile); if(!szPatchFile || szPatchFile[0]==0) { setLastError(AXP_ERR_PARAM); return false; } //已经加入过 if(m_mapPatchFile.find(normaliseName(szPatchFile)) != m_mapPatchFile.end()) { //Log something... return true; } //打开zip文件,根据是否是加密后文件自动选择是否需要使用自定义文件读取接口 zzip_error_t zzipError; ZZIP_DIR* mZzipDir = zzip_dir_open_ext_io(szPatchFile, &zzipError, 0, (zzip_plugin_io_t)getEncryptZipPluginIO(szPatchFile)); if (zzipError != ZZIP_NO_ERROR) { setLastError(AXP_ERR_ZIPFILE, "ziperr=%d", zzipError); return false; } //保存zip文件句柄 m_mapPatchFile.insert(std::make_pair(normaliseName(szPatchFile), (void*)mZzipDir)); //打开(command)文件 char* pCmdFile=0; unsigned int nCmdFileSize = 0; if(!_readContentsFromZip(szPatchFile, PatchMaker::PATCH_COMMAND, 0, &pCmdFile, nCmdFileSize)) return false; //分解command文件 std::vector< std::string > vCommand; convertStringToVector(pCmdFile, vCommand, "\r\n", true, true); //空的更新包文件 if(vCommand.empty()) { //Log some thing... return true; } //逐行分析命令 for(int i=0; i<(int)vCommand.size(); i++) { const char* szCmdLine = vCommand[i].c_str(); std::vector< std::string > vFileCmd; convertStringToVector(vCommand[i].c_str(), vFileCmd, "|", true, false); if(vFileCmd.size() != 3) { //Log some thing... continue; } UPDATE_FILE fileCmd; fileCmd.process = (UPDATE_PROCESS)atoi(vFileCmd[0].c_str()); fileCmd.strPakFileName = vFileCmd[1]; fileCmd.strFileName = vFileCmd[2]; fileCmd.strSourceZip = szPatchFile; //规范后的文件名 std::string strNorFileName = normaliseName(fileCmd.strFileName); std::string strNorPakFile = normaliseName(fileCmd.strPakFileName); const char* szNorExt = ::PathFindExtension(strNorFileName.c_str()); //散文件 if(fileCmd.strPakFileName.empty()) { m_scatteredFiles[strNorFileName] = fileCmd; //如果这个文件本身是一个pak文件 if(szNorExt && strcmp(szNorExt, PackFile::PAKFILE_EXT) == 0) { //说明该包被删除或者重新添加, 重置对该pak包的所有操作 m_pakFiles.erase(strNorFileName); } } //pak包内文件 else { //获得目前该包的操作集合 UPDATE_PAKFILES::iterator itPak = m_pakFiles.find(strNorPakFile); if(itPak == m_pakFiles.end()) { //尚未对该pak进行任何操作,创建 m_pakFiles.insert(std::make_pair(strNorPakFile, UPDATE_FILES())); itPak = m_pakFiles.find(strNorPakFile); } assert(itPak != m_pakFiles.end()); //加入操作 itPak->second[strNorFileName] = fileCmd; } } return true; }
//从zip文件中读取全部文件内容到文件中或者内存中, //zip文件必须是通过addPatchFile加入的patch文件, bool Updater::_readContentsFromZip(const char* szZipFile, const char* szFileName, const char* szDiskFileName, char** ppMemoryBuf, unsigned int& nFileSize) { //参数检查 assert(szZipFile && szFileName && (szDiskFileName || ppMemoryBuf) ); if(!szZipFile || szZipFile[0]==0 || !szFileName || szFileName[0]==0 || (!szDiskFileName && !ppMemoryBuf)) { setLastError(AXP_ERR_PARAM); return false; } //搜索加入的zip文件 PATCHFILE_MAP::iterator itPatch = m_mapPatchFile.find(normaliseName(szZipFile)); //无法找到zip文件 assert(itPatch != m_mapPatchFile.end()); if(itPatch == m_mapPatchFile.end()) { setLastError(AXP_ERR_PARAM, "%s not inserted", szZipFile); return false; } //获得ZIP句柄 ZZIP_DIR* mZzipDir = (ZZIP_DIR*)(itPatch->second); assert(mZzipDir); std::string norFileName = normaliseName(szFileName, false, true); //得到文件信息 ZZIP_STAT zstat; memset(&zstat, 0, sizeof(ZZIP_STAT)); //打开文件,如果打不开,是空文件 ZZIP_FILE* zzipFile = zzip_file_open(mZzipDir, norFileName.c_str(), ZZIP_ONLYZIP | ZZIP_CASELESS); if(zzipFile) { int zip_err = zzip_dir_stat(mZzipDir, norFileName.c_str(), &zstat, ZZIP_CASEINSENSITIVE); if(zip_err!=0) { zzip_file_close(zzipFile); setLastError(AXP_ERR_ZIPFILE, "ziperr=%d", mZzipDir->errcode); return false; } } //如果需要写入文件 if(szDiskFileName) { //确认文件所在目录存在 char szDiskFilePath[MAX_PATH] = {0}; strncpy(szDiskFilePath, szDiskFileName, MAX_PATH); PathRemoveFileSpec(szDiskFilePath); if(szDiskFilePath[0]!=0 && !forceCreatePath(szDiskFilePath)) { if(zzipFile)zzip_file_close(zzipFile); setLastError(AXP_ERR_FILE_ACCESS, "Path=%s, WinErr=%d", szDiskFilePath, ::GetLastError()); return false; } //创建该文件 HANDLE hDiskFile = ::CreateFile(szDiskFileName, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, 0); if(hDiskFile == INVALID_HANDLE_VALUE) { if(zzipFile)zzip_file_close(zzipFile); setLastError(AXP_ERR_FILE_ACCESS, "File=%s, WinErr=%d", szDiskFileName, ::GetLastError()); return false; } if(zstat.st_size > 0) { const int MAX_BUFFER_SIZE = 4096; char buffer[MAX_BUFFER_SIZE] = {0}; zzip_seek(zzipFile, 0, SEEK_SET); zzip_ssize_t zReadSize = zzip_file_read(zzipFile, buffer, sizeof(buffer)); //实际已经写入的尺寸 unsigned int nActWriteSize = 0; //分块读写文件内容 do { //文件结束 if(zReadSize==0) break; //写入磁盘文件 DWORD dwBytesWrite; if(!WriteFile(hDiskFile, buffer, (DWORD)zReadSize, &dwBytesWrite, 0) || dwBytesWrite != (DWORD)zReadSize) { zzip_file_close(zzipFile); CloseHandle(hDiskFile); setLastError(AXP_ERR_FILE_WRITE, "File=%s, WinErr: %d", szDiskFileName, GetLastError()); return false; } //文件结束 if(zzip_tell(zzipFile) >=zstat.st_size) break; zReadSize = zzip_file_read(zzipFile, buffer, sizeof(buffer)); }while(true); } //关闭句柄 CloseHandle(hDiskFile); hDiskFile=0; } //如果需要读入内存 if(ppMemoryBuf) { //所需要的内存 unsigned int nMemoryNeed = (unsigned int)zstat.st_size+1; while(nMemoryNeed%4)nMemoryNeed++; //upbound 4 //扩大静态内存大小 static std::vector< unsigned char > s_autoMemory; if(s_autoMemory.size() < nMemoryNeed) { s_autoMemory.resize(nMemoryNeed); } s_autoMemory.assign(s_autoMemory.size(), 0); //读入文件内容 if(zstat.st_size > 0) { zzip_seek(zzipFile, 0, SEEK_SET); zzip_ssize_t nZipSize = zzip_file_read(zzipFile, (char*)&(s_autoMemory[0]), zstat.st_size); if(nZipSize != zstat.st_size) { zzip_file_close(zzipFile); setLastError(AXP_ERR_ZIPFILE, "ziperr=%d", mZzipDir->errcode); return false; } } //返回内容 *ppMemoryBuf = (char *)(&(s_autoMemory[0])); } //关闭句柄 if(zzipFile)zzip_file_close(zzipFile); zzipFile=0; nFileSize = (unsigned int)zstat.st_size; return true; }
//递归加入一批文件, szFoldInDisk=路径名 sFilter=过滤器, strFoldInPak=Pak中的路径 bool PakMaker::_addDiskFold(const std::string& strFoldInDisk, const std::set< std::string >& sFilter, const std::string& strFoldInPak, bool bRecursive) { WIN32_FIND_DATA theFindData; // TO Search... char szFileToSearch[MAX_PATH] = {0}; strncpy(szFileToSearch, strFoldInDisk.c_str(), MAX_PATH); PathAppend(szFileToSearch, "*.*"); // find first file HANDLE hFind = FindFirstFile(szFileToSearch, &theFindData); if(hFind == INVALID_HANDLE_VALUE) { //empty ! FindClose(hFind); return true; } BOOL bFind = FALSE; do { if(theFindData.cFileName[0] != '.') { //File in Disk CHAR szPathFileName[MAX_PATH]; strncpy(szPathFileName, strFoldInDisk.c_str(), MAX_PATH); PathAppend(szPathFileName, theFindData.cFileName); //File in Pack char szFileInPak[MAX_PATH] = {0}; strncpy(szFileInPak, strFoldInPak.c_str(), MAX_PATH); PathAppend(szFileInPak, theFindData.cFileName); //文件夹 if(theFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if(!bRecursive) goto FIND_NEXT; if(!_addDiskFold(szPathFileName, sFilter, szFileInPak, true)) return false; } //文件 else { //是否是合法后缀的文件 if(!sFilter.empty()) { const char* pExt = ::PathFindExtension(szPathFileName); if(!pExt) goto FIND_NEXT; if(sFilter.find(normaliseName(pExt+1, true, false)) == sFilter.end()) goto FIND_NEXT; } if(!addDiskFile(szPathFileName, szFileInPak)) return false; } } FIND_NEXT: // Find Next file. bFind = FindNextFile(hFind, &theFindData); }while(bFind); FindClose(hFind); return true; }
//将加入的文件和现有的pak文件作内容比较,用于程序测试 bool PakMaker::comparePakFile(const char* szPakFileName, AXP_PAKMAKER_COMPARECALLBACK callbackFunc) { assert(szPakFileName && callbackFunc); if(!szPakFileName || szPakFileName[0]==0 || callbackFunc==0) { setLastError(AXP_ERR_PARAM); return false; } //Pak文件 PackFile pakFile; if(!pakFile.openPakFile(szPakFileName, true)) return false; //保存已经检测的文件 typedef std::set< std::string > FILENAME_SET; FILENAME_SET setFileProcessed; //加入文件 FileNodeBuf::iterator it; for(it=m_AllFiles.begin(); it!=m_AllFiles.end(); it++) { FileNode& file = it->second; char szTempFileName[1024] = {0}; //打开文件 IStream* pStream = pakFile.openFile(file.strFileInPak.c_str()); //调用Callback if(!callbackFunc(file.strFileInDisk.c_str(), pStream)) { setLastError(AXP_ERR_FILE_DIFF, "%s", file.strFileInPak.c_str()); if(pStream) pStream->close(); return false; } if(pStream) { setFileProcessed.insert(normaliseName(file.strFileInPak)); //关闭stream pStream->close(); } } //是否还有尚未检测的文件存在 //打开List文件 IStream* pListStream = pakFile.openFile(PackFile::LIST_FILENAME); if(!pListStream) return false; //skip first line pListStream->skipLine(); //read second line char szTempLine[MAX_PATH*4] = {0}; int nLineSize = pListStream->readLine(szTempLine, MAX_PATH*4); int nFileCount = atoi(szTempLine); while (!pListStream->eof()) { int nLineLength = pListStream->readLine(szTempLine, MAX_PATH*4); if(0 == nLineLength) { pListStream->close(); setLastError(AXP_ERR_FILE_FORMAT, "list file second line=0"); return false; } //分析文件描述 std::vector< std::string > vStringVec; convertStringToVector(szTempLine, vStringVec, "|", true, false); if(vStringVec.size() != 3) { pListStream->close(); setLastError(AXP_ERR_FILE_FORMAT, "list file=%s", szTempLine); return false; } //获得文件信息 if(setFileProcessed.find(normaliseName(vStringVec[0])) == setFileProcessed.end()) { pListStream->close(); setLastError(AXP_ERR_FILE_DIFF, "redufile=%s", vStringVec[0].c_str()); return false; } } pListStream->close(); return true; }
//文件自检功能 bool PackFile::selfCheck(SELFCHECK_CALLBACK callBack) { if(0==m_hPakFile) { setLastError(AXP_ERR_PARAM); return false; } //编辑模式错误 if(m_fileHead.nEditFlag != 0) { setLastError(AXP_ERR_FILE_EDITMODE); return false; } //打开List文件 IStream* pListStream = openFile(LIST_FILENAME); if(!pListStream) return false; //skip first line pListStream->skipLine(); //read second line char szTempLine[MAX_PATH*4] = {0}; int nLineSize = pListStream->readLine(szTempLine, MAX_PATH*4); int nFileCount = atoi(szTempLine); //记录已经检查过的HashNode索引 std::set< unsigned int > setHashNode; //记录已经检查过的BlockNode索引 std::set< unsigned int > setBlockNode; //逐行读文件 int nFileListSize = 0; while (!pListStream->eof()) { int nLineLength = pListStream->readLine(szTempLine, MAX_PATH*4); if(0 == nLineLength) { pListStream->close(); setLastError(AXP_ERR_FILE_FORMAT, "list file second line=0"); return false; } //分析文件描述 std::vector< std::string > vStringVec; convertStringToVector(szTempLine, vStringVec, "|", true, false); if(vStringVec.size() != 3) { pListStream->close(); setLastError(AXP_ERR_FILE_FORMAT, "list file=%s", szTempLine); return false; } //获得文件信息 std::string& strFileName = vStringVec[0]; unsigned int nFileSize, nFileCRC; sscanf(vStringVec[1].c_str(), "%08X", &(nFileSize)); sscanf(vStringVec[2].c_str(), "%08X", &(nFileCRC)); //读入文件 IStream* pFileStream = openFile(strFileName.c_str()); //打开文件 if(!pFileStream) { pListStream->close(); return false; } unsigned int nStreamSize = pFileStream->size(); if(nStreamSize != nFileSize) { pFileStream->close(); pListStream->close(); setLastError(AXP_ERR_FILE_FORMAT, "file=%s, sizedif(%d!=%d)", strFileName.c_str(), nStreamSize, nFileSize); return false; } char* pTempBuf = new char[nStreamSize]; if(nStreamSize != pFileStream->read(pTempBuf, nStreamSize)) { pFileStream->close(); pListStream->close(); setLastError(AXP_ERR_FILE_READ, "file=%s", strFileName.c_str()); } pFileStream->close(); pFileStream=0; //计算文件实际crc unsigned int nStreamCRC; crcMemory32(pTempBuf, nStreamSize, nStreamCRC); delete[] pTempBuf; pTempBuf=0; if(nStreamCRC != nFileCRC) { // pFileStream->close(); pListStream->close(); setLastError(AXP_ERR_FILE_FORMAT, "file=%s, crcdif(%d!=%d)", strFileName.c_str(), nStreamCRC, nFileCRC); return false; } //保存分析过的文件Hash和Block数据 //得到Hash数据 int nHashPos = getStringPosInHashTable(normaliseName(strFileName).c_str()); setHashNode.insert(nHashPos); //得到Block数据 unsigned int nBlockIndex = getHashNodeBlockIndex(m_hashTable[nHashPos]); setBlockNode.insert(nBlockIndex); nFileListSize++; }; pListStream->close(); pListStream=0; //文件个数检查 if(nFileListSize != nFileCount) { setLastError(AXP_ERR_FILE_FORMAT, "file countdif(%d!=%d)", nFileListSize, nFileCount); return false; } //得到(list)的Hash数据 int nListFileHashPos = getStringPosInHashTable(LIST_FILENAME); //得到(list)的Block数据 unsigned int nListFileBlockIndex = getHashNodeBlockIndex(m_hashTable[nListFileHashPos]); //检查是否有未引用的Hash数据 for(int i=0; i<HASH_TABLE_SIZE; i++) { const FILE_HASHNODE& hashNode = m_hashTable[i]; if(!getHashNodeExists(hashNode)) continue; if(setHashNode.find(i) != setHashNode.end()) continue; if(i==nListFileHashPos) continue; //未引用的Hash数据 setLastError(AXP_ERR_FILE_FORMAT, "unref hashnode(%d)", i); return false; } //检查是否有未引用的BlockNode数据 for(int i=0; i<(int)m_blockTable.size(); i++) { const FILE_BLOCKNODE& blockNode = m_blockTable[i]; if(!getBlockNodeUsed(blockNode)) continue; if(setBlockNode.find(i) != setBlockNode.end()) continue; if(i==nListFileBlockIndex) continue; //未引用的Hash数据 setLastError(AXP_ERR_FILE_FORMAT, "unref blocknode(%d)", i); return false; } return true; }
//加入/更新一个磁盘文件到包中 bool PackFile::insertContents(const char* szContents, unsigned int nContentsLen, const char* szFileInPak, AXP_CONTENTS sourceType, bool bSaveAtOnce) { assert(szContents && szFileInPak); if(!szFileInPak || szFileInPak[0]==0 || !m_hPakFile) { setLastError(AXP_ERR_PARAM); return false; } if(sourceType==AC_DISKFILE && (!szContents || szContents[0]==0)) { setLastError(AXP_ERR_PARAM); return false; } //只读模式不支持 if(m_bConst) { setLastError(AXP_ERR_FILE_ACCESS); return false; } //察看文件是否存在 if(sourceType==AC_DISKFILE && !PathFileExists(szContents)) { setLastError(AXP_ERR_FILE_NOTFOUND, "%s", szContents); return false; } //在Hash表中分配位置 int nHashPos = allocStringPosInHashTable(normaliseName(szFileInPak, true, true).c_str()); if(nHashPos < 0) { setLastError(AXP_ERR_HASHFULL); return false; } FILE_HASHNODE& hashNode = m_hashTable[nHashPos]; //获得文件大小 unsigned int nFileSize = sourceType==AC_DISKFILE ? getDiskFileSize(szContents) : nContentsLen; //如果同名文件已经存在 if(getHashNodeExists(hashNode)) { //Block unsigned int nBlockIndex = getHashNodeBlockIndex(hashNode); FILE_BLOCKNODE& blockNode = m_blockTable[nBlockIndex]; //如果尺寸接近 if(upBoundBlockSize(blockNode.nBlockSize) == upBoundBlockSize(nFileSize)) { //直接替换文件内容 //################################### //!! 磁盘操作开始 保存文件 //################################### if(sourceType==AC_DISKFILE) { if(!writeDiskFile(blockNode.nDataOffset, upBoundBlockSize(blockNode.nBlockSize), szContents)) return false; } else { if(!writeMemory(blockNode.nDataOffset, upBoundBlockSize(blockNode.nBlockSize), szContents, nContentsLen)) return false; } if(blockNode.nBlockSize != nFileSize) { //文件尺寸有差异,保存BlockNode数据 blockNode.nBlockSize = nFileSize; if(!writeBlockNode(nBlockIndex)) return false; } // 确认写入磁盘 if(bSaveAtOnce) { FlushFileBuffers(m_hPakFile); } //################################### //!!磁盘操作结束 //################################### } //尺寸发生变化,需要删除旧空间,分配新空间 else { //旧块内容设置为不再使用 setBlockNodeUsed(blockNode, false); //将旧块加入空闲块列表 m_mapFreeBlock.insert(std::make_pair(upBoundBlockSize(blockNode.nBlockSize), nBlockIndex)); m_fileHead.nData_HoleSize += upBoundBlockSize(blockNode.nBlockSize); //重新尝试分配空间 std::pair< int, int > nNewBlockPair = allocFreeBlock(nFileSize); int nNewBlockIndex = nNewBlockPair.first; if(nNewBlockIndex < 0) { setLastError(AXP_ERR_BLOCKFULL); //Block表满了 return false; } //设置Hash表数据 setHashNodeExists(hashNode, true); setHashNodeBlockIndex(hashNode, nNewBlockIndex); //################################### //!! 磁盘操作开始 保存文件 //################################### if(nNewBlockPair.second> 0) { //分割大空间时产生的副空间 if(!writeBlockNode((unsigned int)(nNewBlockPair.second))) return false; } //保存文件内容 if(sourceType==AC_DISKFILE) { if(!writeDiskFile(m_blockTable[nNewBlockIndex].nDataOffset, upBoundBlockSize(m_blockTable[nNewBlockIndex].nBlockSize), szContents)) return false; } else { if(!writeMemory(m_blockTable[nNewBlockIndex].nDataOffset, upBoundBlockSize(m_blockTable[nNewBlockIndex].nBlockSize), szContents, nContentsLen)) return false; } //文件所在的新的BlockNode if(!writeBlockNode((unsigned int)nNewBlockIndex)) return false; //原文件所在的BlockNode if(nBlockIndex != nNewBlockIndex) { if(!writeBlockNode((unsigned int)nBlockIndex)) return false; } //文件的HashNode if(!writeHashNode((unsigned int)nHashPos)) return false; //文件头 if(!writeFileHead()) return false; // 确认写入磁盘 if(bSaveAtOnce) { FlushFileBuffers(m_hPakFile); } //################################### //!!磁盘操作结束 //################################### } } else { //获取一块合适空间 std::pair< int, int > nNewBlockPair = allocFreeBlock(nFileSize); int nBlockIndex = nNewBlockPair.first; if(nBlockIndex < 0) { setLastError(AXP_ERR_BLOCKFULL); //Block表满了 return false; } //设置Hash表数据 setHashNodeBlockIndex(hashNode, nBlockIndex); setHashNodeExists(hashNode, true); //################################### //!! 磁盘操作开始 保存文件 //################################### if(nNewBlockPair.second> 0) { //分割大空间时产生的副空间 if(!writeBlockNode((unsigned int)(nNewBlockPair.second))) return false; } if(sourceType==AC_DISKFILE) { if(!writeDiskFile(m_blockTable[nBlockIndex].nDataOffset, upBoundBlockSize(m_blockTable[nBlockIndex].nBlockSize), szContents)) return false; } else { if(!writeMemory(m_blockTable[nBlockIndex].nDataOffset, upBoundBlockSize(m_blockTable[nBlockIndex].nBlockSize), szContents, nContentsLen)) return false; } if(!writeBlockNode((unsigned int)nBlockIndex)) return false; if(!writeHashNode((unsigned int)nHashPos)) return false; if(!writeFileHead()) return false; // 确认写入磁盘 if(bSaveAtOnce) { FlushFileBuffers(m_hPakFile); } //################################### //!!磁盘操作结束 //################################### } return true; }