diff --git a/CHANGELOG.md b/CHANGELOG.md index 42cdfe62..274d6a8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ * Treat .fomod files as archives * Include WABBAJACK_INCLUDE files before including patches * Ignore .bin and .refcache files (DynDOLOD temp files) +* Shell out to cmd.exe for VFS cleaning should fix "ReadOnlyFile" errors once and for all #### Version 0.9.1 - 9/5/2019 * Fixed a bug where having only one profile selected would result in no profiles being selected diff --git a/VirtualFileSystem/VirtualFileSystem.cs b/VirtualFileSystem/VirtualFileSystem.cs index d07a917f..c5991a89 100644 --- a/VirtualFileSystem/VirtualFileSystem.cs +++ b/VirtualFileSystem/VirtualFileSystem.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; +using System.Runtime.CompilerServices; using Compression.BSA; using ICSharpCode.SharpZipLib.Zip; using Newtonsoft.Json; @@ -28,11 +30,17 @@ namespace VFS RootFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); _stagedRoot = Path.Combine(RootFolder, "vfs_staged_files"); - Utils.OnQueue(() => + + } + + public static void Clean() + { + if (Directory.Exists(_stagedRoot)) { - if (Directory.Exists(_stagedRoot)) - DeleteDirectory(_stagedRoot); - }); + Directory.EnumerateDirectories(_stagedRoot) + .PMap(f => DeleteDirectory(f)); + DeleteDirectory(_stagedRoot); + } Directory.CreateDirectory(_stagedRoot); } @@ -47,28 +55,41 @@ namespace VFS public VirtualFile this[string path] => Lookup(path); - private static void DeleteDirectory(string path, bool recursive = true) + private static void DeleteDirectory(string path) { - if (recursive) + var info = new ProcessStartInfo + { + FileName = "cmd.exe", + Arguments = $"/c del /f /q /s \"{path}\" && rmdir /q /s \"{path}\" ", + RedirectStandardError = true, + RedirectStandardInput = true, + RedirectStandardOutput = true, + UseShellExecute = false, + CreateNoWindow = true + }; + + var p = new Process + { + StartInfo = info + }; + + p.Start(); + ChildProcessTracker.AddProcess(p); + try + { + p.PriorityClass = ProcessPriorityClass.BelowNormal; + } + catch (Exception) { - var subfolders = Directory.GetDirectories(path); - foreach (var s in subfolders) DeleteDirectory(s, recursive); } - var files = Directory.GetFiles(path); - foreach (var f in files) - try - { - var attr = File.GetAttributes(f); - if ((attr & FileAttributes.ReadOnly) == FileAttributes.ReadOnly) - File.SetAttributes(f, attr ^ FileAttributes.ReadOnly); - File.Delete(f); - } - catch (IOException) - { - } - - Directory.Delete(path, true); + while (!p.HasExited) + { + var line = p.StandardOutput.ReadLine(); + if (line == null) break; + Utils.Status(line); + } + p.WaitForExit(); } private void LoadFromDisk() diff --git a/Wabbajack/Compiler.cs b/Wabbajack/Compiler.cs index 9d3b7e25..51996612 100644 --- a/Wabbajack/Compiler.cs +++ b/Wabbajack/Compiler.cs @@ -103,6 +103,7 @@ namespace Wabbajack public void Compile() { + VirtualFileSystem.Clean(); Info("Looking for other profiles"); var other_profiles_path = Path.Combine(MO2ProfileDir, "otherprofiles.txt"); SelectedProfiles = new HashSet(); diff --git a/Wabbajack/Installer.cs b/Wabbajack/Installer.cs index 9e87bd68..c91ff243 100644 --- a/Wabbajack/Installer.cs +++ b/Wabbajack/Installer.cs @@ -78,6 +78,7 @@ namespace Wabbajack public void Install() { + VirtualFileSystem.Clean(); Directory.CreateDirectory(Outputfolder); Directory.CreateDirectory(DownloadFolder);