blob: 721a78d7859f6b0623e00b6fc25e88837a92d161 [file] [log] [blame]
/*
* Copyright (C) 2011-2012 Paulo Alcantara <pcacjr@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "runlist.h"
#ifndef _NTFS_H_
#define _NTFS_H_
struct ntfs_bpb {
uint8_t jmp_boot[3];
char oem_name[8];
uint16_t sector_size;
uint8_t sec_per_clust;
uint16_t res_sectors;
uint8_t zero_0[3];
uint16_t zero_1;
uint8_t media;
uint16_t zero_2;
uint16_t unused_0;
uint16_t unused_1;
uint32_t unused_2;
uint32_t zero_3;
uint32_t unused_3;
uint64_t total_sectors;
uint64_t mft_lclust;
uint64_t mft_mirr_lclust;
int8_t clust_per_mft_record;
uint8_t unused_4[3];
uint8_t clust_per_idx_record;
uint8_t unused_5[3];
uint64_t vol_serial;
uint32_t unused_6;
uint8_t pad[428]; /* padding to a sector boundary (512 bytes) */
} __attribute__((__packed__));
/* Function type for an NTFS-version-dependent MFT record lookup */
struct ntfs_mft_record;
typedef struct ntfs_mft_record *f_mft_record_lookup(struct fs_info *,
uint32_t, block_t *);
struct ntfs_sb_info {
block_t mft_blk; /* The first MFT record block */
uint64_t mft_lcn; /* LCN of the first MFT record */
unsigned mft_size; /* The MFT size in sectors */
uint64_t mft_record_size; /* MFT record size in bytes */
uint8_t clust_per_idx_record; /* Clusters per Index Record */
unsigned long long clusters; /* Total number of clusters */
unsigned clust_shift; /* Based on sectors */
unsigned clust_byte_shift; /* Based on bytes */
unsigned clust_mask;
unsigned clust_size;
uint8_t major_ver; /* Major version from $Volume */
uint8_t minor_ver; /* Minor version from $Volume */
/* NTFS-version-dependent MFT record lookup function to use */
f_mft_record_lookup *mft_record_lookup;
} __attribute__((__packed__));
/* The NTFS in-memory inode structure */
struct ntfs_inode {
int64_t initialized_size;
int64_t allocated_size;
unsigned long mft_no; /* Number of the mft record / inode */
uint16_t seq_no; /* Sequence number of the mft record */
uint32_t type; /* Attribute type of this inode */
uint8_t non_resident;
union { /* Non-resident $DATA attribute */
struct { /* Used only if non_resident flags isn't set */
uint32_t offset; /* Data offset */
} resident;
struct { /* Used only if non_resident is set */
struct runlist *rlist;
} non_resident;
} data;
uint32_t start_cluster; /* Starting cluster address */
sector_t start; /* Starting sector */
sector_t offset; /* Current sector offset */
sector_t here; /* Sector corresponding to offset */
};
/* This is structure is used to keep a state for ntfs_readdir() callers.
* As NTFS stores directory entries in a complex way, this is structure
* ends up saving a state required to find out where we must start from
* for the next ntfs_readdir() call.
*/
struct ntfs_readdir_state {
unsigned long mft_no; /* MFT record number */
bool in_idx_root; /* It's true if we're still in the INDEX root */
uint32_t idx_blks_count; /* Number of read INDX blocks */
uint32_t entries_count; /* Number of read INDEX entries */
int64_t last_vcn; /* Last VCN of the INDX block */
};
enum {
MAP_UNSPEC,
MAP_START = 1 << 0,
MAP_END = 1 << 1,
MAP_ALLOCATED = 1 << 2,
MAP_UNALLOCATED = 1 << 3,
MAP_MASK = 0x0000000F,
};
struct mapping_chunk {
uint64_t vcn;
int64_t lcn;
uint64_t len;
uint32_t flags;
};
/* 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,
};
/*
* 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 */
};
struct ntfs_record {
uint32_t magic;
uint16_t usa_ofs;
uint16_t usa_count;
} __attribute__((__packed__)) NTFS_RECORD;
/* The $MFT metadata file types */
enum ntfs_system_file {
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,
};
enum {
MFT_RECORD_IN_USE = 0x0001,
MFT_RECORD_IS_DIRECTORY = 0x0002,
} __attribute__((__packed__));
struct ntfs_mft_record {
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__)); /* 48 bytes */
/* This is the version without the NTFS 3.1+ specific fields */
struct ntfs_mft_record_old {
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__)); /* 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,
};
struct ntfs_attr_record {
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 data_size; /* Byte size of the attribute value.
* Note: it can be larger than
* allocated_size if attribute value is
* compressed or sparse.
*/
int64_t initialized_size;
int64_t compressed_size;
} __attribute__((__packed__)) non_resident;
} __attribute__((__packed__)) data;
} __attribute__((__packed__));
/* Attribute: Attribute List (0x20)
* Note: it can be either resident or non-resident
*/
struct ntfs_attr_list_entry {
uint32_t type;
uint16_t length;
uint8_t name_length;
uint8_t name_offset;
uint64_t lowest_vcn;
uint64_t mft_ref;
uint16_t instance;
uint16_t name[0];
} __attribute__((__packed__));
#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
*/
struct ntfs_filename_attr {
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__));
/* Attribute: Volume Name (0x60)
* Note: always resident
* Note: Present only in FILE_volume
*/
struct ntfs_vol_name {
uint16_t name[0]; /* The name of the volume in Unicode */
} __attribute__((__packed__));
/* Attribute: Volume Information (0x70)
* Note: always resident
* Note: present only in FILE_Volume
*/
struct ntfs_vol_info {
uint64_t reserved;
uint8_t major_ver;
uint8_t minor_ver;
uint16_t flags; /* Volume flags */
} __attribute__((__packed__));
/* Attribute: Data attribute (0x80)
* Note: can be either resident or non-resident
*/
struct ntfs_data_attr {
uint8_t data[0];
} __attribute__((__packed__));
/* 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 struct ntfs_idx_header.
*/
struct ntfs_idx_header {
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__));
/* Attribute: Index Root (0x90)
* Note: always resident
*/
struct ntfs_idx_root {
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];
struct ntfs_idx_header index;
} __attribute__((__packed__));
/* Attribute: Index allocation (0xA0)
* Note: always non-resident, of course! :-)
*/
struct ntfs_idx_allocation {
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 */
struct ntfs_idx_header index;
} __attribute__((__packed__));
enum {
INDEX_ENTRY_NODE = 1,
INDEX_ENTRY_END = 2,
/* force enum bit width to 16-bit */
INDEX_ENTRY_SPACE_FILTER = 0xFFFF,
} __attribute__((__packed__));
struct ntfs_idx_entry_header {
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__));
struct ntfs_idx_entry {
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 {
struct ntfs_filename_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__));
static inline struct ntfs_sb_info *NTFS_SB(struct fs_info *fs)
{
return fs->fs_info;
}
#define NTFS_PVT(i) ((struct ntfs_inode *)((i)->pvt))
#endif /* _NTFS_H_ */