/*
 *  ntfstools.c
 *  Helper functions for the tools
 *  Copyright (C) 1995 Martin von Löwis
 */

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

ntfs_volume *the_vol;
ntfs_volume myvol;

/* pmemcpy is ignored here */
int ntfs_getput_clusters(ntfs_volume *pvol,int cluster,size_t offs,
	size_t count,void *buf,copyfunction pmemcpy,int do_read)
{
	if(lseek(NTFS_FD(pvol),
		pvol->partition_bias+cluster*pvol->clustersize+offs,SEEK_SET)==-1)
		return 0;
	if(do_read)
		return read(NTFS_FD(pvol),buf,count)!=-1;
	else
		return write(NTFS_FD(pvol),buf,count)!=-1;
}

void ntfs_release_cluster(void *data)
{
	free(data);
}

int open_volume(char *name)
{
	int fd=open(name,O_RDWR);
	if(fd==-1 && errno==EACCES){
		fprintf(stderr,"RW denied, trying RO\n");
		fd=open(name,O_RDONLY);
	}
	if(fd==-1)
	{
		perror("open");
		exit(0);
	}
	return fd;
}

void ntfs_error(char*s,int a1,int a2,int a3,int a4,int a5)
{
	fprintf(stderr,s,a1,a2,a3,a4,a5);
	fputs("",stderr);
}

void ntfs_debug(char*s,int a1,int a2,int a3,int a4,int a5)
{}

void *ntfs_malloc(int size)
{
	return malloc(size);
}

void ntfs_free(void *block)
{
	free(block);
}

int ntfs_open_volume(char *file,int bias,int silent,int no_inodes)
{
	int fd;
	char cluster0[512];
	the_vol=&myvol;
	myvol.partition_bias=bias;
	NTFS_FD(the_vol)=fd=open_volume(file=file?file:NTFS_VOLUME);
	if(fd<0)
	{	
		return 0;
	}
	/* read the boot sector */
	ntfs_getput_clusters(the_vol,0,0,512,cluster0,memcpy,1);
	if(!IS_NTFS_VOLUME(cluster0)){
		fprintf(stderr,"Not a NTFS volume:%s\n",file);
		return 0;
	}
	ntfs_init_volume(the_vol,cluster0);
	/* read the first mft record */
	the_vol->mft=malloc(the_vol->mft_recordsize);
	ntfs_getput_clusters(the_vol,the_vol->mft_cluster,0,
		the_vol->mft_recordsize,the_vol->mft,memcpy,1);
	/* fix it */
	if(!ntfs_check_mft_record(the_vol,the_vol->mft)){
		fprintf(stderr,"MFT record not at cluster 0x%X\n",the_vol->mft_cluster);
		return 0;
	}
	if(!silent)
	fprintf(stderr,"MFT record at block 0x%X, offset 0x%X\n",the_vol->mft_cluster,
		the_vol->mft_cluster*the_vol->clustersize);
	if(!no_inodes)
	{
		ntfs_inode upcase;
		ntfs_load_special_files(the_vol);
		ntfs_init_inode(&upcase,the_vol,FILE_UPCASE);
		ntfs_init_upcase(&upcase);
		ntfs_clear_inode(&upcase);
	}
	return 1;
}

int ntfs_read_mft_record(ntfs_volume *vol,int mftno,char *buf)
{
	/* record 0 of file 0 is always in memory */
	if(mftno==0)
	{
		memcpy(buf,vol->mft,vol->mft_recordsize);
		return 0;
	}
	if(!vol->mft_ino)
	{
		fprintf(stderr,"Cannot load mft %x without mft 0\n",mftno);
		return -1;
	}
	if(!ntfs_read_attr(vol->mft_ino,AT_DATA,NULL,
		mftno*vol->mft_recordsize,
		buf,vol->mft_recordsize,memcpy))
		return -1;
	if(!ntfs_check_mft_record(vol,buf))
	{
		fprintf(stderr,"Inode not found\n");
		return -1;
	}
	return 0;
}

void *ntfs_memcpy(void*a,const void*b,size_t n)
{
	return memcpy(a,b,n);
}

void *ntfs_memset(void*a,int c,size_t len)
{
	return (void*)memset(a,c,len);
}

int ntfs_strlen(char *s)
{
	return strlen(s);
}
