/* 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

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)

#define GRUB_NTFS_ATTRIBUTE_HEADER_SIZE 16

/*
 * To make attribute validation clearer the offsets for each value in the
 * attribute headers are defined as macros.
 *
 * These offsets are all from:
 * https://flatcap.github.io/linux-ntfs/ntfs/concepts/attribute_header.html
 */

/* These offsets are part of the attribute header. */
#define GRUB_NTFS_ATTRIBUTE_LENGTH      4
#define GRUB_NTFS_ATTRIBUTE_RESIDENT    8
#define GRUB_NTFS_ATTRIBUTE_NAME_LENGTH 9
#define GRUB_NTFS_ATTRIBUTE_NAME_OFFSET 10

/* Offsets for values needed for resident data. */
#define GRUB_NTFS_ATTRIBUTE_RES_LENGTH  16
#define GRUB_NTFS_ATTRIBUTE_RES_OFFSET  20

/* Offsets for values needed for non-resident data. */
#define GRUB_NTFS_ATTRIBUTE_DATA_RUNS             32
#define GRUB_NTFS_ATTRIBUTE_COMPRESSION_UNIT_SIZE 34

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

enum
  {
    GRUB_NTFS_RF_BLNK		= 1
  };

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;

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;
  grub_uint8_t *end;
  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 */
