1 // 2 // Copyright (c) 2010-2025 Antmicro 3 // Copyright (c) 2011-2015 Realtime Embedded 4 // 5 // This file is licensed under the MIT License. 6 // Full license text is available in 'licenses/MIT.txt'. 7 // 8 using System; 9 using System.IO; 10 using System.Linq; 11 using System.Diagnostics; 12 using Antmicro.Renode.Core; 13 14 namespace Antmicro.Renode.Utilities 15 { 16 public class TemporaryFilesManager 17 { TemporaryFilesManager()18 static TemporaryFilesManager() 19 { 20 Initialize(Path.GetTempPath(), DefaultDirectoryPrefix, !EmulationManager.DisableEmulationFilesCleanup); 21 } 22 23 public static TemporaryFilesManager Instance { get; private set; } 24 Initialize(string tempDirectory, string tempDirPrefix, bool cleanFiles)25 public static void Initialize(string tempDirectory, string tempDirPrefix, bool cleanFiles) 26 { 27 Instance = new TemporaryFilesManager(tempDirectory, tempDirPrefix, cleanFiles); 28 } 29 GetTemporaryFile(string fileNameSuffix = null)30 public string GetTemporaryFile(string fileNameSuffix = null) 31 { 32 lock(emulatorTemporaryPath) 33 { 34 string path; 35 do 36 { 37 var fileName = string.Format(fileNameSuffix != null ? $"{Guid.NewGuid()}-{fileNameSuffix}" : $"{Guid.NewGuid()}.tmp"); 38 path = Path.Combine(emulatorTemporaryPath, fileName); 39 // this is guid, collision is very unlikely 40 } 41 while(File.Exists(path)); 42 43 using(File.Create(path)) 44 { 45 //that's the simplest way to create and NOT have the file open 46 } 47 48 var ofc = OnFileCreated; 49 if(ofc != null) 50 { 51 ofc(path); 52 } 53 54 return path; 55 } 56 } 57 TryCreateFile(string fileName, out string path, bool overwriteExistingFile = false)58 public bool TryCreateFile(string fileName, out string path, bool overwriteExistingFile = false) 59 { 60 path = Path.Combine(emulatorTemporaryPath, fileName); 61 62 try 63 { 64 if(File.Exists(path)) 65 { 66 if(!overwriteExistingFile) 67 { 68 path = null; 69 return false; 70 } 71 File.Delete(path); 72 } 73 74 using(File.Create(path)) 75 { 76 //that's the simplest way to create and NOT have the file open 77 } 78 } 79 catch(Exception) 80 { 81 path = null; 82 return false; 83 } 84 85 return true; 86 } 87 Cleanup()88 public void Cleanup() 89 { 90 if(!shouldCleanFiles) 91 { 92 return; 93 } 94 95 foreach(var entry in Directory.GetDirectories(Directory.GetParent(emulatorTemporaryPath).FullName) 96 .Where(x => x != emulatorTemporaryPath && x.StartsWith(otherEmulatorTempPrefix, StringComparison.Ordinal) 97 && !x.EndsWith(CrashSuffix, StringComparison.Ordinal))) 98 { 99 var pid = entry.Substring(otherEmulatorTempPrefix.Length); 100 int processId; 101 if(pid != null && int.TryParse(pid, out processId) && IsProcessAlive(processId)) 102 { 103 continue; 104 } 105 ClearDirectory(entry); 106 } 107 } 108 109 public event Action<string> OnFileCreated; 110 111 public string EmulatorTemporaryPath 112 { 113 get 114 { 115 return emulatorTemporaryPath; 116 } 117 } 118 TemporaryFilesManager(string tempDirectory, string tempDirPrefix, bool cleanFiles)119 private TemporaryFilesManager(string tempDirectory, string tempDirPrefix, bool cleanFiles) 120 { 121 shouldCleanFiles = cleanFiles; 122 if(AppDomain.CurrentDomain.IsDefaultAppDomain()) 123 { 124 id = Process.GetCurrentProcess().Id.ToString(); 125 } 126 else 127 { 128 id = string.Format("{0}-{1}", Process.GetCurrentProcess().Id, AppDomain.CurrentDomain.Id); 129 } 130 otherEmulatorTempPrefix = Path.Combine(tempDirectory, tempDirPrefix); 131 emulatorTemporaryPath = otherEmulatorTempPrefix + id; 132 133 if(!Directory.Exists(emulatorTemporaryPath)) 134 { 135 Directory.CreateDirectory(emulatorTemporaryPath); 136 } 137 Cleanup(); 138 } 139 IsProcessAlive(int pid)140 private static bool IsProcessAlive(int pid) 141 { 142 try 143 { 144 var proc = Process.GetProcessById(pid); 145 return proc != null && !proc.HasExited; 146 } 147 catch(ArgumentException) 148 { 149 return false; 150 } 151 } 152 ~TemporaryFilesManager()153 ~TemporaryFilesManager() 154 { 155 Cleanup(); 156 ClearDirectory(emulatorTemporaryPath); 157 } 158 ClearDirectory(string path)159 private void ClearDirectory(string path) 160 { 161 if(!shouldCleanFiles) 162 { 163 return; 164 } 165 try 166 { 167 Directory.Delete(path, true); 168 } 169 catch(Exception) 170 { 171 // we did everything we could 172 } 173 } 174 175 public const string CrashSuffix = "-crash"; 176 177 private readonly string otherEmulatorTempPrefix; 178 private readonly string emulatorTemporaryPath; 179 private readonly string id; 180 private readonly bool shouldCleanFiles; 181 182 private const string DefaultDirectoryPrefix = "renode-"; 183 } 184 } 185