Safe(r)Delete, Safe(r)Move : could have infinite loop of exceptions. Fixed. Limit 3
This commit is contained in:
parent
648b84ee55
commit
dfa5829cbd
@ -65,7 +65,7 @@ namespace AaxDecrypter
|
|||||||
{
|
{
|
||||||
var zeroProgress = Step2_Start();
|
var zeroProgress = Step2_Start();
|
||||||
|
|
||||||
FileUtility.SafeDelete(OutputFileName);
|
FileUtility.SaferDelete(OutputFileName);
|
||||||
|
|
||||||
var outputFile = File.Open(OutputFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
|
var outputFile = File.Open(OutputFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
|
||||||
|
|
||||||
@ -202,7 +202,7 @@ That naming may not be desirable for everyone, but it's an easy change to instea
|
|||||||
var fileName = FileUtility.GetMultipartFileName(OutputFileName, currentChapter, splitChapters.Count, newSplitCallback.Chapter.Title);
|
var fileName = FileUtility.GetMultipartFileName(OutputFileName, currentChapter, splitChapters.Count, newSplitCallback.Chapter.Title);
|
||||||
multiPartFilePaths.Add(fileName);
|
multiPartFilePaths.Add(fileName);
|
||||||
|
|
||||||
FileUtility.SafeDelete(fileName);
|
FileUtility.SaferDelete(fileName);
|
||||||
|
|
||||||
newSplitCallback.OutputFile = File.Open(fileName, FileMode.OpenOrCreate);
|
newSplitCallback.OutputFile = File.Open(fileName, FileMode.OpenOrCreate);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,7 +47,7 @@ namespace AaxDecrypter
|
|||||||
CacheDir = cacheDirectory;
|
CacheDir = cacheDirectory;
|
||||||
|
|
||||||
// delete file after validation is complete
|
// delete file after validation is complete
|
||||||
FileUtility.SafeDelete(OutputFileName);
|
FileUtility.SaferDelete(OutputFileName);
|
||||||
DownloadLicense = ArgumentValidator.EnsureNotNull(dlLic, nameof(dlLic));
|
DownloadLicense = ArgumentValidator.EnsureNotNull(dlLic, nameof(dlLic));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,8 +116,8 @@ namespace AaxDecrypter
|
|||||||
|
|
||||||
protected bool Step4_Cleanup()
|
protected bool Step4_Cleanup()
|
||||||
{
|
{
|
||||||
FileUtility.SafeDelete(jsonDownloadState);
|
FileUtility.SaferDelete(jsonDownloadState);
|
||||||
FileUtility.SafeDelete(tempFile);
|
FileUtility.SaferDelete(tempFile);
|
||||||
return !IsCanceled;
|
return !IsCanceled;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,8 +136,8 @@ namespace AaxDecrypter
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
FileUtility.SafeDelete(jsonDownloadState);
|
FileUtility.SaferDelete(jsonDownloadState);
|
||||||
FileUtility.SafeDelete(tempFile);
|
FileUtility.SaferDelete(tempFile);
|
||||||
return NewNetworkFilePersister();
|
return NewNetworkFilePersister();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net5.0</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
<Version>6.2.6.7</Version>
|
<Version>6.2.6.8</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Dinah.Core" Version="2.0.0.1" />
|
<PackageReference Include="Dinah.Core" Version="2.0.0.1" />
|
||||||
|
<PackageReference Include="Polly" Version="7.2.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@ -3,6 +3,8 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Dinah.Core;
|
using Dinah.Core;
|
||||||
|
using Polly;
|
||||||
|
using Polly.Retry;
|
||||||
|
|
||||||
namespace FileManager
|
namespace FileManager
|
||||||
{
|
{
|
||||||
@ -11,8 +13,7 @@ namespace FileManager
|
|||||||
private const int MAX_FILENAME_LENGTH = 255;
|
private const int MAX_FILENAME_LENGTH = 255;
|
||||||
private const int MAX_DIRECTORY_LENGTH = 247;
|
private const int MAX_DIRECTORY_LENGTH = 247;
|
||||||
|
|
||||||
//public static string GetValidFilename(string template, Dictionary<string, object> parameters) { }
|
public static string GetValidFilename(string dirFullPath, string filename, string extension, string metadataSuffix)
|
||||||
public static string GetValidFilename(string dirFullPath, string filename, string extension, params string[] metadataSuffixes)
|
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(dirFullPath))
|
if (string.IsNullOrWhiteSpace(dirFullPath))
|
||||||
throw new ArgumentException($"{nameof(dirFullPath)} may not be null or whitespace", nameof(dirFullPath));
|
throw new ArgumentException($"{nameof(dirFullPath)} may not be null or whitespace", nameof(dirFullPath));
|
||||||
@ -23,13 +24,11 @@ namespace FileManager
|
|||||||
filename = filename.Replace(':', '_');
|
filename = filename.Replace(':', '_');
|
||||||
filename = PathLib.ToPathSafeString(filename);
|
filename = PathLib.ToPathSafeString(filename);
|
||||||
|
|
||||||
// manage length
|
|
||||||
if (filename.Length > 50)
|
if (filename.Length > 50)
|
||||||
filename = filename.Substring(0, 50) + "[...]";
|
filename = filename.Substring(0, 50) + "[...]";
|
||||||
|
|
||||||
// append metadata
|
if (!string.IsNullOrWhiteSpace(metadataSuffix))
|
||||||
if (metadataSuffixes != null && metadataSuffixes.Length > 0)
|
filename += $" [{metadataSuffix}]";
|
||||||
filename += " [" + string.Join("][", metadataSuffixes) + "]";
|
|
||||||
|
|
||||||
// extension is null when this method is used for directory names
|
// extension is null when this method is used for directory names
|
||||||
if (!string.IsNullOrWhiteSpace(extension))
|
if (!string.IsNullOrWhiteSpace(extension))
|
||||||
@ -65,7 +64,7 @@ namespace FileManager
|
|||||||
public static string Move(string source, string destination)
|
public static string Move(string source, string destination)
|
||||||
{
|
{
|
||||||
// TODO: destination must be valid path. Use: " (#)" when needed
|
// TODO: destination must be valid path. Use: " (#)" when needed
|
||||||
SafeMove(source, destination);
|
SaferMove(source, destination);
|
||||||
return destination;
|
return destination;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,57 +74,50 @@ namespace FileManager
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Delete file. No error when file does not exist.
|
private static int maxRetryAttempts { get; } = 3;
|
||||||
/// Exceptions are logged, not thrown.</summary>
|
private static TimeSpan pauseBetweenFailures { get; } = TimeSpan.FromMilliseconds(100);
|
||||||
/// <param name="source">File to delete</param>
|
private static RetryPolicy retryPolicy { get; } =
|
||||||
public static void SafeDelete(string source)
|
Policy
|
||||||
{
|
.Handle<Exception>()
|
||||||
if (!File.Exists(source))
|
.WaitAndRetry(maxRetryAttempts, i => pauseBetweenFailures);
|
||||||
return;
|
|
||||||
|
|
||||||
while (true)
|
/// <summary>Delete file. No error when source does not exist. Retry up to 3 times.</summary>
|
||||||
|
public static void SaferDelete(string source)
|
||||||
|
=> retryPolicy.Execute(() =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
File.Delete(source);
|
if (!File.Exists(source))
|
||||||
Serilog.Log.Logger.Information($"File successfully deleted: {source}");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
System.Threading.Thread.Sleep(100);
|
|
||||||
Serilog.Log.Logger.Error(e, $"Failed to delete: {source}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Moves a specified file to a new location, providing the option to specify a newfile name.
|
|
||||||
/// Exceptions are logged, not thrown.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="source">The name of the file to move. Can include a relative or absolute path.</param>
|
|
||||||
/// <param name="target">The new path and name for the file.</param>
|
|
||||||
public static void SafeMove(string source, string target)
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (File.Exists(source))
|
|
||||||
{
|
{
|
||||||
SafeDelete(target);
|
File.Delete(source);
|
||||||
File.Move(source, target);
|
Serilog.Log.Logger.Information("File successfully deleted", new { source });
|
||||||
Serilog.Log.Logger.Information($"File successfully moved from '{source}' to '{target}'");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
System.Threading.Thread.Sleep(100);
|
Serilog.Log.Logger.Error(e, "Failed to delete file", new { source });
|
||||||
Serilog.Log.Logger.Error(e, $"Failed to move '{source}' to '{target}'");
|
throw;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
|
||||||
|
/// <summary>Move file. No error when source does not exist. Retry up to 3 times.</summary>
|
||||||
|
public static void SaferMove(string source, string target)
|
||||||
|
=> retryPolicy.Execute(() =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!File.Exists(source))
|
||||||
|
{
|
||||||
|
SaferDelete(target);
|
||||||
|
File.Move(source, target);
|
||||||
|
Serilog.Log.Logger.Information("File successfully moved", new { source, target });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Serilog.Log.Logger.Error(e, "Failed to move file", new { source, target });
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,11 +4,6 @@
|
|||||||
<TargetFramework>net5.0</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="5.0.0" />
|
|
||||||
<PackageReference Include="Polly" Version="7.2.2" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\FileManager\FileManager.csproj" />
|
<ProjectReference Include="..\FileManager\FileManager.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user