From 3b1920c060b9352654b3f2d429548bffcbbbc4a0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 13 Oct 2022 18:18:29 +0900 Subject: [PATCH] Add code to check whether a file is a hard link --- osu.Game/Database/RealmFileStore.cs | 48 +++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/osu.Game/Database/RealmFileStore.cs b/osu.Game/Database/RealmFileStore.cs index 56ea8f23bc..4aa65dd50a 100644 --- a/osu.Game/Database/RealmFileStore.cs +++ b/osu.Game/Database/RealmFileStore.cs @@ -5,6 +5,8 @@ using System; using System.IO; using System.Linq; using System.Runtime.InteropServices; +using System.Runtime.InteropServices.ComTypes; +using Microsoft.Win32.SafeHandles; using osu.Framework; using osu.Framework.Extensions; using osu.Framework.IO.Stores; @@ -77,6 +79,20 @@ namespace osu.Game.Database data.Seek(0, SeekOrigin.Begin); } + public static int GetFileLinkCount(string filePath) + { + int result = 0; + SafeFileHandle handle = CreateFile(filePath, FileAccess.Read, FileShare.Read, IntPtr.Zero, FileMode.Open, FileAttributes.Archive, IntPtr.Zero); + + ByHandleFileInformation fileInfo; + + if (GetFileInformationByHandle(handle, out fileInfo)) + result = (int)fileInfo.NumberOfLinks; + CloseHandle(handle); + + return result; + } + [DllImport("Kernel32.dll", CharSet = CharSet.Unicode)] private static extern bool CreateHardLink( string lpFileName, @@ -84,6 +100,38 @@ namespace osu.Game.Database 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; + } + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] + private static extern SafeFileHandle CreateFile( + string lpFileName, + [MarshalAs(UnmanagedType.U4)] FileAccess dwDesiredAccess, + [MarshalAs(UnmanagedType.U4)] FileShare dwShareMode, + IntPtr lpSecurityAttributes, + [MarshalAs(UnmanagedType.U4)] FileMode dwCreationDisposition, + [MarshalAs(UnmanagedType.U4)] FileAttributes dwFlagsAndAttributes, + IntPtr hTemplateFile); + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern bool GetFileInformationByHandle(SafeFileHandle handle, out ByHandleFileInformation lpFileInformation); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool CloseHandle(SafeHandle hObject); + private bool checkFileExistsAndMatchesHash(RealmFile file) { string path = file.GetStoragePath();