Move hard link availability check to helper class

This commit is contained in:
Dean Herbert 2022-12-13 20:02:57 +09:00
parent bbf931c746
commit 6bb612ce69
2 changed files with 63 additions and 31 deletions

View File

@ -3,7 +3,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using osu.Framework;
@ -57,22 +56,15 @@ public partial class LegacyImportManager : Component
public bool CheckHardLinkAvailability()
{
if (RuntimeInfo.OS != RuntimeInfo.Platform.Windows)
return false;
var stableStorage = GetCurrentStableStorage();
if (stableStorage == null || gameHost is not DesktopGameHost desktopGameHost)
return false;
const string test_filename = "_hard_link_test";
string testExistingPath = stableStorage.GetFullPath(string.Empty);
string testDestinationPath = desktopGameHost.Storage.GetFullPath(string.Empty);
desktopGameHost.Storage.Delete(test_filename);
string testExistingPath = stableStorage.GetFullPath(stableStorage.GetFiles(string.Empty).First());
string testDestinationPath = desktopGameHost.Storage.GetFullPath(test_filename);
return HardLinkHelper.CreateHardLink(testDestinationPath, testExistingPath, IntPtr.Zero);
return HardLinkHelper.CheckAvailability(testDestinationPath, testExistingPath);
}
public virtual async Task<int> GetImportCount(StableContent content, CancellationToken cancellationToken)

View File

@ -6,11 +6,55 @@
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using Microsoft.Win32.SafeHandles;
using osu.Framework;
namespace osu.Game.IO
{
internal static class HardLinkHelper
{
public static bool CheckAvailability(string testDestinationPath, string testSourcePath)
{
// We can support other operating systems quite easily in the future.
// Let's handle the most common one for now, though.
if (RuntimeInfo.OS != RuntimeInfo.Platform.Windows)
return false;
const string test_filename = "_hard_link_test";
testDestinationPath = Path.Combine(testDestinationPath, test_filename);
testSourcePath = Path.Combine(testSourcePath, test_filename);
cleanupFiles();
try
{
File.WriteAllText(testSourcePath, string.Empty);
// Test availability by creating an arbitrary hard link between the source and destination paths.
return CreateHardLink(testDestinationPath, testSourcePath, IntPtr.Zero);
}
catch
{
return false;
}
finally
{
cleanupFiles();
}
void cleanupFiles()
{
try
{
File.Delete(testDestinationPath);
File.Delete(testSourcePath);
}
catch
{
}
}
}
// For future use (to detect if a file is a hard link with other references existing on disk).
public static int GetFileLinkCount(string filePath)
{
@ -27,26 +71,7 @@ public static int GetFileLinkCount(string filePath)
}
[DllImport("Kernel32.dll", CharSet = CharSet.Unicode)]
public static extern bool CreateHardLink(
string lpFileName,
string lpExistingFileName,
IntPtr lpSecurityAttributes
);
[StructLayout(LayoutKind.Sequential)]
private struct ByHandleFileInformation
{
public readonly uint FileAttributes;
public readonly FILETIME CreationTime;
public readonly FILETIME LastAccessTime;
public readonly FILETIME LastWriteTime;
public readonly uint VolumeSerialNumber;
public readonly uint FileSizeHigh;
public readonly uint FileSizeLow;
public readonly uint NumberOfLinks;
public readonly uint FileIndexHigh;
public readonly uint FileIndexLow;
}
public static extern bool CreateHardLink(string lpFileName, string lpExistingFileName, IntPtr lpSecurityAttributes);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern SafeFileHandle CreateFile(
@ -64,5 +89,20 @@ private static extern SafeFileHandle CreateFile(
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(SafeHandle hObject);
[StructLayout(LayoutKind.Sequential)]
private struct ByHandleFileInformation
{
public readonly uint FileAttributes;
public readonly FILETIME CreationTime;
public readonly FILETIME LastAccessTime;
public readonly FILETIME LastWriteTime;
public readonly uint VolumeSerialNumber;
public readonly uint FileSizeHigh;
public readonly uint FileSizeLow;
public readonly uint NumberOfLinks;
public readonly uint FileIndexHigh;
public readonly uint FileIndexLow;
}
}
}