[英]How to get “valid data length” of a file?
有一個函數可以設置“有效數據長度”值: SetFileValidData
,但我沒有找到獲取“有效數據長度”值的方法。
如果 EOF 與 VDL 不同,我想知道給定的文件,因為在VDL<EOF
情況下在VDL<EOF
之后寫入將導致性能損失,如here所述。
我找到了這個頁面,聲稱:
沒有查詢 VDL 值的機制
所以答案是“你不能”。
如果您關心性能,您可以將 VDL 設置為 EOF,但請注意,您可能允許訪問磁盤上的舊垃圾 - 這兩個指針之間的部分,如果您在不設置 VDL 的情況下訪問該文件,則該部分應該為零指向EOF。
我認為您對“有效數據長度”的實際含義感到困惑。 檢查這個答案。
基本上,雖然SetEndOfFile
可以讓您快速增加文件的長度並分配磁盤空間,但如果您跳到(新的)文件結尾在那里寫入,則所有額外分配的磁盤空間都需要用零覆蓋,這有點慢。
SetFileValidData
可讓您跳過歸零。 你告訴系統,“我對這些磁盤塊中的任何內容都沒有意見,繼續吧”。 (這就是您需要SE_MANAGE_VOLUME_NAME
特權的原因,因為如果您不覆蓋數據,它可能會將特權數據透露給非特權用戶。具有此特權的用戶無論如何都可以訪問原始驅動器數據。)
在任何一種情況下,您都設置了文件的新有效大小。 (您可以回讀哪些內容。) 一個單獨的“讀取文件有效數據”究竟應該報告什么? SetFileValidData
告訴系統這些磁盤塊中的任何內容都是“有效的”......
不同的解釋方法:
該文檔提到的“有效數據長度”被跟蹤; 這樣做的目的是讓系統知道哪個范圍(從結束有效數據到文件結束- ),它仍然需要歸零,在的情況下SetEndOfFile
,在必要的時候(例如,你關閉文件) . 您不需要讀回此值,因為它可能與實際文件大小不同的唯一方法是您自己確實通過上述函數更改了它...
SetValidData
(根據 MSDN)可用於創建例如大文件而無需寫入文件。 對於數據庫,這將分配一個(連續的)存儲區域。
結果,磁盤上的文件大小似乎已更改,而沒有將任何數據寫入文件。
暗示,任何GetValidData
(不存在)只返回文件的大小,因此您可以使用GetFileSize
返回“有效”文件大小。
看了這個。 無法通過任何 API 獲取此信息,即使是 NtQueryInformationFile API(FileEndOfFileInformation 僅適用於 NtSetInformationFile)。 所以最后我通過手動讀取 NTFS 記錄來閱讀本文。 如果有人有更好的方法,請告訴! 這顯然也僅適用於完全系統訪問(和 NTFS),並且可能與 Windows 使用的內存信息不同步。
#pragma pack(push)
#pragma pack(1)
struct NTFSFileRecord
{
char magic[4];
unsigned short sequence_offset;
unsigned short sequence_size;
uint64 lsn;
unsigned short squence_number;
unsigned short hardlink_count;
unsigned short attribute_offset;
unsigned short flags;
unsigned int real_size;
unsigned int allocated_size;
uint64 base_record;
unsigned short next_id;
//char padding[470];
};
struct MFTAttribute
{
unsigned int type;
unsigned int length;
unsigned char nonresident;
unsigned char name_lenght;
unsigned short name_offset;
unsigned short flags;
unsigned short attribute_id;
unsigned int attribute_length;
unsigned short attribute_offset;
unsigned char indexed_flag;
unsigned char padding1;
//char padding2[488];
};
struct MFTAttributeNonResident
{
unsigned int type;
unsigned int lenght;
unsigned char nonresident;
unsigned char name_length;
unsigned short name_offset;
unsigned short flags;
unsigned short attribute_id;
uint64 starting_vnc;
uint64 last_vnc;
unsigned short run_offset;
unsigned short compression_size;
unsigned int padding;
uint64 allocated_size;
uint64 real_size;
uint64 initial_size;
};
#pragma pack(pop)
HANDLE GetVolumeData(const std::wstring& volfn, NTFS_VOLUME_DATA_BUFFER& vol_data)
{
HANDLE vol = CreateFileW(volfn.c_str(), GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (vol == INVALID_HANDLE_VALUE)
return vol;
DWORD ret_bytes;
BOOL b = DeviceIoControl(vol, FSCTL_GET_NTFS_VOLUME_DATA,
NULL, 0, &vol_data, sizeof(vol_data), &ret_bytes, NULL);
if (!b)
{
CloseHandle(vol);
return INVALID_HANDLE_VALUE;
}
return vol;
}
int64 GetFileValidData(HANDLE file, HANDLE vol, const NTFS_VOLUME_DATA_BUFFER& vol_data)
{
BY_HANDLE_FILE_INFORMATION hfi;
BOOL b = GetFileInformationByHandle(file, &hfi);
if (!b)
return -1;
NTFS_FILE_RECORD_INPUT_BUFFER record_in;
record_in.FileReferenceNumber.HighPart = hfi.nFileIndexHigh;
record_in.FileReferenceNumber.LowPart = hfi.nFileIndexLow;
std::vector<BYTE> buf;
buf.resize(sizeof(NTFS_FILE_RECORD_OUTPUT_BUFFER) + vol_data.BytesPerFileRecordSegment - 1);
NTFS_FILE_RECORD_OUTPUT_BUFFER* record_out = reinterpret_cast<NTFS_FILE_RECORD_OUTPUT_BUFFER*>(buf.data());
DWORD bout;
b = DeviceIoControl(vol, FSCTL_GET_NTFS_FILE_RECORD, &record_in,
sizeof(record_in), record_out, 4096, &bout, NULL);
if (!b)
return -1;
NTFSFileRecord* record = reinterpret_cast<NTFSFileRecord*>(record_out->FileRecordBuffer);
unsigned int currpos = record->attribute_offset;
MFTAttribute* attr = nullptr;
while ( (attr==nullptr ||
attr->type != 0xFFFFFFFF )
&& record_out->FileRecordBuffer + currpos +sizeof(MFTAttribute)<buf.data() + bout)
{
attr = reinterpret_cast<MFTAttribute*>(record_out->FileRecordBuffer + currpos);
if (attr->type == 0x80
&& record_out->FileRecordBuffer + currpos + attr->attribute_offset+sizeof(MFTAttributeNonResident)
< buf.data()+ bout)
{
if (attr->nonresident == 0)
return -1;
MFTAttributeNonResident* dataattr = reinterpret_cast<MFTAttributeNonResident*>(record_out->FileRecordBuffer
+ currpos + attr->attribute_offset);
return dataattr->initial_size;
}
currpos += attr->length;
}
return -1;
}
[...]
NTFS_VOLUME_DATA_BUFFER vol_data;
HANDLE vol = GetVolumeData(L"\\??\\D:", vol_data);
if (vol != INVALID_HANDLE_VALUE)
{
int64 vdl = GetFileValidData(alloc_test->getOsHandle(), vol, vol_data);
if(vdl>=0) { [...] }
[...]
}
[...]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.