@@ -162,12 +162,34 @@ public static void SaveSettings(string? filePath = null)
162162 }
163163
164164 if ( File . Exists ( filePath ) )
165- {
166- File . Replace ( tempPath , filePath , backupPath , true ) ;
167- }
165+ _ = Task . Run ( async ( ) =>
166+ {
167+ // Run asynchronously to avoid blocking the UI thread
168+ try
169+ {
170+ await TryReplaceSettingsFileAsync ( filePath , tempPath , backupPath ) ;
171+ Logger . Info ( "Settings successfully saved to {0}" , filePath ) ;
172+ }
173+ catch ( Exception ex )
174+ {
175+ Logger . Error ( ex , "Error replacing settings file" ) ;
176+ }
177+ finally
178+ {
179+ TryDeleteFileIfExists ( tempPath ) ;
180+ }
181+ } ) ;
168182 else
169183 {
170- File . Move ( tempPath , filePath , true ) ;
184+ try
185+ {
186+ File . Move ( tempPath , filePath , true ) ;
187+ Logger . Info ( "Settings successfully saved to {0}" , filePath ) ;
188+ }
189+ finally
190+ {
191+ TryDeleteFileIfExists ( tempPath ) ;
192+ }
171193 }
172194 }
173195 }
@@ -181,19 +203,55 @@ public static void SaveSettings(string? filePath = null)
181203 // if the settings file cannot be saved
182204 Logger . Error ( ex , "Error saving settings" ) ;
183205 }
184- finally
206+ }
207+
208+ private async static Task TryReplaceSettingsFileAsync ( string filePath , string tempPath , string backupPath )
209+ {
210+ Logger . Debug ( "Initializing replacing settings file at {0}" , filePath ) ;
211+ int maxAttempts = 5 ;
212+ // The following steps try to avoid issues with file locks and permissions on some systems.
213+ for ( int attempts = 1 ; attempts <= maxAttempts ; attempts ++ )
185214 {
186- // delete temp file if it still exists
187- if ( File . Exists ( tempPath ) )
215+ try
188216 {
189- try
190- {
191- File . Delete ( tempPath ) ;
192- }
193- catch ( Exception ex )
194- {
195- Logger . Error ( ex , "Error deleting temporary settings file" ) ;
196- }
217+ File . Replace ( tempPath , filePath , backupPath , ignoreMetadataErrors : true ) ;
218+ break ;
219+ }
220+ catch ( IOException ex ) when ( attempts < maxAttempts )
221+ {
222+ // if the file is locked, wait and retry
223+ Logger . Warn ( ex , "Settings file is locked, retrying..." ) ;
224+ Thread . Sleep ( 75 ) ;
225+ }
226+ catch ( IOException ex )
227+ {
228+ Logger . Warn ( ex , "File.Replace failed after retries, manually replacing..." ) ;
229+ ManualReplace ( filePath , tempPath , backupPath ) ;
230+ return ;
231+ }
232+ }
233+ }
234+
235+ private static void ManualReplace ( string filePath , string tempPath , string backupPath )
236+ {
237+ TryDeleteFileIfExists ( backupPath ) ;
238+ File . Copy ( filePath , backupPath ) ;
239+ TryDeleteFileIfExists ( filePath ) ;
240+ File . Move ( tempPath , filePath ) ;
241+ }
242+
243+ private static void TryDeleteFileIfExists ( string path )
244+ {
245+ // delete file if it still exists
246+ if ( File . Exists ( path ) )
247+ {
248+ try
249+ {
250+ File . Delete ( path ) ;
251+ }
252+ catch ( Exception ex )
253+ {
254+ Logger . Error ( ex , "Error deleting file at {0}" , path ) ;
197255 }
198256 }
199257 }
0 commit comments