Skip to content

Commit bdbdf58

Browse files
JusterZhuclaude
andcommitted
fix(DiffPipeline): CopyUnknownFiles 使用原子替换避免文件占用冲突
ISSUE: 全量包升级时,CopyUnknownFiles 直接调用 File.Copy(dest, true) 覆盖目标文件。若目标进程刚退出,文件句柄未释放,抛出 IOException: 'The process cannot access the file because it is being used by another process' 导致 AllPackagesSucceeded=false,版本号不回写 manifest,ClientTest 陷入无限循环检测-下载-失败的更新循环。 FIX: CopyUnknownFiles 改为和 ApplyPatch 一致的 temp-file 原子替换策略: 1. File.Copy 到临时文件 {random}_{filename} 2. File.Replace 原子替换目标文件 3. 新文件直接用 File.Move File.Replace 是 NTFS 内核级原子操作,不会出现半覆盖状态。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 829c4a0 commit bdbdf58

2 files changed

Lines changed: 16 additions & 10 deletions

File tree

src/c#/GeneralUpdate.Core/Pipeline/DiffPipeline.cs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,22 @@ private static Task CopyUnknownFiles(string appPath, string patchPath)
507507
if (parentFolder?.Exists == false)
508508
parentFolder.Create();
509509

510-
File.Copy(file.FullName, targetPath, true);
510+
// Atomic replace via temp file, same strategy as ApplyPatch.
511+
// Avoids file-in-use errors when the process just exited.
512+
var safeName = targetFileName.Replace(Path.DirectorySeparatorChar, '_');
513+
var tempPath = Path.Combine(appPath, $"{Path.GetRandomFileName()}_{safeName}");
514+
File.Copy(file.FullName, tempPath, true);
515+
516+
// Use File.Replace for atomic overwrite (handles locked targets gracefully)
517+
if (File.Exists(targetPath))
518+
{
519+
File.SetAttributes(targetPath, FileAttributes.Normal);
520+
File.Replace(tempPath, targetPath, null, true);
521+
}
522+
else
523+
{
524+
File.Move(tempPath, targetPath);
525+
}
511526
}
512527

513528
if (Directory.Exists(patchPath))

tests/ClientTest/generalupdate.manifest.json

Lines changed: 0 additions & 9 deletions
This file was deleted.

0 commit comments

Comments
 (0)