/*
 *  ntfs.h
 *
 *  Copyright (C) 1995 Martin von Löwis
 */

#include <linux/types.h>

/* This is really unsigned long long. So we support only volumes up to 2 TB */
typedef unsigned int ntfs_cluster_t;

struct ntfs_inode;

typedef struct _ntfs_volume{
	int blocksize;
	int clusterfactor;
	int clustersize;
	int mft_recordsize;
	int mft_clusters_per_record;
	int index_recordsize;
	int index_clusters_per_record;
	int mft_cluster;
	unsigned char *mft;
	uid_t uid;
	gid_t gid;
	umode_t umask;
	unsigned short *upcase;
	unsigned int upcase_length;
	int partition_bias;	/* for access to underlying device */
	/* inodes we always hold onto */
	struct ntfs_inode *mft_ino;
	union{
		int fd;		/* file descriptor for the tools */
		void *sb;	/* pointer to super block for the kernel */
	}u;
}ntfs_volume;

#define NTFS_FD(vol)	((vol)->u.fd)
#define NTFS_SB(vol)	((struct super_block*)(vol)->u.sb)
#define NTFS_SB2VOL(sb)	((ntfs_volume*)(sb)->u.generic_sbp)
#define NTFS_INO2VOL(ino)	((ntfs_volume*)((ino)->i_sb->u.generic_sbp))

typedef struct {
	ntfs_cluster_t cluster;
	ntfs_cluster_t len;
}ntfs_runlist;

typedef struct {
	int type;
	int *name;
	int namelen;
	unsigned char header[0x40]; /* XXX */
	union{
		void *data;             /* if resident */
		struct {
			ntfs_runlist *runlist;
			int len;
		}r;
	}d;
}ntfs_attribute;

typedef struct ntfs_inode{
	ntfs_volume *vol;
	int i_number;
	unsigned char* attr;
	int attr_count;
	ntfs_attribute *attrs;
	int record_count;
	int *records;
}ntfs_inode;

typedef struct {
	ntfs_volume *vol;
	ntfs_inode *ino;
	int type;
	char *name;
	int mftno;
	int start_vcn;
} ntfs_attrlist_item;

typedef void* (*copyfunction)(void*,const void*,size_t);

#define AT_STANDARD_INFORMATION	0x10
#define AT_ATTRIBUTE_LIST		0x20
#define AT_FILE_NAME			0x30
#define AT_VOLUME_VERSION		0x40
#define AT_SECURITY_DESCRIPTOR	0x50
#define AT_VOLUME_NAME			0x60
#define AT_VOLUME_INFORMATION	0x70
#define AT_DATA					0x80
#define AT_INDEX_ROOT			0x90
#define AT_INDEX_ALLOCATION		0xA0
#define AT_BITMAP				0xB0
#define AT_SYMBOLIC_LINK		0xC0
#define AT_EA_INFORMATION		0xD0
#define AT_EA					0xE0

#define FILE_MFT				0
#define FILE_MFTMIRR			1
#define FILE_LOGFILE			2
#define FILE_VOLUME				3
#define FILE_ATTRDEF			4
#define FILE_ROOT				5
#define FILE_BITMAP				6
#define FILE_BOOT				7
#define FILE_BADCLUS			8
#define FILE_QUOTA				9
#define FILE_UPCASE				10

extern ntfs_volume *the_vol;

void print_time(long long*);

/* Volume management */
void ntfs_init_volume(ntfs_volume *vol,char *boot);
int ntfs_load_special_files(ntfs_volume*);
void ntfs_init_upcase(ntfs_inode *upcase);
int ntfs_open_volume(char*, int, int, int);

/* MFT records */
int ntfs_read_mft_record(ntfs_volume *vol,int mftno,char *buf);
int ntfs_init_inode(ntfs_inode *ino,ntfs_volume* vol,int inum);
void ntfs_clear_inode(ntfs_inode *ino);
void ntfs_load_attributes(ntfs_inode* ino);

/* Attribute list */
int ntfs_find_in_attr_list(ntfs_attrlist_item *,int );
int ntfs_get_attr_size(ntfs_inode *ino,int attr,char*name);
int ntfs_attr_is_resident(ntfs_inode *ino,int attr,char*name);
ntfs_attribute* ntfs_find_attr(ntfs_inode *ino,int type,char *name);

/* attribute data */
char *ntfs_get_attr(ntfs_inode *inode,int attr,char *name);
int ntfs_read_attr(ntfs_inode *ino,int attr,
	char *name,int offset,char *buf,int length,copyfunction);
int ntfs_modify_attr(ntfs_inode *ino,int attr,
	char *name,int offset,char *buf,int length,copyfunction);
int ntfs_write_attr(ntfs_inode *ino,int attr,
    char *name,int offset,char *buf,int l,copyfunction pmemcpy);
int ntfs_readwrite_attr(ntfs_inode *ino,int attr,
	char *name,int offset,char *buf,int length,copyfunction,int do_read);

/* block access */
int decompress_run(unsigned char** data,int* length,int *cluster,int *ctype);
int ntfs_vcn_to_lcn(ntfs_inode*,int);
int ntfs_getput_clusters(ntfs_volume *vol,int start_cluster,size_t start_offs,
	size_t length,void *buf,copyfunction,int do_read);

/* directory access */
int ntfs_get_name(char*,char*);
int ntfs_getdir_byposition(ntfs_inode *ino,long long *num,char *ret);
int ntfs_getdir_byname(ntfs_inode*ino,const char *name,
	int namelen,char *ret);
void dumpdir(ntfs_inode*);
void list_attr_mem(char*);
time_t ntfs_ntutc2unixutc(long long);
void ntfs_uni2ascii(char*,char*,int);
void *ntfs_malloc(int size);
int ntfs_fixup_record(ntfs_volume*,char *record,int count);
int ntfs_check_index_record(ntfs_volume*,char *record);
int ntfs_check_mft_record(ntfs_volume*,char *record);
int ntfs_get_volumesize(ntfs_volume *);
int ntfs_get_free_cluster_count(ntfs_inode *bitmap);
int ntfs_get_free_inode_count(ntfs_volume *,char*mft);
void* ntfs_memcpy(void*a,const void*b,size_t);
void ntfs_decompress(unsigned char*dst, unsigned char*src,size_t len);

#define min(a,b)	((a) <= (b) ? (a) : (b))
#define max(a,b)	((a) >= (b) ? (a) : (b))
#define RESIDENT(attr)	(*((char*)(attr)+8)=='\0')
#define COMPRESSED(attr)	(*((char*)(attr)+0xC)!='\0')
#define DATASIZE(attr)	\
	(RESIDENT(attr)?*(short*)((char*)(attr)+0x10):*(int*)((char*)(attr)+0x30))
#define IS_MAGIC(a,b)	(*(int*)(a)==*(int*)(b))
#define IS_MFT_RECORD(a)	IS_MAGIC((a),"FILE")
#define IS_NTFS_VOLUME(a)	IS_MAGIC((a)+3,"NTFS")
#define IS_INDEX_RECORD(a)	IS_MAGIC((a),"INDX")

/* 'NTFS' in little endian */
#define NTFS_SUPER_MAGIC	0x5346544E
