| 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 |