@@ -791,6 +791,7 @@ enum class MacAdvanceResult
791791{
792792 Pending, // Chunk queued or in progress
793793 Ready, // Local MAC is computed (check state->localMac)
794+ Obsolete, // Local file changed; discard state and rescan
794795 Failed // Error occurred
795796};
796797
@@ -832,6 +833,19 @@ MacAdvanceResult advanceMacComputation(MegaClient& mc,
832833 return MacAdvanceResult::Pending;
833834 }
834835
836+ // Empty file: compute local MAC directly without reading or queueing chunks
837+ if (state->totalSize == 0 )
838+ {
839+ SymmCipher cipher;
840+ cipher.setkey (state->transferkey .data ());
841+
842+ const int64_t localMac = state->partialMacs .macsmac (&cipher);
843+
844+ LOG_debug << logPrefix << " Local MAC computed for empty file: " << localMac;
845+ state->setComplete (localMac);
846+ return MacAdvanceResult::Ready;
847+ }
848+
835849 // Ready for next chunk - read and queue
836850 m_off_t readStart = state->currentPosition ;
837851 m_off_t tentativeEnd = std::min (readStart + MacComputationState::BUFFER_SIZE, state->totalSize );
@@ -875,8 +889,7 @@ MacAdvanceResult advanceMacComputation(MegaClient& mc,
875889 LOG_debug << logPrefix << " File size changed: expected " << state->totalSize << " , got "
876890 << fa->size ;
877891 fa->fclose ();
878- state->setFailed ();
879- return MacAdvanceResult::Failed;
892+ return MacAdvanceResult::Obsolete;
880893 }
881894
882895 // Read chunk into buffer
@@ -987,6 +1000,13 @@ FsCloudComparisonResult asyncMacComputation(MegaClient& mc,
9871000 LocalNode& syncNode)
9881001{
9891002 static const std::string logPre{" asyncMacComputation: " };
1003+ const auto restartAfterInvalidation = [&syncNode, &fsNodeFullPath]() -> FsCloudComparisonResult
1004+ {
1005+ LOG_debug << logPre << " MAC state invalidated, requesting rescan: " << fsNodeFullPath;
1006+ syncNode.resetMacComputationIfAny ();
1007+ syncNode.setScanAgain (true , false , false , 0 );
1008+ return {NODE_COMP_PENDING, INVALID_META_MAC, INVALID_META_MAC, FingerprintMismatch::Other};
1009+ };
9901010
9911011 // Check throttling first - skip if a recent mtime-only op just completed
9921012 if (syncNode.shouldThrottleMacComputation (MAC_THROTTLE_WINDOW))
@@ -1044,6 +1064,10 @@ FsCloudComparisonResult asyncMacComputation(MegaClient& mc,
10441064 INVALID_META_MAC,
10451065 FingerprintMismatch::Other};
10461066 }
1067+ else if (result == MacAdvanceResult::Obsolete)
1068+ {
1069+ return restartAfterInvalidation ();
1070+ }
10471071 else
10481072 {
10491073 // Pending - return and wait
@@ -1096,6 +1120,11 @@ FsCloudComparisonResult asyncMacComputation(MegaClient& mc,
10961120 // Advance computation (will queue first chunk)
10971121 auto result = advanceMacComputation (mc, macComp, logPre);
10981122
1123+ if (result == MacAdvanceResult::Obsolete)
1124+ {
1125+ return restartAfterInvalidation ();
1126+ }
1127+
10991128 if (result == MacAdvanceResult::Failed)
11001129 {
11011130 syncNode.resetMacComputationIfAny ();
@@ -1233,7 +1262,7 @@ CloneMacStatus initCloneCandidateMacComputation(MegaClient& mc, SyncUpload_inCli
12331262
12341263 // Start first chunk - pass local macComp to ensure object stays alive
12351264 auto result = advanceMacComputation (mc, macComp, logPre);
1236- if (result == MacAdvanceResult::Failed)
1265+ if (result == MacAdvanceResult::Failed || result == MacAdvanceResult::Obsolete )
12371266 {
12381267 LOG_debug << logPre << " Failed to start computation of MAC for "
12391268 << upload.getLocalname ();
@@ -1335,6 +1364,12 @@ CloneMacStatus checkPendingCloneMac(MegaClient& mc, SyncUpload_inClient& upload)
13351364 upload.macComputation .reset ();
13361365 return CloneMacStatus::Failed;
13371366 }
1367+ else if (result == MacAdvanceResult::Obsolete)
1368+ {
1369+ LOG_debug << logPre << " Obsolete: " << upload.getLocalname ();
1370+ upload.macComputation .reset ();
1371+ return CloneMacStatus::Failed;
1372+ }
13381373
13391374 // Pending
13401375 return CloneMacStatus::Pending;
0 commit comments