got basic mft parsing

This commit is contained in:
Itay Almog 2021-09-03 18:24:22 +03:00
parent eced64231d
commit 10caa22bbc
2 changed files with 189 additions and 30 deletions

View File

@ -7,8 +7,39 @@
#include <lib/part.h>
#include <lib/blib.h>
struct ntfs_bpb {
uint8_t jump[3];
char oem[8];
uint16_t bytes_per_sector;
uint8_t sectors_per_cluster;
uint16_t reserved_sectors;
uint8_t fats_count;
uint16_t directory_entries_count;
uint16_t sector_totals;
uint8_t media_descriptor_type;
uint16_t sectors_per_fat_16;
uint16_t sectors_per_track;
uint16_t heads_count;
uint32_t hidden_sectors_count;
uint32_t large_sectors_count;
// ntfs
uint32_t sectors_per_fat_32;
uint64_t sectors_count_64;
uint64_t mft_cluster;
} __attribute__((packed));
struct ntfs_file_handle {
struct volume *part;
struct ntfs_bpb bpb;
uint8_t mft_run_list[256];
uint8_t root_run_list[128];
uint8_t resident_index[256];
uint8_t attribute_list[256];
uint64_t mft_offset;
uint32_t size_bytes;
};

View File

@ -1,31 +1,77 @@
#include <fs/ntfs.h>
struct ntfs_bpb {
uint8_t jump[3];
char oem[8];
uint16_t bytes_per_sector;
uint8_t sectors_per_cluster;
uint16_t reserved_sectors;
uint8_t fats_count;
uint16_t directory_entries_count;
uint16_t sector_totals;
uint8_t media_descriptor_type;
uint16_t sectors_per_fat_16;
uint16_t sectors_per_track;
uint16_t heads_count;
uint32_t hidden_sectors_count;
uint32_t large_sectors_count;
// ntfs
uint32_t sectors_per_fat_32;
uint64_t sectors_count_64;
uint64_t mft_cluster;
#include <lib/print.h>
#include <stdbool.h>
struct mft_file_record {
char name[4];
uint16_t update_seq_offset;
uint16_t update_seq_size;
uint64_t log_seq_number;
uint16_t sequence_number;
uint16_t hard_link_count;
uint16_t attribute_offset;
uint16_t flags;
uint32_t real_size;
uint32_t allocated_size;
uint64_t base_record_number;
} __attribute__((packed));
struct file_record_attr_header {
uint32_t type;
uint32_t length;
uint8_t non_res_flag;
uint8_t name_length;
uint16_t name_offset;
uint16_t flags;
uint16_t attribute_id;
} __attribute__((packed));
#define FR_ATTRIBUTE_LIST 0x00000020
#define FR_ATTRIBUTE_NAME 0x00000030
#define FR_ATTRIBUTE_VOLUME_NAME 0x00000060
#define FR_ATTRIBUTE_DATA 0x00000080
#define FR_ATTRIBUTE_INDEX_ROOT 0x00000090
#define FR_ATTRIBUTE_INDEX_ALLOC 0x000000A0
struct file_record_attr_header_res {
struct file_record_attr_header header;
uint32_t info_length;
uint16_t info_offset;
uint16_t index_flag;
} __attribute__((packed));
struct file_record_attr_header_non_res {
struct file_record_attr_header header;
uint64_t first_vcn;
uint64_t last_vcn;
uint16_t run_offset;
} __attribute__((packed));
struct index_entry {
uint64_t mft_record;
uint16_t entry_size;
uint16_t name_offset;
uint16_t index_Flag;
uint16_t padding;
uint64_t mft_parent_record;
uint64_t creation_time;
uint64_t altered_time;
uint64_t mft_changed_time;
uint64_t read_time;
uint64_t alloc_size;
uint64_t real_size;
uint64_t file_flags;
uint8_t name_length;
uint8_t name_type;
wchar_t name[];
} __attribute__((packed));
int ntfs_check_signature(struct volume *part) {
struct ntfs_bpb bpb = { 0 };
if (volume_read(part, &bpb, 0, sizeof(bpb))) {
return 1;
struct ntfs_bpb bpb;
if (!volume_read(part, &bpb, 0, sizeof(bpb))) {
return 0;
}
//
@ -33,29 +79,111 @@ int ntfs_check_signature(struct volume *part) {
//
if (strncmp(bpb.oem, "NTFS ", SIZEOF_ARRAY(bpb.oem))) {
return 1;
return 0;
}
if (bpb.sector_totals != 0) {
return 1;
return 0;
}
if (bpb.large_sectors_count != 0) {
return 1;
return 0;
}
if (bpb.sectors_count_64 == 0) {
return 1;
return 0;
}
// this is a valid ntfs sector
return 0;
return 1;
}
/**
* Read the the directory's file record from the mft
*/
// static int ntfs_read_directory(struct ntfs_file_handle *handle, uint64_t mft_record, char *file_record) {
// }
/**
* Get an attribute from the given file record
*/
static bool ntfs_get_file_record_attr(uint8_t* file_record, uint32_t attr_type, uint8_t **out_attr) {
struct mft_file_record *fr = (struct mft_file_record *)file_record;
// get the offset to the first attribute
uint8_t* cur_attr_ptr = file_record + fr->attribute_offset;
while (true) {
if (cur_attr_ptr + sizeof(struct file_record_attr_header) > file_record + 4096)
panic("File record attribute is outside of file record");
struct file_record_attr_header *cur_attr = (struct file_record_attr_header *)cur_attr_ptr;
if (cur_attr->type == attr_type) {
*out_attr = cur_attr_ptr;
return true;
}
// we either found an attr with higher type or the end type
if (cur_attr->type > attr_type || cur_attr->type == 0xFF)
return false;
if (cur_attr->length == 0)
panic("File record attribute has zero length");
cur_attr_ptr += cur_attr->length;
}
}
/**
* Prepare for reading a file by reading the root directory into the file handle
*/
static void ntfs_read_root(struct ntfs_file_handle *handle) {
// calculate the offset for the mft
handle->mft_offset = (uint64_t)handle->bpb.mft_cluster * (uint64_t)handle->bpb.sectors_per_cluster * (uint64_t)handle->bpb.bytes_per_sector;
// read the mft file record, this should be the size of a sector
// but we will use 4096 since it should cover it
uint8_t file_record_buffer[4096];
if (!volume_read(handle->part, file_record_buffer, handle->mft_offset, sizeof(file_record_buffer)))
panic("Failed to read MFT file record");
// get the file attribute
struct file_record_attr_header_non_res *attr;
if (!ntfs_get_file_record_attr(file_record_buffer, FR_ATTRIBUTE_DATA, (uint8_t **)&attr))
panic("MFT file record missing DATA attribute");
// verify the attr and run list are in the buffer
if ((uint8_t *)attr + sizeof(*attr) > file_record_buffer + sizeof(file_record_buffer))
panic("MFT file record attribute is outside of file record");
if ((uint8_t *)attr + attr->run_offset + 256 > file_record_buffer + sizeof(file_record_buffer))
panic("MFT Run list is outside of file record");
// save the run list
memcpy(handle->mft_run_list, (uint8_t *)attr + attr->run_offset, sizeof(handle->mft_run_list));
// TODO: read the root directory
}
// static int ntfs_find_file_in_directory(char *dir, size_t dir_size, short *name, struct index_entry* entry) {
// }
int ntfs_open(struct ntfs_file_handle *ret, struct volume *part, const char *path) {
(void)ret;
(void)part;
// save the part
ret->part = part;
// start by reading the bpb so we can access it later on
if (!volume_read(part, &ret->bpb, 0, sizeof(ret->bpb)))
panic("Failed to read the BPB");
// now prepare the root directory so we can search for
// the rest of the stuff
ntfs_read_root(ret);
// TODO: search for the file we want
(void)path;
return 1;
}