#pragma once #include "index.hpp" #include namespace wl { struct DataRun { uint64_t vcn = 0, clusters = 0; int64_t lcn = 0; }; struct RecordInfo { uint64_t id = 0, base_id = 0, size = 0, modified = 0, created = 0, accessed = 0; uint32_t attributes = 0; uint16_t link_count = 0; uint32_t filename_attribute_count = 0; bool in_use = false, has_attribute_list = false; std::vector> names; std::vector extension_ids; std::vector data_runs; }; bool fixup_record(std::span record, uint32_t sector_size); RecordInfo parse_record(std::span record, uint64_t record_number); std::vector parse_runs(std::span data, uint64_t first_vcn); class NtfsReader { public: explicit NtfsReader(wchar_t drive); std::shared_ptr scan(const std::function& cancelled); std::vector read_links(uint64_t id); bool poll(Volume& volume); uint64_t serial() const { return serial_; } USN_JOURNAL_DATA_V0 journal() const; private: Handle handle_; std::string root_; uint32_t sector_size_ = 512, cluster_size_ = 4096, record_size_ = 1024; uint64_t serial_ = 0, mft_length_ = 0; std::vector mft_runs_; std::unordered_map pending_updates_; uint64_t pending_from_ = UINT64_MAX; std::vector read_at(uint64_t offset, size_t bytes) const; std::vector raw_record(uint64_t index) const; std::vector get_record(uint64_t id) const; void expand_attribute_list(std::span record, RecordInfo& info) const; }; std::vector ntfs_drives(); }