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

#include <stdio.h>
#include <fcntl.h>
#include "ntfs.h"
#include "config.h"

void ntfs_init_volume(ntfs_volume *vol,char *boot)
{
	vol->blocksize=*(unsigned short*)(boot+0xB);
	vol->clusterfactor=*(unsigned char*)(boot+0xD);
	vol->mft_clusters_per_record=*(unsigned int*)(boot+0x40);
	vol->index_clusters_per_record=*(unsigned int*)(boot+0x44);

	vol->clustersize=vol->blocksize*vol->clusterfactor;
	vol->mft_recordsize=vol->clustersize*vol->mft_clusters_per_record;
	vol->index_recordsize=vol->clustersize*vol->index_clusters_per_record;
	/* BUGBUG: long long value */
	vol->mft_cluster=*(int*)(boot+0x30);
	vol->upcase=0;
	vol->upcase_length=0;
	/* this will be initialized later */
	vol->mft_ino=0;
}

int ntfs_load_special_files(ntfs_volume *vol)
{
	vol->mft_ino=(ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode));
	if(!vol->mft_ino || ntfs_init_inode(vol->mft_ino,vol,FILE_MFT)==-1)
	{
		ntfs_error("Problem loading MFT\n");
		return -1;
	}
	return 0;
}

void ntfs_init_upcase(ntfs_inode *upcase)
{
#define UPCASE_LENGTH  256
	upcase->vol->upcase = ntfs_malloc(2*UPCASE_LENGTH);
	upcase->vol->upcase_length = UPCASE_LENGTH;
	ntfs_read_attr(upcase,AT_DATA,NULL,0,
		(char*)upcase->vol->upcase,2*UPCASE_LENGTH,ntfs_memcpy);
}

int ntfs_get_volumesize(ntfs_volume *vol)
{
	char *cluster0=ntfs_malloc(vol->clustersize);
	int size;
	ntfs_getput_clusters(vol,0,0,vol->clustersize,cluster0,ntfs_memcpy,1);
	size=*(int*)(cluster0+0x28);
	ntfs_free(cluster0);
	return size;
}

static int nc[16]={4,3,3,2,3,2,2,1,3,2,2,1,2,1,1,0};

int ntfs_get_free_cluster_count(ntfs_inode *bitmap)
{
	unsigned char bits[2048];
	int l,offset;
	int clusters=0;
	offset=0;
	while(1)
	{
		register int i;
		l=ntfs_read_attr(bitmap,AT_DATA,NULL,offset,bits,2048,ntfs_memcpy);
		if(l==0)break;
		if(l<0 || l>2048)return 0; /* something wrong here */
		/* I never thought I would do loop unrolling some day */
		for(i=0;i<l-8;){
			clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF];
			clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF];
			clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF];
			clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF];
			clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF];
			clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF];
			clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF];
			clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF];
		}
		for(;i<l;){
			clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF];
		}
		offset+=l;
	}
	return clusters;
}
		
