/*
 *  ntdump.c
 *
 *  Copyright (C) 1995 Martin von Löwis
 */

#include <stdio.h>
#include <getopt.h>
#include <unistd.h>
#include "ntfs.h"
#include "config.h"
/* glibc string.h does not define a memcpy prototype */
void* memcpy(void*,const void*,size_t);

char *short_opts="vrdf:o:c:Mi:ID:B:A:N:nh";
struct option options[]={
	{"raw",0,0,'r'},
	{"filesystem",1,0,'f'},
	{"offset",1,0,'o'},
	{"cluster",1,0,'c'},
	{"mft",0,0,'M'},
	{"inode",1,0,'i'},
	{"dir",0,0,'d'},
	{"info",0,0,'I'},
	{"decompress",1,0,'D'},
	{"verbose",0,0,'v'},
	{"bias",1,0,'B'},
	{"attribute-type",1,0,'A'},
	{"attribute-name",1,0,'N'},
	{"linode",0,0,'n'},
	{"help",0,0,'h'}
};

void usage()
{
	fprintf(stderr,"ntdump: prints low-level structures of an NTFS\n"
		"  --filesystem, -f device  Use device\n"
		"  --raw, -r                Access the raw device\n"
		"  --offset, -o n           Start at offset o\n"
		"  --cluster, -c n          Start at cluster n\n"
		"  --mft, -M                Display as master file table record\n"
		"  --inode, -i n            Display inode n\n"
		"  --dir, -d                Display as directory\n"
		"  --info, -I               Display file system information\n"
		"  --decompress, -D n       Decompress run n\n"
		"  --bias, -B n             Add partition bias n [bytes]\n"
		"  --attribute-type, -A n   Dump type n\n"
		"  --attribute-name, -N str Dump attribute named str\n"
		"  --verbose, -v            decompress verbose\n"
		"  --linode, -n             show internal inode representation\n"
	);
}

int main(int argc,char *argv[])
{
	int c,with_ino;
	int raw=0,as_mft=0,as_dir=0,inode=0,use_ino=0,get_info=0,cluster=0;
	int decompress=0,verbose=0,bias=0,as_inode=0;
	int attribute_type=AT_DATA;
	char *attribute_name=0;
	char *device=0;
	int offset=0;
	opterr=1;
	while((c=getopt_long(argc,argv,short_opts,options,NULL))>0)
	switch(c)
	{
		case 'r': raw=1;break;
		case 'f': device=optarg;break;
		case 'o': offset=strtol(optarg,NULL,0);break;
		case 'c': cluster=strtol(optarg,NULL,0);break;
		case 'M': as_mft=1;break;
		case 'i': inode=strtol(optarg,NULL,0);use_ino=1;break;
		case 'd': as_dir=1;break;
		case 'I': get_info=1;break;
		case 'D': decompress=1;offset=strtol(optarg,NULL,0);break;
		case 'v': verbose=1;break;
		case 'B': bias=strtol(optarg,NULL,0);break;
		case 'A': attribute_type=strtol(optarg,NULL,0);break;
		case 'N': attribute_name=optarg;break;
		case 'n': as_inode=1;break;
		default:
			usage();
			exit(1);
	}
	with_ino = use_ino || get_info;
	if(!ntfs_open_volume(device,bias,0,!with_ino) && !raw)return 1;
	if(cluster)
		offset=the_vol->clustersize*cluster;
	if(use_ino){
		ntfs_inode ino;
		ntfs_init_inode(&ino,the_vol,inode);
		if(as_mft){
			list_attr_mem(ino.attr);
			return 0;
		}
		if(as_dir){
			dumpdir(&ino);
			return 0;
		}
		if(as_inode){
			dump_inode(&ino);
			return 0;
		}
		if(decompress){
			dump_decompress(ino.attr,offset,verbose);
			return 0;
		}
		while(1)
		{
			char buf[4096];
			int r=ntfs_read_attr(&ino,
				attribute_type,attribute_name,
				offset,buf,the_vol->clustersize,memcpy);
			if(r==-1)return 0;
			dump_mem(buf,offset,the_vol->clustersize);
			offset+=r;
			if(r<the_vol->clustersize)return 0;
		}
		return 0;
	}
	if(raw)
	{
		dump(offset+bias,offset,-1);
	}else if(as_mft)
	{
		list_attributes(offset);
	}else if(get_info)
	{
		ntfs_inode ino;
		printf("Total clusters: %d\n",ntfs_get_volumesize(the_vol));
		ntfs_init_inode(&ino,the_vol,FILE_BITMAP);
		printf("Free clusters:  %d\n",
			ntfs_get_free_cluster_count(&ino));
	}else{
		usage();
	}
	return 0;
}

