// sync_client.cpp // sync_client // Created by housisong on 2019-09-18. /* The MIT License (MIT) Copyright (c) 2019-2023 HouSisong Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "sync_client_private.h" #include "../../file_for_patch.h" #include "match_in_old.h" #include "sync_diff_data.h" #include namespace sync_private{ #define check(v,errorCode) \ do{ if (!(v)) { if (result==kSyncClient_ok) result=errorCode; \ if (!_inClear) goto clear; } }while(0) bool _open_continue_out(hpatch_BOOL& isOutContinue,const char* outFile,hpatch_TFileStreamOutput* out_stream, hpatch_TStreamInput* continue_stream,hpatch_StreamPos_t maxContinueLength){ memset(continue_stream,0,sizeof(*continue_stream)); if ((isOutContinue)&&(hpatch_isPathExist(outFile))){ if (!hpatch_TFileStreamOutput_reopen(out_stream,outFile,(hpatch_StreamPos_t)(-1))) return false; hpatch_TFileStreamOutput_setRandomOut(out_stream,hpatch_TRUE); //can rewrite if (out_stream->out_length>maxContinueLength) return false; if (out_stream->out_length>0){ assert(out_stream->base.read_writed!=0); *continue_stream=*(hpatch_TStreamInput*)(void*)(&out_stream->base); continue_stream->streamSize=out_stream->out_length; out_stream->out_length=0; }else{ isOutContinue=hpatch_FALSE; } }else{ isOutContinue=hpatch_FALSE; if (!hpatch_TFileStreamOutput_open(out_stream,outFile,(hpatch_StreamPos_t)(-1))) return false; } return true; } static size_t _indexOfCompressedSyncBlock(const TNewDataSyncInfo* self,const hpatch_StreamPos_t* newBlockDataInOldPoss,uint32_t indexBegin){ size_t blockCount=(size_t)TNewDataSyncInfo_blockCount(self); if (self->savedSizes){ for (size_t i=indexBegin;isavedSizes[i])&&(newBlockDataInOldPoss[i]==kBlockType_needSync)) return i; } } return ~(size_t)0; } struct _TWriteDatas { const hpatch_TStreamOutput* out_newStream; const hpatch_TStreamInput* newDataContinue; const hpatch_TStreamOutput* out_diffStream; hpatch_StreamPos_t outDiffDataPos; const hpatch_TStreamInput* oldStream; const TNewDataSyncInfo* newSyncInfo; const TNeedSyncInfos* needSyncInfo; const hpatch_StreamPos_t* newBlockDataInOldPoss; TSyncDiffData* continueDiffData; uint32_t needSyncBlockCount; bool isLocalPatch; hpatch_TChecksum* strongChecksumPlugin; hpatch_checksumHandle checkChecksum; hsync_TDictDecompress* decompressPlugin; IReadSyncDataListener* syncDataListener; }; #define _checkSumNewDataBuf() { \ if (newDataSizebegin(checksumSync); \ strongChecksumPlugin->append(checksumSync,dataBuf,dataBuf+kSyncBlockSize); \ strongChecksumPlugin->end(checksumSync,checksumSync_buf+newSyncInfo->savedStrongChecksumByteSize, \ checksumSync_buf+newSyncInfo->savedStrongChecksumByteSize \ +newSyncInfo->kStrongChecksumByteSize);\ toPartChecksum(checksumSync_buf,newSyncInfo->savedStrongChecksumBits, \ checksumSync_buf+newSyncInfo->savedStrongChecksumByteSize, \ newSyncInfo->kStrongChecksumByteSize); \ check(0==memcmp(checksumSync_buf, \ newSyncInfo->partChecksums+i*newSyncInfo->savedStrongChecksumByteSize, \ newSyncInfo->savedStrongChecksumByteSize),kSyncClient_checksumSyncDataError); \ } static TSyncClient_resultType writeToNewOrDiff(_TWriteDatas& wd,bool& isNeed_readSyncDataEnd) { const TNewDataSyncInfo* newSyncInfo=wd.newSyncInfo; IReadSyncDataListener* syncDataListener=wd.syncDataListener; hpatch_TChecksum* strongChecksumPlugin=wd.strongChecksumPlugin; TSyncClient_resultType result=kSyncClient_ok; int _inClear=0; const uint32_t kBlockCount=(uint32_t)TNewDataSyncInfo_blockCount(newSyncInfo); const uint32_t kSyncBlockSize=newSyncInfo->kSyncBlockSize; TByte* _memBuf=0; TByte* checksumSync_buf=0; hsync_dictDecompressHandle decompressHandle=0; hpatch_checksumHandle checksumSync=0; hpatch_StreamPos_t posInNewSyncData=newSyncInfo->newSyncDataOffsert; hpatch_StreamPos_t posInNeedSyncData=0; hpatch_StreamPos_t outNewDataPos=0; const hpatch_StreamPos_t oldDataSize=wd.oldStream->streamSize; bool isNeedSync; bool isOnDiffContinue =(wd.continueDiffData!=0); bool isOnNewDataContinue =(wd.newDataContinue!=0); size_t lastCompressedIndex=_indexOfCompressedSyncBlock(newSyncInfo,wd.newBlockDataInOldPoss,0); if (lastCompressedIndex>=kBlockCount) wd.decompressPlugin=0; const size_t _memSize=(size_t)kSyncBlockSize*(wd.decompressPlugin?3:1) +newSyncInfo->kStrongChecksumByteSize +checkChecksumBufByteSize(newSyncInfo->kStrongChecksumByteSize); _memBuf=(TByte*)malloc(_memSize); check(_memBuf!=0,kSyncClient_memError); checksumSync_buf=_memBuf+(size_t)kSyncBlockSize*(wd.decompressPlugin?3:1); {//checksum newSyncData checksumSync=strongChecksumPlugin->open(strongChecksumPlugin); check(checksumSync!=0,kSyncClient_strongChecksumOpenError); } if (wd.decompressPlugin){ decompressHandle=wd.decompressPlugin->dictDecompressOpen(wd.decompressPlugin,kBlockCount,kSyncBlockSize, newSyncInfo->decompressInfo,newSyncInfo->decompressInfo+newSyncInfo->decompressInfoSize); check(decompressHandle,kSyncClient_decompressOpenError); } for (uint32_t syncSize=0,newDataSize=0,i=0; iwd.newDataContinue->streamSize)) isOnNewDataContinue=hpatch_FALSE; if (isOnNewDataContinue){ //copy from newDataContinue check(wd.newDataContinue->read(wd.newDataContinue,outNewDataPos,dataBuf,dataBuf+newDataSize), kSyncClient_newFileReopenReadError); }else if (isNeedSync){ //download or read from diff data TByte* buf=isCompressedBlock?(dataBuf+kSyncBlockSize):dataBuf; /*if ((wd.out_newStream)||(wd.out_diffStream))*/{//download data if (isOnDiffContinue){ //read from local data if (!wd.continueDiffData->readSyncData(wd.continueDiffData,i,posInNewSyncData, posInNeedSyncData,buf,syncSize)) isOnDiffContinue=false; // swap to download } if (!isOnDiffContinue){ //downloaded data or read from diff data if (!isNeed_readSyncDataEnd){ isNeed_readSyncDataEnd=true; if (syncDataListener->readSyncDataBegin) check(syncDataListener->readSyncDataBegin(syncDataListener,wd.needSyncInfo, i,posInNewSyncData,posInNeedSyncData), kSyncClient_readSyncDataBeginError); } check(syncDataListener->readSyncData(syncDataListener,i,posInNewSyncData, posInNeedSyncData,buf,syncSize), kSyncClient_readSyncDataError); } if (wd.out_diffStream){ //out diff if (!isOnDiffContinue){ //save downloaded data check(wd.out_diffStream->write(wd.out_diffStream,wd.outDiffDataPos, buf,buf+syncSize),kSyncClient_saveDiffError); } wd.outDiffDataPos+=syncSize; } } if (/*wd.out_newStream&&*/isCompressedBlock){// need deccompress assert(lastCompressedIndex==i); check(wd.decompressPlugin->dictDecompress(decompressHandle,i,buf,buf+syncSize, dataBuf,dataBuf+newDataSize), kSyncClient_decompressError); lastCompressedIndex=_indexOfCompressedSyncBlock(newSyncInfo,wd.newBlockDataInOldPoss,i+1); } }else{//copy from old assert(curSyncPosoldDataSize) readSize=(uint32_t)(oldDataSize-curSyncPos); check(wd.oldStream->read(wd.oldStream,curSyncPos,dataBuf,dataBuf+readSize), kSyncClient_readOldDataError); if (readSizedictUncompress(decompressHandle,i,lastCompressedIndex,dataBuf,dataBuf+newDataSize); /*if (wd.out_newStream)*/{//write bool isNeedChecksumAppend=isNeedSync|wd.isLocalPatch|(wd.continueDiffData!=0); if (isNeedChecksumAppend|isOnNewDataContinue) _checkSumNewDataBuf(); if (isNeedChecksumAppend) checkChecksumAppendData(newSyncInfo->savedNewDataCheckChecksum,i, strongChecksumPlugin,wd.checkChecksum, checksumSync_buf+wd.newSyncInfo->savedStrongChecksumByteSize, newSyncInfo->kStrongChecksumByteSize); if ((!isOnNewDataContinue)&&wd.out_newStream){ check(wd.out_newStream->write(wd.out_newStream,outNewDataPos,dataBuf, dataBuf+newDataSize), kSyncClient_writeNewDataError); } } } check(outNewDataPos==newSyncInfo->newDataSize,kSyncClient_newDataSizeError); if (newSyncInfo->newSyncDataSize==0) assert(posInNewSyncData<=newSyncInfo->newDataSize); else assert(posInNewSyncData<=newSyncInfo->newSyncDataSize);//checked in readSavedSizesTo() clear: _inClear=1; if (decompressHandle) wd.decompressPlugin->dictDecompressClose(wd.decompressPlugin,decompressHandle); if (checksumSync) strongChecksumPlugin->close(strongChecksumPlugin,checksumSync); if (_memBuf) free(_memBuf); return result; } struct TNeedSyncInfosImport:public TNeedSyncInfos{ const hpatch_StreamPos_t* newBlockDataInOldPoss; const TNewDataSyncInfo* newSyncInfo; // opened .hsyni }; static void _getBlockInfoByIndex(const TNeedSyncInfos* needSyncInfos,uint32_t blockIndex, hpatch_BOOL* out_isNeedSync,uint32_t* out_syncSize){ const TNeedSyncInfosImport* self=(const TNeedSyncInfosImport*)needSyncInfos->import; assert(blockIndexblockCount); *out_isNeedSync=(self->newBlockDataInOldPoss[blockIndex]==kBlockType_needSync); *out_syncSize=TNewDataSyncInfo_syncBlockSize(self->newSyncInfo,blockIndex); } static void getNeedSyncInfo(const hpatch_StreamPos_t* newBlockDataInOldPoss, const TNewDataSyncInfo* newSyncInfo,TNeedSyncInfosImport* out_nsi){ const uint32_t kBlockCount=(uint32_t)TNewDataSyncInfo_blockCount(newSyncInfo); out_nsi->newBlockDataInOldPoss=newBlockDataInOldPoss; out_nsi->newSyncInfo=newSyncInfo; out_nsi->import=out_nsi; //self out_nsi->newDataSize=newSyncInfo->newDataSize; out_nsi->newSyncDataSize=newSyncInfo->newSyncDataSize; out_nsi->newSyncInfoSize=newSyncInfo->newSyncInfoSize; out_nsi->kSyncBlockSize=newSyncInfo->kSyncBlockSize; out_nsi->blockCount=kBlockCount; out_nsi->blockCount=kBlockCount; out_nsi->getBlockInfoByIndex=_getBlockInfoByIndex; out_nsi->needSyncBlockCount=0; out_nsi->needSyncSumSize=0; for (uint32_t i=0; ineedSyncBlockCount; out_nsi->needSyncSumSize+=TNewDataSyncInfo_syncBlockSize(newSyncInfo,i); } } } TSyncClient_resultType _sync_patch(ISyncInfoListener* listener,IReadSyncDataListener* syncDataListener,TSyncDiffData* diffData, const hpatch_TStreamInput* oldStream,const TNewDataSyncInfo* newSyncInfo, const hpatch_TStreamOutput* out_newStream,const hpatch_TStreamInput* newDataContinue, const hpatch_TStreamOutput* out_diffStream,TSyncDiffType diffType, const hpatch_TStreamInput* diffContinue,int threadNum){ assert(listener!=0); hsync_TDictDecompress* decompressPlugin=0; hpatch_TChecksum* strongChecksumPlugin=0; hpatch_checksumHandle checkChecksum=0; const uint32_t kBlockCount=(uint32_t)TNewDataSyncInfo_blockCount(newSyncInfo); TNeedSyncInfosImport needSyncInfo; memset(&needSyncInfo,0,sizeof(needSyncInfo)); hpatch_StreamPos_t* newBlockDataInOldPoss=0; hpatch_StreamPos_t outDiffDataPos=0; TSyncClient_resultType result=kSyncClient_ok; int _inClear=0; TSyncDiffData continueDiffData; memset(&continueDiffData,0,sizeof(continueDiffData)); const bool isNeedOut=(out_newStream!=0)||((out_diffStream!=0)&&(diffType!=kSyncDiff_info)); bool isLoadedOldPoss=false; bool isReMatchInOld=false; bool isNeed_readSyncDataEnd=false; //decompressPlugin if (newSyncInfo->compressType){ if ((newSyncInfo->_decompressPlugin!=0) &&(newSyncInfo->_decompressPlugin->is_can_open(newSyncInfo->compressType))){ decompressPlugin=newSyncInfo->_decompressPlugin; }else{ decompressPlugin=listener->findDecompressPlugin(listener,newSyncInfo->compressType,newSyncInfo->dictSize); check(decompressPlugin!=0,kSyncClient_noDecompressPluginError); } } //strongChecksumPlugin if ((newSyncInfo->_strongChecksumPlugin!=0) &&(newSyncInfo->kStrongChecksumByteSize==newSyncInfo->_strongChecksumPlugin->checksumByteSize()) &&(0==strcmp(newSyncInfo->strongChecksumType,newSyncInfo->_strongChecksumPlugin->checksumType()))){ strongChecksumPlugin=newSyncInfo->_strongChecksumPlugin; }else{ strongChecksumPlugin=listener->findChecksumPlugin(listener,newSyncInfo->strongChecksumType); check(strongChecksumPlugin!=0,kSyncClient_noStrongChecksumPluginError); check(strongChecksumPlugin->checksumByteSize()==newSyncInfo->kStrongChecksumByteSize, kSyncClient_strongChecksumByteSizeError); } checkChecksumInit(newSyncInfo->savedNewDataCheckChecksum,newSyncInfo->kStrongChecksumByteSize); checkChecksum=strongChecksumPlugin->open(strongChecksumPlugin); check(checkChecksum!=0,kSyncClient_strongChecksumOpenError); //matched in oldData newBlockDataInOldPoss=(hpatch_StreamPos_t*)malloc(kBlockCount*(size_t)sizeof(hpatch_StreamPos_t)); check(newBlockDataInOldPoss!=0,kSyncClient_memError); for (uint32_t i=0; ikSyncBlockSize, oldStream->streamSize,newSyncInfo->savedNewDataCheckChecksum, newSyncInfo->kStrongChecksumByteSize), kSyncClient_loadDiffError); isLoadedOldPoss=(diffData->diffType!=kSyncDiff_data); if (!isLoadedOldPoss) isReMatchInOld=true; syncDataListener=diffData; }else{ assert(syncDataListener!=0); if (diffContinue!=0){ // try continue local diff assert(out_diffStream!=0); if (_TSyncDiffData_load(&continueDiffData,diffContinue)){ if (_TSyncDiffData_readOldPoss(&continueDiffData,newBlockDataInOldPoss,kBlockCount, newSyncInfo->kSyncBlockSize,oldStream->streamSize, newSyncInfo->savedNewDataCheckChecksum,newSyncInfo->kStrongChecksumByteSize)){ isLoadedOldPoss=(continueDiffData.diffType!=kSyncDiff_data);//ok diffContinue if (!isLoadedOldPoss) isReMatchInOld=true; }else diffContinue=0; // not use diffContinue }else diffContinue=0; // not use diffContinue } } if (!isLoadedOldPoss){ try{ matchNewDataInOld(newBlockDataInOldPoss,newSyncInfo,oldStream,strongChecksumPlugin, ((diffType==kSyncDiff_data)||isReMatchInOld)?1:threadNum); if (isReMatchInOld){ checkChecksumInit(newSyncInfo->savedNewDataCheckChecksum, newSyncInfo->kStrongChecksumByteSize); } }catch(const std::exception& e){ fprintf(stderr,"matchNewDataInOld() run an error: %s",e.what()); result=kSyncClient_matchNewDataInOldError; } } check(result==kSyncClient_ok,result); if ((out_diffStream!=0)){ if (diffContinue==0){ check(_saveSyncDiffData(newBlockDataInOldPoss,kBlockCount,newSyncInfo->kSyncBlockSize,oldStream->streamSize, newSyncInfo->savedNewDataCheckChecksum,newSyncInfo->kStrongChecksumByteSize, out_diffStream,diffType,&outDiffDataPos),kSyncClient_saveDiffError); }else{ // continue local diff outDiffDataPos=continueDiffData.diffDataPos0; } } getNeedSyncInfo(newBlockDataInOldPoss,newSyncInfo,&needSyncInfo); if (diffContinue) needSyncInfo.localDiffDataSize=(diffContinue->streamSize-continueDiffData.diffDataPos0); if (listener->onNeedSyncInfo) listener->onNeedSyncInfo(listener,&needSyncInfo); if (syncDataListener->onNeedSyncInfo) syncDataListener->onNeedSyncInfo(syncDataListener,&needSyncInfo); if (isNeedOut) check(syncDataListener->readSyncData!=0,kSyncClient_noReadSyncDataError); if (isNeedOut){ _TWriteDatas writeDatas; writeDatas.out_newStream=out_newStream; writeDatas.newDataContinue=newDataContinue; writeDatas.out_diffStream=(diffType==kSyncDiff_info)?0:out_diffStream; writeDatas.outDiffDataPos=outDiffDataPos; writeDatas.oldStream=oldStream; writeDatas.newSyncInfo=newSyncInfo; writeDatas.needSyncInfo=&needSyncInfo; writeDatas.newBlockDataInOldPoss=newBlockDataInOldPoss; writeDatas.needSyncBlockCount=needSyncInfo.needSyncBlockCount; writeDatas.decompressPlugin=decompressPlugin; writeDatas.strongChecksumPlugin=strongChecksumPlugin; writeDatas.checkChecksum=checkChecksum; writeDatas.syncDataListener=syncDataListener; writeDatas.continueDiffData=diffContinue?&continueDiffData:0; writeDatas.isLocalPatch=(diffData!=0); result=writeToNewOrDiff(writeDatas,isNeed_readSyncDataEnd); if (/*(*/result==kSyncClient_ok/*)&&out_newStream*/){ checkChecksumEndTo(newSyncInfo->savedNewDataCheckChecksum+newSyncInfo->kStrongChecksumByteSize, newSyncInfo->savedNewDataCheckChecksum,newSyncInfo->kStrongChecksumByteSize); check(0==memcmp(newSyncInfo->savedNewDataCheckChecksum+newSyncInfo->kStrongChecksumByteSize, newSyncInfo->savedNewDataCheckChecksum,newSyncInfo->kStrongChecksumByteSize), kSyncClient_newDataCheckChecksumError); } } clear: _inClear=1; if (isNeed_readSyncDataEnd&&(syncDataListener->readSyncDataEnd)) syncDataListener->readSyncDataEnd(syncDataListener); if (checkChecksum) strongChecksumPlugin->close(strongChecksumPlugin,checkChecksum); if (newBlockDataInOldPoss) free(newBlockDataInOldPoss); return result; } static TSyncClient_resultType _sync_patch_file2file(ISyncInfoListener* listener,IReadSyncDataListener* syncDataListener, TSyncDiffData* diffData,const char* oldFile,const char* newSyncInfoFile, const char* outNewFile,hpatch_BOOL isOutNewContinue, const hpatch_TStreamOutput* out_diffStream,TSyncDiffType diffType, const hpatch_TStreamInput* diffContinue,int threadNum){ TSyncClient_resultType result=kSyncClient_ok; int _inClear=0; TNewDataSyncInfo newSyncInfo; hpatch_TFileStreamInput oldData; hpatch_TFileStreamOutput out_newData; const hpatch_TStreamInput* newDataContinue=0; hpatch_TStreamInput _newDataContinue; const hpatch_TStreamInput* oldStream=0; bool isOldPathInputEmpty=(oldFile==0)||(strlen(oldFile)==0); TNewDataSyncInfo_init(&newSyncInfo); hpatch_TFileStreamInput_init(&oldData); hpatch_TFileStreamOutput_init(&out_newData); result=TNewDataSyncInfo_open_by_file(&newSyncInfo,newSyncInfoFile,listener); check(result==kSyncClient_ok,result); if (!isOldPathInputEmpty) check(hpatch_TFileStreamInput_open(&oldData,oldFile),kSyncClient_oldFileOpenError); oldStream=&oldData.base; if (outNewFile){ check(_open_continue_out(isOutNewContinue,outNewFile,&out_newData,&_newDataContinue,newSyncInfo.newDataSize), isOutNewContinue?kSyncClient_newFileReopenWriteError:kSyncClient_newFileCreateError); if (isOutNewContinue) newDataContinue=&_newDataContinue; } result=_sync_patch(listener,syncDataListener,diffData,oldStream,&newSyncInfo, outNewFile?&out_newData.base:0,newDataContinue, out_diffStream,diffType,diffContinue,threadNum); clear: _inClear=1; check(hpatch_TFileStreamOutput_close(&out_newData),kSyncClient_newFileCloseError); check(hpatch_TFileStreamInput_close(&oldData),kSyncClient_oldFileCloseError); TNewDataSyncInfo_close(&newSyncInfo); return result; } struct _TRange{ hpatch_StreamPos_t first; hpatch_StreamPos_t second; }; static const hpatch_StreamPos_t kEmptyEndPos=~(hpatch_StreamPos_t)0; static inline bool _isCanCombine(const _TRange& back_range,hpatch_StreamPos_t rangeBegin){ return ((rangeBegin>0)&(back_range.second+1==rangeBegin)); } static inline void _setRange(_TRange& next_ranges,hpatch_StreamPos_t rangeBegin,hpatch_StreamPos_t rangeEnd){ assert(rangeBeginblockCount){ hpatch_BOOL isNeedSync; uint32_t syncSize; nsi->getBlockInfoByIndex(nsi,blockIndex,&isNeedSync,&syncSize); if (isNeedSync){ if ((result>0)&&_isCanCombine(backRange,posInNewSyncData)){ backRange.second+=syncSize; }else if (result>=maxGetRangeLen){ break; //finish }else{ _setRange(backRange,posInNewSyncData,posInNewSyncData+syncSize); ++result; } if (out_ranges) out_ranges[result-1]=backRange; } posInNewSyncData+=syncSize; ++blockIndex; } return result; } TSyncClient_resultType sync_patch(ISyncInfoListener* listener,IReadSyncDataListener* syncDataListener, const hpatch_TStreamInput* oldStream,const TNewDataSyncInfo* newSyncInfo, const hpatch_TStreamOutput* out_newStream,const hpatch_TStreamInput* newDataContinue, const hpatch_TStreamOutput* out_diffInfoStream,const hpatch_TStreamInput* diffInfoContinue,int threadNum){ return _sync_patch(listener,syncDataListener,0,oldStream,newSyncInfo,out_newStream,newDataContinue, out_diffInfoStream,kSyncDiff_info,diffInfoContinue,threadNum); } TSyncClient_resultType sync_local_diff(ISyncInfoListener* listener,IReadSyncDataListener* syncDataListener, const hpatch_TStreamInput* oldStream,const TNewDataSyncInfo* newSyncInfo, const hpatch_TStreamOutput* out_diffStream,TSyncDiffType diffType, const hpatch_TStreamInput* diffContinue,int threadNum){ return _sync_patch(listener,syncDataListener,0,oldStream,newSyncInfo,0,0, out_diffStream,diffType,diffContinue,threadNum); } TSyncClient_resultType sync_local_patch(ISyncInfoListener* listener,const hpatch_TStreamInput* in_diffStream, const hpatch_TStreamInput* oldStream,const TNewDataSyncInfo* newSyncInfo, const hpatch_TStreamOutput* out_newStream,const hpatch_TStreamInput* newDataContinue,int threadNum){ TSyncDiffData diffData; if (!_TSyncDiffData_load(&diffData,in_diffStream)) return kSyncClient_loadDiffError; return _sync_patch(listener,0,&diffData,oldStream,newSyncInfo,out_newStream,newDataContinue, 0,kSyncDiff_default,0,threadNum); } TSyncClient_resultType sync_patch_file2file(ISyncInfoListener* listener,IReadSyncDataListener* syncDataListener, const char* oldFile,const char* newSyncInfoFile, const char* outNewFile,hpatch_BOOL isOutNewContinue, const char* cacheDiffInfoFile,int threadNum){ TSyncClient_resultType result=kSyncClient_ok; int _inClear=0; hpatch_TFileStreamOutput out_diffInfo; hpatch_TFileStreamOutput_init(&out_diffInfo); const hpatch_TStreamInput* diffContinue=0; hpatch_TStreamInput _diffContinue; if (cacheDiffInfoFile){ hpatch_BOOL isOutDiffContinue=hpatch_TRUE; check(_open_continue_out(isOutDiffContinue,cacheDiffInfoFile,&out_diffInfo,&_diffContinue), isOutDiffContinue?kSyncClient_diffFileReopenWriteError:kSyncClient_diffFileCreateError); if (isOutDiffContinue) diffContinue=&_diffContinue; } result=_sync_patch_file2file(listener,syncDataListener,0,oldFile,newSyncInfoFile, outNewFile,isOutNewContinue, cacheDiffInfoFile?&out_diffInfo.base:0,kSyncDiff_info,diffContinue,threadNum); clear: _inClear=1; check(hpatch_TFileStreamOutput_close(&out_diffInfo),kSyncClient_diffFileCloseError); return result; } TSyncClient_resultType sync_local_diff_file2file(ISyncInfoListener* listener,IReadSyncDataListener* syncDataListener, const char* oldFile,const char* newSyncInfoFile, const char* outDiffFile,TSyncDiffType diffType, hpatch_BOOL isOutDiffContinue,int threadNum){ TSyncClient_resultType result=kSyncClient_ok; int _inClear=0; hpatch_TFileStreamOutput out_diff; hpatch_TFileStreamOutput_init(&out_diff); const hpatch_TStreamInput* diffContinue=0; hpatch_TStreamInput _diffContinue; check(_open_continue_out(isOutDiffContinue,outDiffFile,&out_diff,&_diffContinue), isOutDiffContinue?kSyncClient_diffFileReopenWriteError:kSyncClient_diffFileCreateError); if (isOutDiffContinue) diffContinue=&_diffContinue; result=_sync_patch_file2file(listener,syncDataListener,0,oldFile,newSyncInfoFile,0,hpatch_FALSE, &out_diff.base,diffType,diffContinue,threadNum); /*if ((result==kSyncClient_ok)&&isOutDiffContinue &&(out_diff.out_length>0)&&(out_diff.out_lengthstreamSize)){ check(hpatch_TFileStreamOutput_truncate(&out_diff,out_diff.out_length), kSyncClient_diffFileReopenWriteError); // retained data error }*/ clear: _inClear=1; check(hpatch_TFileStreamOutput_close(&out_diff),kSyncClient_diffFileCloseError); return result; } TSyncClient_resultType sync_local_patch_file2file(ISyncInfoListener* listener,const char* inDiffFile, const char* oldFile,const char* newSyncInfoFile, const char* outNewFile,hpatch_BOOL isOutNewContinue,int threadNum){ TSyncClient_resultType result=kSyncClient_ok; int _inClear=0; TSyncDiffData diffData; hpatch_TFileStreamInput in_diffData; hpatch_TFileStreamInput_init(&in_diffData); check(hpatch_TFileStreamInput_open(&in_diffData,inDiffFile), kSyncClient_diffFileOpenError); check(_TSyncDiffData_load(&diffData,&in_diffData.base),kSyncClient_loadDiffError); result=_sync_patch_file2file(listener,0,&diffData,oldFile,newSyncInfoFile,outNewFile,isOutNewContinue, 0,kSyncDiff_default,0,threadNum); clear: _inClear=1; check(hpatch_TFileStreamInput_close(&in_diffData),kSyncClient_diffFileCloseError); return result; }