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-対応アドレスProgram Files frn:2814744976710716-C:Program Files pfrn:140737883553285-C:Common Files frn:28474776710717-C:Program FilesCommon Files pfrn:281477710716-C:Program FilesFiles microsoft shared frn:281474976710718 - C:\Program Files\Common Files\microsoft shared pfrn:281474976710717 - C:\Program Files\Common Files Program Files frn:281474976710691 - D:\Program Files pfrn:1407374883553285 - D:\ Thunder Network frn:281474976710692 - D:\Program Files\Thunder Network pfrn:281474976710691 - D:\Program Files ThundErfrn:28147476710693-D:Program FilesThunder NetworkThunder pfrn:281476710692-D:Program FilesThunder Network実況8中超風雲秋風DIY版frn:2814744976710694-E:実況8中超風雲秋風DIY版pfrn:140737883553285-E:WE 8.exe frn:28147476710698-E:実況8中超風雲秋風DIY版WE 8.exe pfrn:28147476710694-E:実況8中超風雲秋風DIY版******************まず太く注意して、指す経路はルートディレクトリ(ディスク)で、彼らの対応するReferenceNumberがすべて一致していることを発見するのは難しくなくて、テストを経てUディスクに関わらず、外付けハードディスクはUSNを削除して再構築して、私はすべて一致していることを発見して、しかも1407374853285で、機械そのものと関係があるかどうかは不明ですが、具体的には検証が必要ですが、<ルートディレクトリのReferenceNumberはディスクに関係のない特定の不変の数値--14073748883553285>データを具体的に見て、上ののデータを例にとると、整理は以下の通り:name frn pfrn pathWE 8.exe 28147476710698 281474976710694 E:実況8中超風雲秋風DIY版WE 8.exe実況8中超風雲秋風DIY版2814744976710694 140734883553285 E:実況8中超風雲秋風DIY版E:140734883553285/E:前の3つの情報はUSNを通じて直接入手できます.pathは私たちが取得しなければならないものです.最後の行(140737483553285->E:)は、前に検証したものです.
 
これに基づいて、「実況8における超風雲秋風DIY版」が存在する経路を取得すると、彼のpfrn(14073748883553285)に基づいてE:に関連付けられ、「E:実況8における超風雲秋風DIY版」が出てくる.「WE 8.exe」なら?それはまず「実況8における超風雲秋風DIY版」の経路を取得してから構築しなければならない.
このような法則に従って、私たちが上から下へ連絡を確立すれば、すべてのファイルの完全なパスを得ることができます.実はこれが木の構造です.
 
 
<具体的な実装>上から下へ構築できるように、USNを読み取るときはまずいくつかの処理をしなければなりません.1.各ディレクトリ属性のレコードのfrnをkey値とし、そのkeyをpfrnとするレコードを内容としてハッシュテーブルを構築する(Hashtable).これにより、すべてのレコードを読み出すと、key value(ディレクトリ属性)レコードのfrn array{...}というハッシュテーブル構造が得られる.[pfrnがkey値である記録]2.第1段階の関連付けは、E:)->140734883553285のようなディスク名に基づいて確立する、key=140734883553285のすべてのレコードを見つけ、そのパスを「ディスク+ボディ名」3として1つずつマークする.再帰的に遍歴し、すべてのレコードのパスを取得して確立されたパスの各レコードを遍歴し、そのレコードのfrnをkey値とする要素を見つけ、パスを確立し、このように繰り返します.
最後に完全なパステーブルを作成できます.もちろん、このような限界は、すべてのデータを先に取得する必要があることです.
ここでは、大まかな参考を提供します.
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);
         }
     }
}