history | TOP |
2006/01/08:作成
overview | TOP |
いつものようにまず最初に。このページの内容に独自性はありません。完全無欠にパクリです。
感動的なフリーウェアが多く公開されている Sysinternals Freeware で、ソースコードもいくつか公開されているのですが、このうちの NTFSドライブの情報を取得するサンプルをDelphiに翻訳しただけです。
WindowsXP と Windows2000 で試したんですが、オリジナル と同じ答えを戻しているようです。でもいつものごとく思うのは、Delphiでなくても...
それから、Delphiに翻訳するにあたってよくわからない箇所はそのままに動くように動くようにを目標にしています。記述にまずい点があるかも知れません。
NtFsControlFile というドキュメント化されてない(Last Updated: November 11, 1997 v1.0 時点で...)関数を使っているんですが、コレを使うためのフラグや結果を受けとるための構造体がわからないことには、使い道がありません。どなたかが既に調べられていると思いますが、検索してしまうとここでやった内容が陳腐化する可能性が高いので、横に置いときます。
XPでやっても2000でやっても同じだったんですが、メタファイル情報を出力するはずの処理で全く何も出力されません。最初に定数値で書いているメタファイルの名称が変更になっているのかも知れません。
コード | TOP |
//==================================================================== // // Ntsinfo.c // // Copyright (C) 1997 Mark Russinovich // http://www.ntinternals.com // // Shows NTFS volume information. // //==================================================================== unit Ntsinfo; interface uses Windows, SysUtils, Classes; type // NTFS volume information PNTFS_VOLUME_DATA_BUFFER = ^NTFS_VOLUME_DATA_BUFFER; NTFS_VOLUME_DATA_BUFFER = record SerialNumber : LARGE_INTEGER; NumberOfSectors : LARGE_INTEGER; TotalClusters : LARGE_INTEGER; FreeClusters : LARGE_INTEGER; Reserved : LARGE_INTEGER; BytesPerSector : ULONG; BytesPerCluster : ULONG; BytesPerMFTRecord : ULONG; ClustersPerMFTRecord: ULONG; MFTLength : LARGE_INTEGER; MFTStart : LARGE_INTEGER; MFTMirrorStart : LARGE_INTEGER; MFTZoneStart : LARGE_INTEGER; MFTZoneEnd : LARGE_INTEGER; end; procedure DumpMetaFiles(const DriveId: Char; Results: TStrings); function GetNTFSInfo(const DriveId: Char; var VolumeInfo: NTFS_VOLUME_DATA_BUFFER; var Err: String): Boolean; implementation const // File System Control command for getting NTFS information FSCTL_GET_VOLUME_INFORMATION = $90064; // return code type type NTSTATUS = UINT; const // Error codes returned by NtFsControlFile (see NTSTATUS.H) STATUS_SUCCESS = NTSTATUS($00000000); STATUS_BUFFER_OVERFLOW = NTSTATUS($80000005); STATUS_INVALID_PARAMETER = NTSTATUS($C000000D); STATUS_BUFFER_TOO_SMALL = NTSTATUS($C0000023); STATUS_ALREADY_COMMITTED = NTSTATUS($C0000021); STATUS_INVALID_DEVICE_REQUEST = NTSTATUS($C0000010); // Metadata file names MetaFileNames: array[0..10] of string = ( '$mft', '$mftmirr', '$logfile', '$volume', '$attrdef', '$bitmap', '$boot', '$badclus', '$quota', '$badclust', '$upcase' ); type PVOID = Pointer; HANDLE = Cardinal; // Io Status block (see NTDDK.H) PIO_STATUS_BLOCK = ^_IO_STATUS_BLOCK; _IO_STATUS_BLOCK = record Status: NTSTATUS; Information: ULONG; end; // Apc Routine (see NTDDK.H) PIO_APC_ROUTINE = procedure( ApcContext: PVOID; IoStatusBlock: PIO_STATUS_BLOCK; Reserved: ULONG ); // The undocumented NtFsControlFile // This function is used to send File System Control (FSCTL) // commands into file system drivers. Its definition is // in ntdll.dll (ntdll.lib), a file shipped with the NTDDK. TNtFsControlFile = function( FileHandle : HANDLE; Event : HANDLE; // optional ApcRoutine : PIO_APC_ROUTINE; // optional ApcContext : PVOID; // optional IoStatusBlock : PIO_STATUS_BLOCK; FsControlCode : ULONG; InputBuffer : PVOID; // optional InputBufferLength : ULONG; OutputBuffer : PVOID; // optional OutputBufferLength : ULONG ): NTSTATUS; stdcall; var NtFsControlFile: TNtFsControlFile = nil; //-------------------------------------------------------------------- // F U N C T I O N S //-------------------------------------------------------------------- //-------------------------------------------------------------------- // Translates an NTDLL error code into its text equivalent. This // only deals with ones commonly returned by defragmenting FS Control // commands. //-------------------------------------------------------------------- function PrintNtError(const Status: NTSTATUS): String; begin case (Status) of STATUS_SUCCESS: Result := 'STATUS_SUCCESS'; STATUS_INVALID_PARAMETER: Result := 'STATUS_INVALID_PARAMETER'; STATUS_BUFFER_TOO_SMALL: Result := 'STATUS_BUFFER_TOO_SMALL'; STATUS_ALREADY_COMMITTED: Result := 'STATUS_ALREADY_COMMITTED'; STATUS_INVALID_DEVICE_REQUEST: Result := 'STATUS_INVALID_DEVICE_REQUEST'; else Result := Format('%8d', [Status]); end; end; //-------------------------------------------------------------------- // Does directory lookups of NTFS metadata files. //-------------------------------------------------------------------- procedure DumpMetaFiles(const DriveId: Char; Results: TStrings); var FileName: String; FindData: WIN32_FIND_DATA; FindHandle: HANDLE; i: Integer; Line: String; begin // Loop through array of files for i := 0 to Length(MetaFileNames) - 1 do begin FileName := Format('%s:\%s', [DriveId, MetaFileNames[i]]); FindHandle := FindFirstFile(PChar(FileName), FindData); if (FindHandle <> INVALID_HANDLE_VALUE) then begin Line := Format('%-11s %d bytes', [findData.cFileName, findData.nFileSizeLow]); Windows.FindClose(FindHandle); Results.Add(Line); end; end; end; //-------------------------------------------------------------------- // Open the volume and query its data. //-------------------------------------------------------------------- function GetNTFSInfo(const DriveId: Char; var VolumeInfo: NTFS_VOLUME_DATA_BUFFER; var Err: String): Boolean; var VolumeName: String; VolumeHandle: HANDLE; IoStatus: _IO_STATUS_BLOCK; Status: NTSTATUS; begin Result := False; // 関数ロード成功チェック if (@NtFsControlFile = nil) then begin Err := 'Not running on supported version of Windows NT.'; Exit; end; // open the volume VolumeName := Format('\\.\%s:', [DriveId]); VolumeHandle := CreateFile( PChar(VolumeName), GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0); if (VolumeHandle = INVALID_HANDLE_VALUE) then begin Err := 'Error opening volume:' + SysErrorMessage(GetLastError()); Exit; end; // Query the volume information Status := NtFsControlFile( VolumeHandle, 0, nil, nil, @IoStatus, FSCTL_GET_VOLUME_INFORMATION, nil, 0, @VolumeInfo, SizeOf(NTFS_VOLUME_DATA_BUFFER)); if (Status <> STATUS_SUCCESS) then begin Err := 'Error obtaining NTFS information:' + PrintNtError(Status); CloseHandle(VolumeHandle); Exit; end; // Close the volume CloseHandle(VolumeHandle); Result := True; end; initialization // Loads function entry points in NTDLL @NtFsControlFile := GetProcAddress(GetModuleHandle('ntdll.dll'), 'NtFsControlFile'); finalization // end.
使い方 | TOP |
こんな感じで。
uses Ntsinfo; //-------------------------------------------------------------------- // Just open the volume and dump its information. procedure TForm1.Button1Click(Sender: TObject); var Drive: Char; VolumeInfo: NTFS_VOLUME_DATA_BUFFER; Err: String; begin Drive := 'C'; // Get ntfs volume data if (GetNTFSInfo(Drive, VolumeInfo, Err)) then begin Memo1.Lines.Add(IntToStr(VolumeInfo.NumberOfSectors.QuadPart)); DumpMetaFiles(Drive, Memo1.Lines); end else begin Memo1.Lines.Add(Err); end; end;
実行結果 | TOP |
NtfsInfoTest.zip(192,936bytes)
EOF | TOP |