Skip to content

Commit

Permalink
Resolve files in-use during update on Windows
Browse files Browse the repository at this point in the history
  • Loading branch information
JustArchi committed Apr 6, 2024
1 parent 9b3ab17 commit 27bafb1
Showing 1 changed file with 28 additions and 5 deletions.
33 changes: 28 additions & 5 deletions ArchiSteamFarm/Core/Utilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -388,10 +388,10 @@ internal static async Task<bool> UpdateFromArchive(ZipArchive zipArchive, string

Directory.CreateDirectory(backupDirectory);

MoveAllUpdateFiles(targetDirectory, backupDirectory, true);
MoveAllUpdateFiles(targetDirectory, backupDirectory);

// Finally, we can move the newly extracted files to target directory
MoveAllUpdateFiles(updateDirectory, targetDirectory, false);
MoveAllUpdateFiles(updateDirectory, targetDirectory, backupDirectory);

// Critical section has finished, we can now cleanup the update directory, backup directory must wait for the process restart
Directory.Delete(updateDirectory, true);
Expand Down Expand Up @@ -481,13 +481,16 @@ private static async Task DeletePotentiallyUsedDirectory(string directory) {
}
}

private static void MoveAllUpdateFiles(string sourceDirectory, string targetDirectory, bool keepUserFiles) {
ArgumentException.ThrowIfNullOrEmpty(sourceDirectory);
private static void MoveAllUpdateFiles(string sourceDirectory, string targetDirectory, string? backupDirectory = null) {
ArgumentException.ThrowIfNullOrEmpty(sourceDirectory);
ArgumentException.ThrowIfNullOrEmpty(targetDirectory);

// Determine if targetDirectory is within sourceDirectory, if yes we need to skip it from enumeration further below
string targetRelativeDirectoryPath = Path.GetRelativePath(sourceDirectory, targetDirectory);

// We keep user files if backup directory is null, as it means we're creating one
bool keepUserFiles = string.IsNullOrEmpty(backupDirectory);

foreach (string file in Directory.EnumerateFiles(sourceDirectory, "*", SearchOption.AllDirectories)) {
string fileName = Path.GetFileName(file);

Expand All @@ -505,7 +508,7 @@ private static void MoveAllUpdateFiles(string sourceDirectory, string targetDire

switch (relativeDirectoryName) {
case null:
throw new InvalidOperationException(nameof(keepUserFiles));
throw new InvalidOperationException(nameof(relativeDirectoryName));
case "":
// No directory, root folder
switch (fileName) {
Expand Down Expand Up @@ -557,6 +560,26 @@ private static void MoveAllUpdateFiles(string sourceDirectory, string targetDire

string targetUpdateFile = Path.Combine(targetUpdateDirectory, fileName);

// If target update file exists and we have a backup directory, we should consider moving it to the backup directory regardless whether or not we did that before as part of backup procedure
// This achieves two purposes, firstly, we ensure additional backup of user file in case something goes wrong, and secondly, we decrease a possibility of overwriting files that are in-use on Windows, since we move them out of the picture first
if (!string.IsNullOrEmpty(backupDirectory) && File.Exists(targetUpdateFile)) {
string targetBackupDirectory;

if (relativeDirectoryName.Length > 0) {
// File inside a subdirectory
targetBackupDirectory = Path.Combine(backupDirectory, relativeDirectoryName);

Directory.CreateDirectory(targetBackupDirectory);
} else {
// File in root directory
targetBackupDirectory = backupDirectory;
}

string targetBackupFile = Path.Combine(targetBackupDirectory, fileName);

File.Move(targetUpdateFile, targetBackupFile, true);
}

File.Move(file, targetUpdateFile, true);
}
}
Expand Down

0 comments on commit 27bafb1

Please sign in to comment.