From ab60ce09495d2ff036255548f94dcf9b969d841f Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Fri, 8 Jul 2011 00:57:26 +0000 Subject: [PATCH] ntfs: implement for_each_mft_record() macro Walk through the MFT records from a given block number. Also add more NTFS-specific structures that'll be used in turn. Signed-off-by: Paulo Alcantara --- core/fs/ntfs/ntfs.c | 14 ++ core/fs/ntfs/ntfs.h | 468 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 482 insertions(+) diff --git a/core/fs/ntfs/ntfs.c b/core/fs/ntfs/ntfs.c index de73f38..e476fab 100644 --- a/core/fs/ntfs/ntfs.c +++ b/core/fs/ntfs/ntfs.c @@ -28,6 +28,14 @@ #include "codepage.h" #include "ntfs.h" +#define for_each_mft_record(fs, data, block) \ + for ((data) = get_right_block((fs), (block)); \ + (block) < NTFS_SB((fs))->mft_size && \ + ((const MFT_RECORD *)(data))->magic == NTFS_MAGIC_FILE; \ + (block) += ((const MFT_RECORD *)(data))->bytes_allocated >> \ + BLOCK_SHIFT((fs)), \ + (data) = get_right_block((fs), (block))) + /* Check if there are specific zero fields in an NTFS boot sector */ static inline int ntfs_check_zero_fields(const struct ntfs_bpb *sb) { @@ -55,6 +63,12 @@ static inline struct inode *new_ntfs_inode(struct fs_info *fs) return inode; } +static inline const void *get_right_block(struct fs_info *fs, + block_t block) +{ + return get_cache(fs->fs_dev, NTFS_SB(fs)->mft + block); +} + /* Initialize the filesystem metadata and return block size in bits */ static int ntfs_fs_init(struct fs_info *fs) { diff --git a/core/fs/ntfs/ntfs.h b/core/fs/ntfs/ntfs.h index 7e392c0..9c7de0f 100644 --- a/core/fs/ntfs/ntfs.h +++ b/core/fs/ntfs/ntfs.h @@ -93,4 +93,472 @@ struct ntfs_inode { sector_t here; /* Sector corresponding to offset */ }; +/* System defined attributes (32-bit) + * Each attribute type has a corresponding attribute name (in Unicode) + */ +enum { + NTFS_AT_UNUSED = 0x00, + NTFS_AT_STANDARD_INFORMATION = 0x10, + NTFS_AT_ATTR_LIST = 0x20, + NTFS_AT_FILENAME = 0x30, + NTFS_AT_OBJ_ID = 0x40, + NTFS_AT_SECURITY_DESCP = 0x50, + NTFS_AT_VOL_NAME = 0x60, + NTFS_AT_VOL_INFO = 0x70, + NTFS_AT_DATA = 0x80, + NTFS_AT_INDEX_ROOT = 0x90, + NTFS_AT_INDEX_ALLOCATION = 0xA0, + NTFS_AT_BITMAP = 0xB0, + NTFS_AT_REPARSE_POINT = 0xC0, + NTFS_AT_EA_INFO = 0xD0, + NTFS_AT_EA = 0xE0, + NTFS_AT_PROPERTY_SET = 0xF0, + NTFS_AT_LOGGED_UTIL_STREAM = 0x100, + NTFS_AT_FIRST_USER_DEFINED_ATTR = 0x1000, + NTFS_AT_END = 0xFFFFFFFF, +}; + +/* NTFS File Permissions (also called attributes in DOS terminology) */ +enum { + NTFS_FILE_ATTR_READONLY = 0x00000001, + NTFS_FILE_ATTR_HIDDEN = 0x00000002, + NTFS_FILE_ATTR_SYSTEM = 0x00000004, + NTFS_FILE_ATTR_DIRECTORY = 0x00000010, + NTFS_FILE_ATTR_ARCHIVE = 0x00000020, + NTFS_FILE_ATTR_DEVICE = 0x00000040, + NTFS_FILE_ATTR_NORMAL = 0x00000080, + NTFS_FILE_ATTR_TEMPORARY = 0x00000100, + NTFS_FILE_ATTR_SPARSE_FILE = 0x00000200, + NTFS_FILE_ATTR_REPARSE_POINT = 0x00000400, + NTFS_FILE_ATTR_COMPRESSED = 0x00000800, + NTFS_FILE_ATTR_OFFLINE = 0x00001000, + NTFS_FILE_ATTR_NOT_CONTENT_INDEXED = 0x00002000, + NTFS_FILE_ATTR_ENCRYPTED = 0x00004000, + NTFS_FILE_ATTR_VALID_FLAGS = 0x00007FB7, + NTFS_FILE_ATTR_VALID_SET_FLAGS = 0x000031A7, + NTFS_FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT = 0x10000000, + NTFS_FILE_ATTR_DUP_VIEW_INDEX_PRESENT = 0x20000000, +}; + +/* The collation rules for sorting views/indexes/etc (32-bit) */ +enum { + NTFS_COLLATION_BINARY = 0x00, + NTFS_COLLATION_FILE_NAME = 0x01, + NTFS_COLLATION_UNICODE_STRING = 0x02, + NTFS_COLLATION_NTOFS_ULONG = 0x10, + NTFS_COLLATION_NTOFS_SID = 0x11, + NTFS_COLLATION_NTOFS_SECURITY_HASH = 0x12, + NTFS_COLLATION_NTOFS_ULONGS = 0x13, +}; + +/* + * Magic identifiers present at the beginning of all ntfs record containing + * records (like mft records for example). + */ +enum { + /* Found in $MFT/$DATA */ + NTFS_MAGIC_FILE = 0x454C4946, /* MFT entry */ + NTFS_MAGIC_INDX = 0x58444E49, /* Index buffer */ + NTFS_MAGIC_HOLE = 0x454C4F48, + + /* Found in $LogFile/$DATA */ + NTFS_MAGIC_RSTR = 0x52545352, + NTFS_MAGIC_RCRD = 0x44524352, + /* Found in $LogFile/$DATA (May be found in $MFT/$DATA, also ?) */ + NTFS_MAGIC_CHKDSK = 0x444B4843, + /* Found in all ntfs record containing records. */ + NTFS_MAGIC_BAAD = 0x44414142, + NTFS_MAGIC_EMPTY = 0xFFFFFFFF, /* Record is empty */ +}; + +typedef struct { + uint32_t magic; + uint16_t usa_ofs; + uint16_t usa_count; +} __attribute__((packed)) NTFS_RECORD; + +/* The $MFT metadata file types */ +typedef enum { + FILE_MFT = 0, + FILE_MFTMirr = 1, + FILE_LogFile = 2, + FILE_Volume = 3, + FILE_AttrDef = 4, + FILE_root = 5, + FILE_Bitmap = 6, + FILE_Boot = 7, + FILE_BadClus = 8, + FILE_Secure = 9, + FILE_UpCase = 10, + FILE_Extend = 11, + FILE_reserved12 = 12, + FILE_reserved13 = 13, + FILE_reserved14 = 14, + FILE_reserved15 = 15, + FILE_reserved16 = 16, +} NTFS_SYSTEM_FILES; + +/* MFT record flags */ +enum { + MFT_RECORD_IN_USE = 0x0001, + MFT_RECORD_IS_DIRECTORY = 0x0002, +} __attribute__((packed)); + +typedef struct { + uint32_t magic; + uint16_t usa_ofs; + uint16_t usa_count; + uint64_t lsn; + uint16_t seq_no; + uint16_t link_count; + uint16_t attrs_offset; + uint16_t flags; /* MFT record flags */ + uint32_t bytes_in_use; + uint32_t bytes_allocated; + uint64_t base_mft_record; + uint16_t next_attr_instance; + uint16_t reserved; + uint32_t mft_record_no; +} __attribute__((packed)) MFT_RECORD; /* 48 bytes */ + +/* This is the version without the NTFS 3.1+ specific fields */ +typedef struct { + uint32_t magic; + uint16_t usa_ofs; + uint16_t usa_count; + uint64_t lsn; + uint16_t seq_no; + uint16_t link_count; + uint16_t attrs_offset; + uint16_t flags; /* MFT record flags */ + uint32_t bytes_in_use; + uint32_t bytes_allocated; + uint64_t base_mft_record; + uint16_t next_attr_instance; +} __attribute__((packed)) MFT_RECORD_OLD; /* 42 bytes */ + +enum { + ATTR_DEF_INDEXABLE = 0x02, + ATTR_DEF_MULTIPLE = 0x04, + ATTR_DEF_NOT_ZERO = 0x08, + ATTR_DEF_INDEXED_UNIQUE = 0x10, + ATTR_DEF_NAMED_UNIQUE = 0x20, + ATTR_DEF_RESIDENT = 0x40, + ATTR_DEF_ALWAYS_LOG = 0x80, +}; + +typedef struct { + uint16_t name[0x40]; + uint32_t type; + uint32_t display_rule; + uint32_t collation_rule; + uint32_t flags; /* Attr def flags */ + uint64_t min_size; + uint64_t max_size; +} __attribute__((packed)) ATTR_DEF; + +/* Attribute flags (16-bit) */ +enum { + ATTR_IS_COMPRESSED = 0x0001, + ATTR_COMPRESSION_MASK = 0x00FF, + + ATTR_IS_ENCRYPTED = 0x4000, + ATTR_IS_SPARSE = 0x8000, +} __attribute__((packed)); + +/* Flags of resident attributes (8-bit) */ +enum { + RESIDENT_ATTR_IS_INDEXED = 0x01, +} __attribute__((packed)); + +typedef struct { + uint32_t type; /* Attr. type code */ + uint32_t len; + uint8_t non_resident; + uint8_t name_len; + uint16_t name_offset; + uint16_t flags; /* Attr. flags */ + uint16_t instance; + union { + struct { /* Resident attribute */ + uint32_t value_len; + uint16_t value_offset; + uint8_t flags; /* Flags of resident attributes */ + int8_t reserved; + } __attribute__((packed)) resident; + struct { /* Non-resident attributes */ + uint64_t lowest_vcn; + uint64_t highest_vcn; + uint16_t mapping_pairs_offset; + uint8_t compression_unit; + uint8_t reserved[5]; + int64_t allocated_size; + int64_t initialized_size; + int64_t compressed_size; + } __attribute__((packed)) non_resident; + } __attribute__((packed)) data; +} __attribute__((packed)) ATTR_RECORD; + +/* Attribute: Standard Information (0x10) + * Note: always resident + */ +typedef struct { + int64_t ctime; + int64_t atime; + int64_t mtime; + int64_t rtime; + uint32_t file_attrs; + union { + struct { /* NTFS 1.2 (48 bytes) */ + uint8_t reserved12[12]; + } __attribute__((packed)) v1; + struct { /* NTFS 3.x (72 bytes) */ + uint32_t max_version; + uint32_t version; + uint32_t class_id; + uint32_t owner_id; + uint32_t sec_id; + uint64_t quota_charged; + int64_t usn; + } __attribute__((packed)) v3; + } __attribute__((packed)) ver; +} __attribute__((packed)) STANDARD_INFORMATION; + +/* Attribute: Attribute List (0x20) + * Note: can be either resident or non-resident + */ +typedef struct { + uint32_t type; + uint16_t len; + uint8_t name_len; + uint8_t name_offset; + uint64_t lowest_vcn; + uint64_t mft_ref; + uint16_t instance; + uint16_t name[0]; /* Name in Unicode */ + /* sizeof() = 26 + (attribute_name_length * 2) bytes */ +} __attribute__((packed)) ATTR_LIST_ENTRY; + +#define NTFS_MAX_FILE_NAME_LEN 255 + +/* Possible namespaces for filenames in ntfs (8-bit) */ +enum { + FILE_NAME_POSIX = 0x00, + FILE_NAME_WIN32 = 0x01, + FILE_NAME_DOS = 0x02, + FILE_NAME_WIN32_AND_DOS = 0x03, +} __attribute__((packed)); + +/* Attribute: Filename (0x30) + * Note: always resident + */ +typedef struct { + uint64_t parent_directory; + int64_t ctime; + int64_t atime; + int64_t mtime; + int64_t rtime; + uint64_t allocated_size; + uint64_t data_size; + uint32_t file_attrs; + union { + struct { + uint16_t packed_ea_size; + uint16_t reserved; /* reserved for alignment */ + } __attribute__((packed)) ea; + struct { + uint32_t reparse_point_tag; + } __attribute__((packed)) rp; + } __attribute__((packed)) type; + uint8_t file_name_len; + uint8_t file_name_type; + uint16_t file_name[0]; /* File name in Unicode */ +} __attribute__((packed)) FILE_NAME_ATTR; + +/* GUID structure */ +typedef struct { + uint32_t data0; + uint16_t data1; + uint16_t data2; + uint8_t data3[8]; +} __attribute__((packed)) GUID; + +typedef struct { + uint64_t mft_ref; + union { + struct { + GUID birth_vol_id; + GUID birth_obj_id; + GUID domain_id; + } __attribute__((packed)) origin; + uint8_t extended_info[48]; + } __attribute__((packed)) opt; +} __attribute__((packed)) OBJ_ID_INDEX_DATA; + +/* Attribute: Object ID (NTFS 3.0+) (0x40) + * Note: always resident + */ +typedef struct { + GUID object_id; + union { + struct { + GUID birth_vol_id; + GUID birth_obj_id; + GUID domain_id; + } __attribute__((packed)) origin; + uint8_t extended_info[48]; + } __attribute__((packed)) opt; +} __attribute__((packed)) OBJECT_ID_ATTR; + +/* Attribute: Volume Name (0x60) + * Note: always resident + * Note: Present only in FILE_volume + */ +typedef struct { + uint16_t name[0]; /* The name of the volume in Unicode */ +} __attribute__((packed)) VOLUME_NAME; + +/* Volume flags (16-bit) */ +enum { + VOLUME_IS_DIRTY = 0x0001, + VOLUME_RESIZE_LOG_FILE = 0x0002, + VOLUME_UPGRADE_ON_MOUNT = 0x0004, + VOLUME_MOUNTED_ON_NT4 = 0x0008, + + VOLUME_DELETE_USN_UNDERWAY = 0x0010, + VOLUME_REPAIR_OBJECT_ID = 0x0020, + + VOLUME_CHKDSK_UNDERWAY = 0x4000, + VOLUME_MODIFIED_BY_CHKDSK = 0x8000, + + VOLUME_FLAGS_MASK = 0xC03F, + + VOLUME_MUST_MOUNT_RO_MASK = 0xC027, +} __attribute__((packed)); + +/* Attribute: Volume Information (0x70) + * Note: always resident + * Note: present only in FILE_Volume + */ +typedef struct { + uint64_t reserved; + uint8_t major_ver; + uint8_t minor_ver; + uint16_t flags; /* Volume flags */ +} __attribute__((packed)) VOLUME_INFORMATION; + +/* Attribute: Data attribute (0x80) + * Note: can be either resident or non-resident + */ +typedef struct { + uint8_t data[0]; +} __attribute__((packed)) DATA_ATTR; + +/* Index header flags (8-bit) */ +enum { + SMALL_INDEX = 0, + LARGE_INDEX = 1, + LEAF_NODE = 0, + INDEX_NODE = 1, + NODE_MASK = 1, +} __attribute__((packed)); + +/* Header for the indexes, describing the INDEX_ENTRY records, which + * follow the INDEX_HEADER. + */ +typedef struct { + uint32_t entries_offset; + uint32_t index_len; + uint32_t allocated_size; + uint8_t flags; /* Index header flags */ + uint8_t reserved[3]; /* Align to 8-byte boundary */ +} __attribute__((packed)) INDEX_HEADER; + +/* Attribute: Index Root (0x90) + * Note: always resident + */ +typedef struct { + uint32_t type; /* It is $FILE_NAME for directories, zero for view indexes. + * No other values allowed. + */ + uint32_t collation_rule; + uint32_t index_block_size; + uint8_t clust_per_index_block; + uint8_t reserved[3]; + INDEX_HEADER index; +} __attribute__((packed)) INDEX_ROOT; + +/* Attribute: Index allocation (0xA0) + * Note: always non-resident, of course! :-) + */ +typedef struct { + uint32_t magic; + uint16_t usa_ofs; /* Update Sequence Array offsets */ + uint16_t usa_count; /* Update Sequence Array number in bytes */ + int64_t lsn; + int64_t index_block_vcn; /* Virtual cluster number of the index block */ + INDEX_HEADER index; +} __attribute__((packed)) INDEX_BLOCK; + +typedef INDEX_BLOCK INDEX_ALLOCATION; + +enum { + INDEX_ENTRY_NODE = 1, + INDEX_ENTRY_END = 2, + /* force enum bit width to 16-bit */ + INDEX_ENTRY_SPACE_FILTER = 0xFFFF, +} __attribute__((packed)); + +typedef struct { + union { + struct { /* Only valid when INDEX_ENTRY_END is not set */ + uint64_t indexed_file; + } __attribute__((packed)) dir; + struct { /* Used for views/indexes to find the entry's data */ + uint16_t data_offset; + uint16_t data_len; + uint32_t reservedV; + } __attribute__((packed)) vi; + } __attribute__((packed)) data; + uint16_t len; + uint16_t key_len; + uint16_t flags; /* Index entry flags */ + uint16_t reserved; /* Align to 8-byte boundary */ +} __attribute__((packed)) INDEX_ENTRY_HEADER; + +typedef struct { + union { + struct { /* Only valid when INDEX_ENTRY_END is not set */ + uint64_t indexed_file; + } __attribute__((packed)) dir; + struct { /* Used for views/indexes to find the entry's data */ + uint16_t data_offset; + uint16_t data_len; + uint32_t reservedV; + } __attribute__((packed)) vi; + } __attribute__((packed)) data; + uint16_t len; + uint16_t key_len; + uint16_t flags; /* Index entry flags */ + uint16_t reserved; /* Align to 8-byte boundary */ + union { + FILE_NAME_ATTR file_name; + //SII_INDEX_KEY sii; + //SDH_INDEX_KEY sdh; + //GUID object_id; + //REPARSE_INDEX_KEY reparse; + //SID sid; + uint32_t owner_id; + } __attribute__((packed)) key; +} __attribute__((packed)) INDEX_ENTRY; + +typedef struct { + uint8_t bitmap[0]; /* Array of bits */ +} __attribute__((packed)) BITMAP_ATTR; + +static inline struct ntfs_sb_info *NTFS_SB(struct fs_info *fs) +{ + return fs->fs_info; +} + #endif /* _NTFS_H_ */ -- 2.7.4