/*
  gestion de quota dans une partition - juil97 - par Sylvain Huet

  Les répertoires sont examines recursivement. Les fichiers en trop sont 
  supprimés, en commencant par ceux dont la date d'acces est la plus ancienne.
  Les fichiers en lecture seule ne sont pas supprimés,(* ainsi que les descendant
  d'un repertoire 'locked' - SUPPRIME A PARTIR DE 1.5*) 
  (par contre leur taille est prise en compte dans le
  calcul global de la taille).
  L'operation s'effectue par étapes chacune séparée d'un seconde.
  Le temps complet est :
  - 1 seconde par fichier parcouru
  - 1 seconde par fichier détruit.
  Le système détruit jusqu'à 128 fichiers par passe.
*/

#include <windows.h>

#include <stdio.h>
#include <io.h>
#include <direct.h>
#include <time.h>
#include <string.h>

#include "../kernel/mmemory.h"
#include "../kernel/vm/mbytec.h"

#define NBQUOTA 128
#define SIZEQUOTA 512
#define QDBG 0

char quotafile[NBQUOTA][SIZEQUOTA];
int quotadate[NBQUOTA];
int quotasize[NBQUOTA];
int quotanxt[NBQUOTA];
int nbfiles;
int youngest;
int globalsize;

void QuotaWait()
{
#if QDBG
#else
	Sleep(1000);
#endif
}

int QuotaIni()
{
	nbfiles=0;
	youngest=-1;
	globalsize=0;
	return 0;
}

int QuotaAdd(char *name,int size,int date)
{
	int i,l,b;

#if QDBG
	printf("add %s\n",name);
#endif
	if (nbfiles==NBQUOTA)
	{
		if (quotadate[youngest]<date) return 0;
	}
	else
	{
		quotanxt[nbfiles]=youngest;
		youngest=nbfiles++;
	}
	strcpy(quotafile[youngest],name);
	quotasize[youngest]=size;
	quotadate[youngest]=date;
	i=youngest;
	l=-1;
	while(((b=quotanxt[i])!=-1)&&(quotadate[b]>date))
	{
		if (l==-1) youngest=b;
		else quotanxt[l]=b;
		l=b;
		quotanxt[i]=quotanxt[b];
		quotanxt[b]=i;
	}
	return 0;
}

int QuotaRev()
{
	int a,b,l;

	a=youngest;
	if (a==-1) return 0;
	l=-1;
	do
	{
		b=quotanxt[a];
		quotanxt[a]=l;
		l=a;
		a=b;
	}
	while(a!=-1);
	youngest=l;
	return 0;
}

int QuotaList()
{
	int i;

	i=youngest;
	while(i!=-1)
	{
		printf("%s %d %s",quotafile[i],quotasize[i],ctime(&quotadate[i]));
		i=quotanxt[i];
	}
	return 0;
}

/*void QuotaDir(char *path)
{
	int res;
	long h;
	struct _finddata_t fileinfo;

	_chdir(path);
	h=_findfirst("*.*",&fileinfo );
	res=h;
	while(res!=-1)
	{
		if (fileinfo.attrib&16)
    		printf(">%s (%d) (%d) %s\n",fileinfo.name,fileinfo.size,fileinfo.time_access,
				ctime(&fileinfo.time_access));
		res=_findnext(h,&fileinfo );
	}
}
*/

int QuotaScan(char *path,int flag)
{
	int res;
	long h;
	struct _finddata_t fileinfo;
	char buf[512];

	sprintf(buf,"%s/*.*",path);
	h=_findfirst(buf,&fileinfo );
	res=h;
	while(res!=-1)
	{
		QuotaWait();
		sprintf(buf,"%s/%s",path,fileinfo.name);
		if (fileinfo.attrib&16)
		{
			if (strcmp(fileinfo.name,".")&&strcmp(fileinfo.name,".."))
			{
/*				if ((!strcmpi(fileinfo.name,"locked"))
					||(!strcmpi(fileinfo.name,"l"))) QuotaScan(buf,0);
				else*/
				QuotaScan(buf,flag);
			}
		}
		else
		{
			globalsize+=fileinfo.size;
			if ((!(fileinfo.attrib&1))&&(flag))
				QuotaAdd(buf,fileinfo.size,fileinfo.time_access);
		}
		res=_findnext(h,&fileinfo );
	}
	if (h!=-1) _findclose(h);
	return 0;
}

int QuotaClean(int szq)
{
	int i,sizeclean;

	sizeclean=0;
	i=youngest;
	while((i!=-1)&&(globalsize-sizeclean>szq))
	{
		QuotaWait();
#if QDBG
		printf("deleting %s %d\n",quotafile[i],globalsize-sizeclean-quotasize[i]);
#else
		DeleteFile(quotafile[i]);
#endif
		sizeclean+=quotasize[i];
		i=quotanxt[i];
	}
	return sizeclean;
}

int QuotaManage(char *path,int szq)
{
	QuotaIni();
	QuotaScan(path,1);
	QuotaRev();
#if QDBG
	QuotaList(path);
	printf("globalsize=%d\n",globalsize);
#endif
	QuotaClean(szq);
	return 0;
}

HANDLE hThread; 
DWORD dwThreadId; 
char quotadirectory[1024];
int quota;

DWORD ThreadFunc(void)
{
	while(1)
	{
		QuotaWait();
		QuotaManage(quotadirectory,quota);
	}
}

int StartQuotaThread (char *path,int size)
{
	if ((path==NULL)||(size<=0)) return -1;
	strcpy(quotadirectory,path);
	quotadirectory[strlen(quotadirectory)-1]=0;
	quota=size;
    hThread = CreateThread( 
        NULL,                        /* no security attributes        */ 
        0,                           /* use default stack size        */ 
        (LPTHREAD_START_ROUTINE) ThreadFunc, /* thread function       */ 
        0,                           /* argument to thread function   */ 
        0,                           /* use default creation flags    */ 
        &dwThreadId);                /* returns the thread identifier */ 
 
    /* Check the return value for success. */ 
    if (hThread == NULL)
	{
		return -1; 
	}
	MMechostr(MSKDEBUG,"start Quota Thread on %s (%d bytes)\n",quotadirectory,quota);
    return 0;
}

/*
int main()
{
	QuotaManage("c:/scol/partition/signed",30096);
	return 0;
}
*/