private bool ApplyDiffToFile(string filePath, string diffPath, string targetPath, int patchItemIndex) { PatchItem item = patchInfo.Files[patchItemIndex]; FileInfo targetFile = new FileInfo(targetPath); if (targetFile.Exists && targetFile.MatchesSignature(item.AfterFileSize, item.AfterMd5Hash)) { comms.Log(Localization.Get(StringId.AlreadyUpToDateXthFile, patchItemIndex + 1, patchInfo.Files.Count, item.Path)); return(true); } if (item.BeforeFileSize == 0L) { comms.Log(Localization.Get(StringId.CreatingXthFile, patchItemIndex + 1, patchInfo.Files.Count, item.Path)); Directory.CreateDirectory(Path.GetDirectoryName(targetPath)); PatchUtils.CopyFile(diffPath, targetPath); File.Delete(diffPath); return(true); } FileInfo localFile = new FileInfo(filePath); if (!localFile.Exists || !localFile.MatchesSignature(item.BeforeFileSize, item.BeforeMd5Hash)) { return(false); } comms.Log(Localization.Get(StringId.UpdatingXthFile, patchItemIndex + 1, patchInfo.Files.Count, item.Path)); FilePatchProgress progress = null; string tempOutputPath = diffPath + "_.tmp"; if (comms.LogProgress) { progress = new FilePatchProgress(comms, Path.GetFileName(filePath)); } OctoUtils.ApplyDelta(filePath, tempOutputPath, diffPath, progress); FileInfo updatedFile = new FileInfo(tempOutputPath); if (!updatedFile.Exists || !updatedFile.MatchesSignature(item.AfterFileSize, item.AfterMd5Hash)) { return(false); } Directory.CreateDirectory(Path.GetDirectoryName(targetPath)); PatchUtils.CopyFile(tempOutputPath, targetPath); File.Delete(tempOutputPath); File.Delete(diffPath); return(true); }
private void TraverseIncrementalPatchRecursively(DirectoryInfo directory, string relativePath) { FileInfo[] files = directory.GetFiles(); for (int i = 0; i < files.Length; i++) { if (cancel) { return; } FileInfo fileInfo = files[i]; string fileRelativePath = relativePath + fileInfo.Name; if (!ignoredPathsRegex.PathMatchesPattern(fileRelativePath)) { string targetAbsolutePath = previousVersionRoot + fileRelativePath; string diffFileAbsolutePath = incrementalPatchTempPath + fileRelativePath; if (!File.Exists(targetAbsolutePath)) { Log(Localization.Get(StringId.CopyingXToPatch, fileRelativePath)); PatchUtils.CopyFile(fileInfo.FullName, diffFileAbsolutePath); incrementalPatch.Files.Add(new PatchItem(fileRelativePath, null, fileInfo)); } else { FileInfo prevVersion = new FileInfo(targetAbsolutePath); if (!fileInfo.MatchesSignature(prevVersion)) { Log(Localization.Get(StringId.CalculatingDiffOfX, fileRelativePath)); OctoUtils.CalculateDelta(targetAbsolutePath, fileInfo.FullName, diffFileAbsolutePath, diffQuality); incrementalPatch.Files.Add(new PatchItem(fileRelativePath, prevVersion, fileInfo)); } } } } DirectoryInfo[] subDirectories = directory.GetDirectories(); for (int i = 0; i < subDirectories.Length; i++) { if (cancel) { return; } string directoryRelativePath = relativePath + subDirectories[i].Name + Path.DirectorySeparatorChar; if (!ignoredPathsRegex.PathMatchesPattern(directoryRelativePath)) { Directory.CreateDirectory(incrementalPatchTempPath + directoryRelativePath); TraverseIncrementalPatchRecursively(subDirectories[i], directoryRelativePath); } } }
private PatchResult CreateRepairPatch() { if (cancel) { return(PatchResult.Failed); } Directory.CreateDirectory(repairPatchOutputPath); Log(Localization.Get(StringId.CreatingRepairPatch)); Stopwatch timer = Stopwatch.StartNew(); // Compress repair patch files and move them to the destination Log(Localization.Get(StringId.CompressingFilesToDestination)); Stopwatch compressTimer = Stopwatch.StartNew(); // Check if we can use existing repair patch files for files that didn't change since the last patch string previousRepairPatchFilesRoot = null; if (previousVersionInfo != null && previousVersionInfo.CompressionFormat == compressionFormatRepairPatch) { previousRepairPatchFilesRoot = previousPatchFilesRoot + PatchParameters.REPAIR_PATCH_DIRECTORY + Path.DirectorySeparatorChar; if (!Directory.Exists(previousRepairPatchFilesRoot)) { previousRepairPatchFilesRoot = null; } } for (int i = 0; i < versionInfo.Files.Count; i++) { if (cancel) { return(PatchResult.Failed); } VersionItem patchItem = versionInfo.Files[i]; string fromAbsolutePath = rootPath + patchItem.Path; string toAbsolutePath = repairPatchOutputPath + patchItem.Path + PatchParameters.REPAIR_PATCH_FILE_EXTENSION; if (previousRepairPatchFilesRoot != null) { VersionItem previousPatchItem = previousVersionInfo.Files.Find((item) => item.Path == patchItem.Path); if (previousPatchItem != null && previousPatchItem.FileSize == patchItem.FileSize && previousPatchItem.Md5Hash == patchItem.Md5Hash) { if (dontCreatePatchFilesForUnchangedFiles) { patchItem.CompressedFileSize = previousPatchItem.CompressedFileSize; patchItem.CompressedMd5Hash = previousPatchItem.CompressedMd5Hash; continue; } FileInfo previousCompressedFile = new FileInfo(previousRepairPatchFilesRoot + patchItem.Path + PatchParameters.REPAIR_PATCH_FILE_EXTENSION); if (previousCompressedFile.Exists && previousCompressedFile.MatchesSignature(previousPatchItem.CompressedFileSize, previousPatchItem.CompressedMd5Hash)) { Log(Localization.Get(StringId.CopyingXToPatch, previousCompressedFile.FullName)); PatchUtils.CopyFile(previousCompressedFile.FullName, toAbsolutePath); patchItem.CompressedFileSize = previousPatchItem.CompressedFileSize; patchItem.CompressedMd5Hash = previousPatchItem.CompressedMd5Hash; continue; } } } Log(Localization.Get(StringId.CompressingXToY, fromAbsolutePath, toAbsolutePath)); compressTimer.Reset(); compressTimer.Start(); ZipUtils.CompressFile(fromAbsolutePath, toAbsolutePath, compressionFormatRepairPatch); Log(Localization.Get(StringId.CompressionFinishedInXSeconds, compressTimer.ElapsedSeconds())); patchItem.OnCompressed(new FileInfo(toAbsolutePath)); } if (cancel) { return(PatchResult.Failed); } Log(Localization.Get(StringId.PatchCreatedInXSeconds, timer.ElapsedSeconds())); // Calculate compression ratio long uncompressedTotal = 0L, compressedTotal = 0L; for (int i = 0; i < versionInfo.Files.Count; i++) { uncompressedTotal += versionInfo.Files[i].FileSize; compressedTotal += versionInfo.Files[i].CompressedFileSize; } Log(Localization.Get(StringId.CompressionRatioIsX, ((double)compressedTotal * 100 / uncompressedTotal).ToString("F2"))); return(PatchResult.Success); }
protected override PatchResult Execute() { if (comms.Cancel) { return(PatchResult.Failed); } if (comms.IsUnderMaintenance()) { return(PatchResult.Failed); } string rootPath = comms.SelfPatching ? comms.DecompressedFilesPath : comms.RootPath; string patchDecompressPath = comms.GetDecompressPathForPatch(PatchParameters.INSTALLER_PATCH_DIRECTORY); string patchDownloadPath = comms.CachePath + PatchParameters.INSTALLER_PATCH_FILENAME; InstallerPatch patchInfo = comms.VersionInfo.InstallerPatch; Stopwatch timer = Stopwatch.StartNew(); comms.Stage = PatchStage.CalculatingFilesToUpdate; comms.Log(Localization.Get(StringId.CalculatingNewOrChangedFiles)); List <VersionItem> filesToUpdate = comms.FindFilesToUpdate(); if (filesToUpdate.Count == 0) { return(PatchResult.AlreadyUpToDate); } if (comms.Cancel) { return(PatchResult.Failed); } InitializeProgress(filesToUpdate.Count, patchInfo.PatchSize); PatchUtils.DeleteDirectory(patchDecompressPath); Directory.CreateDirectory(patchDecompressPath); FileInfo patchFile = new FileInfo(patchDownloadPath); if (!patchFile.Exists || !patchFile.MatchesSignature(patchInfo.PatchSize, patchInfo.PatchMd5Hash)) { comms.Stage = PatchStage.DownloadingFiles; Stopwatch downloadTimer = Stopwatch.StartNew(); comms.Log(Localization.Get(StringId.DownloadingPatchX, PatchParameters.INSTALLER_PATCH_FILENAME)); patchFile = comms.DownloadManager.DownloadFileFromURLToPath(comms.VersionInfo.GetDownloadURLFor(patchInfo), patchDownloadPath, patchInfo.PatchSize); if (patchFile == null) { comms.FailReason = PatchFailReason.DownloadError; comms.FailDetails = Localization.Get(StringId.E_XCouldNotBeDownloaded, PatchParameters.INSTALLER_PATCH_FILENAME); return(PatchResult.Failed); } else if (!patchFile.MatchesSignature(patchInfo.PatchSize, patchInfo.PatchMd5Hash)) { comms.FailReason = PatchFailReason.CorruptDownloadError; comms.FailDetails = Localization.Get(StringId.E_DownloadedFileXIsCorrupt, PatchParameters.INSTALLER_PATCH_FILENAME); return(PatchResult.Failed); } else { comms.Log(Localization.Get(StringId.XDownloadedInYSeconds, PatchParameters.INSTALLER_PATCH_FILENAME, downloadTimer.ElapsedSeconds())); } } else { ReportProgress(0, patchInfo.PatchSize); } if (comms.Cancel) { return(PatchResult.Failed); } comms.Stage = PatchStage.ExtractingFilesFromArchive; comms.Log(Localization.Get(StringId.DecompressingPatchX, PatchParameters.INSTALLER_PATCH_FILENAME)); ZipUtils.DecompressFolder(patchFile.FullName, patchDecompressPath, patchInfo.CompressionFormat); comms.Stage = PatchStage.UpdatingFiles; comms.Log(Localization.Get(StringId.UpdatingXFiles, filesToUpdate.Count)); for (int i = 0; i < filesToUpdate.Count; i++) { if (comms.Cancel) { return(PatchResult.Failed); } string fileRelativePath = filesToUpdate[i].Path; string targetAbsolutePath = rootPath + fileRelativePath; comms.Log(Localization.Get(StringId.UpdatingXthFile, i + 1, filesToUpdate.Count, fileRelativePath)); Directory.CreateDirectory(Path.GetDirectoryName(targetAbsolutePath)); PatchUtils.CopyFile(patchDecompressPath + fileRelativePath, targetAbsolutePath); ReportProgress(1, 0L); } PatchUtils.DeleteDirectory(patchDecompressPath); File.Delete(patchDownloadPath); comms.Log(Localization.Get(StringId.PatchAppliedInXSeconds, timer.ElapsedSeconds())); return(PatchResult.Success); }