Everythingの研究によるUSNレコードのファイルパスの迅速な取得
前回のUSNの探索に続いて、私たちはUSNを簡単に操作することができましたが、基本的なことはできませんでした.私たちはまだUSN記録のファイルパスを得ることができません.これはちょうど必要です.<探索開始>typedef struct{DWORD RecordLength;//記録長WORD MajorVersion;//メインバージョンWORD MinorVersion;//サブバージョンDWORDLONG FileReferenceNumber;//ファイル参照数DWORDLONG ParentFileReferenceNumber;//親ディレクトリ参照数USN Usn;//USN LARGEE_INTEGER TimeStamp;//タイムスタンプDWORD Reason;//理由DWORD SourceInfo;//ソース情報DWORD SecurityId;//セキュリティID DWORD FileAttributes;//ファイルのプロパティWORD FileNameLength;//ファイル長WORD FileNameOffset;//penultimate of original version 2.0<ファイル名オフセット>DWORD ExtraInfo 1;//Hypothetically added in version 2.1 DWORD ExtraInfo2;//Hypothetically added in version 2.2 DWORD ExtraInfo3;//Hypothetically added in version 2.3 WCHAR FileName[1];//variable length always at the end<ファイル名1位のポインタ>}USN_RECORD, *PUSN_RECORD;
これはUSNごとに記録された構造で、この構造を通じて私たちが得ることができるファイル名とその他のいくつかの情報ですが、その経路は含まれていません.
前述の記事では、FileReferenceNumberとParentFileReferenceNumberがキーです.
マイクロソフトが提供するNtQueryInformationFile関数から取得する方法で、具体的には以下のように実現されています.
/// <summary>
/// GetPathByFileReferenceNumber() ID .
/// </summary>
/// <param name="hVol">HANDLE ,
/// </param>
/// <param name="frn"> ID, USN_RECORD
/// </param>
/// <param name="pathBuffer"> char*
/// </param>
/// <param name="bufferSize">
/// </param>
/// <returns>BOOL
/// </returns>
/// <remarks>
/// NTFS3.0 , Win7
/// </remarks>
BOOL GetPathByFileReferenceNumber(__in HANDLE hVol, __in DWORDLONG frn, __out char* pathBuffer, __in int bufferSize)
{
BOOL result = FALSE;
HANDLE hFile;
//printf("frn: %I64x
", frn);
// FileReferenceNumber UNICODE_STR
UNICODE_STRING fidstr;
CoverFileReferenceNumberToFileIdStr(frn, &fidstr);
//ULONG fid[2] = {0x00000892, 0x00020000};//{i.nFileIndexLow, i.nFileIndexHigh};
//UNICODE_STRING fidstr = {8, 8, (PWSTR) fid};
// OBJECT_ATTRIBUTES
OBJECT_ATTRIBUTES oa = {0};
oa.Length = sizeof(OBJECT_ATTRIBUTES);
oa.ObjectName = &fidstr;
oa.RootDirectory = hVol;
oa.Attributes = OBJ_CASE_INSENSITIVE;
//InitializeObjectAttributes (&oa, &fidstr, OBJ_CASE_INSENSITIVE, d, NULL);
IO_STATUS_BLOCK ioStatusBlock = {0};
// FILE_ID ,
ULONG status = NtCreatefile(&hFile,
FILE_GENERIC_READ,
&oa,
&ioStatusBlock,
NULL,
FILE_ATTRIBUTE_READONLY,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN,
FILE_OPEN_BY_FILE_ID | FILE_OPEN_FOR_BACKUP_INTENT,
NULL,
0);
//printf("status: %X, handle: %x
", status, hFile);
//printf("error: %d, t: %x
", GetLastError(), iosb);
if(0==status){
//FILE_NAME_INFORMATION* info = (FILE_NAME_INFORMATION*)malloc(BUF_LEN);
//int allocSize = BUF_LEN;
//
status = NtQueryInformationFile(hFile,
&ioStatusBlock,
info,
allocSize,
FileNameInformation);
if(0==status){
// wchar*, char*
int dwMinSize = (*info).FileNameLength;
WideCharToMultiByte(CP_OEMCP,NULL,(*info).FileName,dwMinSize/2,pathBuffer,dwMinSize,NULL,FALSE);
result = TRUE;
}
//free(info);
CloseHandle(hFile);
}
return result;
}
これはいい方法ですが、遅すぎて、簡単にテストしてみました.20 Wのファイルは14秒以上かかります.1台の機械はこんなに少ないファイル数だけではありません.Everythingの速さにははるかに及ばない.
しかしMSDNとネット上で私はすべてひっくり返して、何の収穫もありません.それは本当に他の方法がありますか?
<新しいアイデアを探す>
そこで私は手元のすべての情報を集めて、情報をテキストに印刷してよく審査しました.
以下に印刷された情報の一部を示します:***************************************<ディスク>ファイル名FileReferenceNumber-対応アドレスP r e n t FileReferenceNumber-対応アドレス
これに基づいて、「実況8における超風雲秋風DIY版」が存在する経路を取得すると、彼のpfrn(14073748883553285)に基づいてE:に関連付けられ、「E:実況8における超風雲秋風DIY版」が出てくる.「WE 8.exe」なら?それはまず「実況8における超風雲秋風DIY版」の経路を取得してから構築しなければならない.
このような法則に従って、私たちが上から下へ連絡を確立すれば、すべてのファイルの完全なパスを得ることができます.実はこれが木の構造です.
<具体的な実装>上から下へ構築できるように、USNを読み取るときはまずいくつかの処理をしなければなりません.1.各ディレクトリ属性のレコードのfrnをkey値とし、そのkeyをpfrnとするレコードを内容としてハッシュテーブルを構築する(Hashtable
最後に完全なパステーブルを作成できます.もちろん、このような限界は、すべてのデータを先に取得する必要があることです.
ここでは、大まかな参考を提供します.
static final long rootFileReferenceNumber = Long.parseLong("1407374883553285");
static final String EndSymbol = "\\";
private Hashtable<Long, Vector> hashByPfrn; // pfrn key
private Hashtable<Long, String> hashPaths; //
public static main(String[] args){
for( USN ){
addData(.frn, .fileName, .pfrn, .filePath, .fileAttribute);
}
buildPath(rootFileReferenceNumber, "E:\\");
}
/**
*
* @param frn
* @param fileName
* @param pfrn
* @param filePath
* @param fileAttribute
*/
private void addData(long frn, String fileName, long pfrn, String filePath, int fileAttribute) {
Vector<NtfsVolumeData> v = (Vector<NtfsVolumeData>) hashByPfrn.get(pfrn);
NtfsVolumeData record = new NtfsVolumeData(frn, fileName, pfrn, filePath, fileAttribute);
if (v == null) {
v = new Vector<NtfsVolumeData>();
v.add(record);
hashByPfrn.put(pfrn, v);
} else {
v.add(record);
}
fileCounter++;
}
/**
*
* @param rootKey
* @param rootName
*/
private void buildPath(long rootKey, String rootName) {
hashPaths.clear();
long key = rootKey;
hashPaths.put(key, rootName);
buildPath(key, hashPaths);
}
/**
*
* @param key
* @param hashPaths
*/
private void buildPath(long key, Hashtable hashPaths) {
// key
Vector<NtfsVolumeData> records = (Vector<NtfsVolumeData>) hashByPfrn.get(key);
if (records == null || records.size() <= 0) {
return;
}
// key
String filePath = (String) hashPaths.get(key);
//
for (NtfsVolumeData record : records) {
record.setParentPath(filePath);
/**
*
*/
if (0 != (record.getFileAttributes() & UsnRecordAttributeValues.FILE_ATTRIBUTE_DIRECTORY)) {
//
hashPaths.put(record.frn, record.getFullPath() + EndSymbol);
//
buildPath(record.frn, hashPaths);
}
}
}