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