/* ntfs.h - header for the NTFS filesystem */
/*
 *  GRUB  --  GRand Unified Bootloader
 *  Copyright (C) 2007,2009  Free Software Foundation, Inc.
 *
 *  GRUB 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 3 of the License, or
 *  (at your option) any later version.
 *
 *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef GRUB_NTFS_H
#define GRUB_NTFS_H	1

#include <grub/types.h>
#include <grub/disk.h>

enum
{
	GRUB_NTFS_FILE_MFT = 0,
	GRUB_NTFS_FILE_MFTMIRR = 1,
	GRUB_NTFS_FILE_LOGFILE = 2,
	GRUB_NTFS_FILE_VOLUME = 3,
	GRUB_NTFS_FILE_ATTRDEF = 4,
	GRUB_NTFS_FILE_ROOT = 5,
	GRUB_NTFS_FILE_BITMAP = 6,
	GRUB_NTFS_FILE_BOOT = 7,
	GRUB_NTFS_FILE_BADCLUS = 8,
	GRUB_NTFS_FILE_QUOTA = 9,
	GRUB_NTFS_FILE_UPCASE = 10,
};

enum
{
	GRUB_NTFS_AT_STANDARD_INFORMATION = 0x10,
	GRUB_NTFS_AT_ATTRIBUTE_LIST = 0x20,
	GRUB_NTFS_AT_FILENAME = 0x30,
	GRUB_NTFS_AT_OBJECT_ID = 0x40,
	GRUB_NTFS_AT_SECURITY_DESCRIPTOR = 0x50,
	GRUB_NTFS_AT_VOLUME_NAME = 0x60,
	GRUB_NTFS_AT_VOLUME_INFORMATION = 0x70,
	GRUB_NTFS_AT_DATA = 0x80,
	GRUB_NTFS_AT_INDEX_ROOT = 0x90,
	GRUB_NTFS_AT_INDEX_ALLOCATION = 0xA0,
	GRUB_NTFS_AT_BITMAP = 0xB0,
	GRUB_NTFS_AT_SYMLINK = 0xC0,
	GRUB_NTFS_AT_EA_INFORMATION = 0xD0,
	GRUB_NTFS_AT_EA = 0xE0,
};

enum
{
	GRUB_NTFS_ATTR_READ_ONLY = 0x1,
	GRUB_NTFS_ATTR_HIDDEN = 0x2,
	GRUB_NTFS_ATTR_SYSTEM = 0x4,
	GRUB_NTFS_ATTR_ARCHIVE = 0x20,
	GRUB_NTFS_ATTR_DEVICE = 0x40,
	GRUB_NTFS_ATTR_NORMAL = 0x80,
	GRUB_NTFS_ATTR_TEMPORARY = 0x100,
	GRUB_NTFS_ATTR_SPARSE = 0x200,
	GRUB_NTFS_ATTR_REPARSE = 0x400,
	GRUB_NTFS_ATTR_COMPRESSED = 0x800,
	GRUB_NTFS_ATTR_OFFLINE = 0x1000,
	GRUB_NTFS_ATTR_NOT_INDEXED = 0x2000,
	GRUB_NTFS_ATTR_ENCRYPTED = 0x4000,
	GRUB_NTFS_ATTR_DIRECTORY = 0x10000000,
	GRUB_NTFS_ATTR_INDEX_VIEW = 0x20000000
};

enum
{
	GRUB_NTFS_FLAG_COMPRESSED = 1,
	GRUB_NTFS_FLAG_ENCRYPTED = 0x4000,
	GRUB_NTFS_FLAG_SPARSE = 0x8000
};

#define GRUB_NTFS_BLK_SHR		GRUB_DISK_SECTOR_BITS

#define GRUB_NTFS_MAX_MFT		(4096 >> GRUB_NTFS_BLK_SHR)
#define GRUB_NTFS_MAX_IDX		(16384 >> GRUB_NTFS_BLK_SHR)

#define GRUB_NTFS_COM_LEN		4096
#define GRUB_NTFS_COM_LOG_LEN	12
#define GRUB_NTFS_COM_SEC		(GRUB_NTFS_COM_LEN >> GRUB_NTFS_BLK_SHR)
#define GRUB_NTFS_LOG_COM_SEC		(GRUB_NTFS_COM_LOG_LEN - GRUB_NTFS_BLK_SHR)

enum
{
	GRUB_NTFS_AF_ALST = 1,
	GRUB_NTFS_AF_MMFT = 2,
	GRUB_NTFS_AF_GPOS = 4,
};

enum
{
	GRUB_NTFS_RF_BLNK = 1
};

GRUB_PACKED_START
struct grub_ntfs_bpb
{
	grub_uint8_t jmp_boot[3];
	grub_uint8_t oem_name[8];
	grub_uint16_t bytes_per_sector;
	grub_uint8_t sectors_per_cluster;
	grub_uint8_t reserved_1[7];
	grub_uint8_t media;
	grub_uint16_t reserved_2;
	grub_uint16_t sectors_per_track;
	grub_uint16_t num_heads;
	grub_uint32_t num_hidden_sectors;
	grub_uint32_t reserved_3;
	grub_uint8_t bios_drive;
	grub_uint8_t reserved_4[3];
	grub_uint64_t num_total_sectors;
	grub_uint64_t mft_lcn;
	grub_uint64_t mft_mirr_lcn;
	grub_int8_t clusters_per_mft;
	grub_int8_t reserved_5[3];
	grub_int8_t clusters_per_index;
	grub_int8_t reserved_6[3];
	grub_uint64_t num_serial;
	grub_uint32_t checksum;
};
GRUB_PACKED_END

struct grub_ntfs_attr
{
	int flags;
	grub_uint8_t* emft_buf, * edat_buf;
	grub_uint8_t* attr_cur, * attr_nxt, * attr_end;
	grub_uint32_t save_pos;
	grub_uint8_t* sbuf;
	struct grub_ntfs_file* mft;
};

struct grub_ntfs_file
{
	struct grub_ntfs_data* data;
	grub_uint8_t* buf;
	grub_uint64_t size;
	grub_uint64_t mtime;
	grub_uint64_t ino;
	int inode_read;
	struct grub_ntfs_attr attr;
};

struct grub_ntfs_data
{
	struct grub_ntfs_file cmft;
	struct grub_ntfs_file mmft;
	grub_disk_t disk;
	grub_uint64_t mft_size;
	grub_uint64_t idx_size;
	int log_spc;
	grub_uint64_t mft_start;
	grub_uint64_t uuid;
};

struct grub_ntfs_comp_table_element
{
	grub_uint32_t next_vcn;
	grub_uint32_t next_lcn;
};

struct grub_ntfs_comp
{
	grub_disk_t disk;
	int comp_head, comp_tail;
	struct grub_ntfs_comp_table_element comp_table[16];
	grub_uint32_t cbuf_ofs, cbuf_vcn;
	int log_spc;
	grub_uint8_t* cbuf;
};

struct grub_ntfs_rlst
{
	int flags;
	grub_disk_addr_t target_vcn, curr_vcn, next_vcn, curr_lcn;
	grub_uint8_t* cur_run;
	struct grub_ntfs_attr* attr;
	struct grub_ntfs_comp comp;
	void* file;
};

typedef grub_err_t(*grub_ntfscomp_func_t) (grub_uint8_t* dest,
	grub_disk_addr_t ofs,
	grub_size_t len,
	struct grub_ntfs_rlst* ctx);

extern grub_ntfscomp_func_t grub_ntfscomp_func;

grub_err_t grub_ntfs_read_run_list(struct grub_ntfs_rlst* ctx);

#endif /* ! GRUB_NTFS_H */
