Windowsでもinode的なところを調べたかったのですが調べてみると、
Open both files with CreateFile, call GetFileInformationByHandle for both, and compare dwVolumeSerialNumber, nFileIndexLow, nFileIndexHigh. If all three are equal they both point to the same file:
とのことで、GetFileInformationByHandle
関数で取得できる、BY_HANDLE_FILE_INFORMATION
のStructureを調べれば良いようです。
GetFileInformationByHandle function | Microsoft Docs _BY_HANDLE_FILE_INFORMATION | Microsoft Docs
ここで取得した dwVolumeSerialNumber
, nFileIndexLow
, nFileIndexHigh
を比較するということのようです。
処理の定義
すみません。PowerShellと題名に書いておきながらコードはC#です。
以下をPowerShellに貼り付けてEnterで定義ができます。
Add-Type -TypeDefinition @' using System; using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; using System.Text; using Microsoft.Win32.SafeHandles; using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME; namespace WindowsFileInfo { public static class Kernel32Api { [StructLayout(LayoutKind.Sequential)] public struct BY_HANDLE_FILE_INFORMATION { public uint FileAttributes; public FILETIME CreationTime; public FILETIME LastAccessTime; public FILETIME LastWriteTime; public uint VolumeSerialNumber; public uint FileSizeHigh; public uint FileSizeLow; public uint NumberOfLinks; public uint FileIndexHigh; public uint FileIndexLow; } [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] 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)] static extern bool GetFileInformationByHandle(SafeFileHandle handle, out BY_HANDLE_FILE_INFORMATION lpFileInformation); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool CloseHandle(SafeHandle hObject); public static BY_HANDLE_FILE_INFORMATION GetFileInfo(string filepath) { SafeFileHandle handle = CreateFile(filepath, FileAccess.Read, FileShare.Read, IntPtr.Zero, FileMode.Open, FileAttributes.Archive, IntPtr.Zero); BY_HANDLE_FILE_INFORMATION fileInfo = new BY_HANDLE_FILE_INFORMATION(); GetFileInformationByHandle(handle, out fileInfo); CloseHandle(handle); return fileInfo; } } } '@
確認
VolumeSerialNumber
と FileIndexHigh
と FileIndexLow
を比較して同一のファイルであることを判断します。
PS > echo "a" > a.txt PS > $filepath = [System.IO.Directory]::GetCurrentDirectory() + "\a.txt" PS > [WindowsFileInfo.Kernel32Api]::GetFileInfo($filepath) FileAttributes : 32 CreationTime : System.Runtime.InteropServices.ComTypes.FILETIME LastAccessTime : System.Runtime.InteropServices.ComTypes.FILETIME LastWriteTime : System.Runtime.InteropServices.ComTypes.FILETIME VolumeSerialNumber : 2421491731 FileSizeHigh : 0 FileSizeLow : 8 NumberOfLinks : 1 FileIndexHigh : 327680 FileIndexLow : 901684 PS > mv a.txt b.txt PS > [WindowsFileInfo.Kernel32Api]::GetFileInfo($filepath) FileAttributes : 32 CreationTime : System.Runtime.InteropServices.ComTypes.FILETIME LastAccessTime : System.Runtime.InteropServices.ComTypes.FILETIME LastWriteTime : System.Runtime.InteropServices.ComTypes.FILETIME VolumeSerialNumber : 2421491731 FileSizeHigh : 0 FileSizeLow : 8 NumberOfLinks : 1 FileIndexHigh : 327680 FileIndexLow : 901684
fsutilでも似た情報を取得可能
同僚に教えてもらいましたが、似たような情報はfsutilでも取得可能です。
PS> fsutil usn readdata .\b.txt メジャー バージョン : 0x3 マイナー バージョン : 0x0 ファイルの参照番号 : 0x0000000000000000008a00000006ff4f 親ファイルの参照番号 : 0x000000000000000000c3000000021499 USN : 0x000000026e1def60 タイム スタンプ : 0x0000000000000000 0:00:00 1601/01/01 理由 : 0x0 ソース情報 : 0x0 セキュリティ ID : 0x0 ファイル属性 : 0x20 ファイル名の長さ : 0xa ファイル名オフセット : 0x4c ファイル名 : b.txt