如何获得有效数据长度"一个档案?

时间:2016-02-23 08:52:13

标签: c windows winapi ntfs

有一个功能设置"有效数据长度"价值:SetFileValidData,但我找不到获取"有效数据长度的方法"值。

如果EOF与VDL不同,我想知道给定的文件,因为在VDL<EOF的情况下在VDL之后写入将导致性能损失,如here所述。

4 个答案:

答案 0 :(得分:1)

我认为你对什么&#34;有效数据长度&#34;感到困惑。实际上意味着。检查this answer

基本上,虽然SetEndOfFile允许您快速增加文件的长度,并分配磁盘空间,但如果跳到(新)文件结尾写入,则所有额外分配的磁盘空间需要用零覆盖,这有点慢。

SetFileValidData可让您跳过归零。你告诉系统,&#34;我对这些磁盘块中的任何内容都没关系,继续使用它&#34;。 (这就是为什么你需要SE_MANAGE_VOLUME_NAME特权,因为如果你不覆盖数据,它可以向非特权用户显示特权数据。 这个特权的用户可以访问原始驱动器无论如何数据。)

在任何一种情况下,您都设置了文件的新有效大小。 (你可以回读。)确切地说,应该一个单独的&#34;读取文件有效数据&#34;报告回来? SetFileValidData 告诉系统这些磁盘块中的任何内容 &#34;有效&#34; ...

不同的解释方法:

documentation提到&#34;有效数据长度&#34;正在跟踪 ;这样做的目的是让系统在{{1}的上下文中知道它仍然需要归零的范围(从有效结束数据到结束文件)。必要时(例如关闭文件)。 不需要回读此值,因为它与实际文件 size 的唯一方式不同是因为您,你自己,确实通过上述功能改变了它......

答案 1 :(得分:0)

SetValidData(根据MSDN)可用于创建例如大文件而无需写入文件。对于数据库,这将分配一个(连续的)存储区域。

结果,似乎磁盘上的文件大小已经改变,而没有任何数据写入文件。

通过暗示,任何GetValidData(不存在)只返回文件的大小,因此您可以使用GetFileSize返回“有效”文件大小。

答案 2 :(得分:0)

我找到了this页面,声称:

  

没有机制来查询VDL的值

所以答案是“你不能”。

如果您关心性能,可以将VDL设置为EOF,但请注意,您可以允许访问磁盘上的旧垃圾 - 这两个指针之间的部分,如果您不访问该文件则应该为零将VDL设置为指向EOF。

答案 3 :(得分:0)

对此进行了调查。无法通过任何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) { [...] }
        [...]
    }
[...]