[英]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.