/*  FileCheck.c

    Usage: FileCheck <Path>

    Function: FileCheck reads ALL files in <Path> and sub-directories.
		It is designed to find out whether there are faults
		in the file-structure of the OFS on disk
		(These can't be found by DiskCopy for there is no
		trackdisk-fault, but Checksum-Errors produced by OFS).	*/

#include <exec/libraries.h>
#include <exec/memory.h>
#include <exec/types.h>
#include <dos/dos.h>
#include <dos/exall.h>
#include <dos/dostags.h>
#include <ctype.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define READBUFFSIZE (488*512/8)    /* das kleinste gemeinsame Vielfache
				       von 512 und 488, den Blockgrößen
				       von altem FS und FFS */

APTR ReadBuffer;
BOOL abort;

BOOL CheckBreak(void)
{
    if(SetSignal(0,SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)
	{
	printf("^C\n");
	abort=TRUE;
	}
    return(abort);
}

void Check(STRPTR name, long size)
{
    register BPTR FH;
    register long toget;
    long gotten, really_read;

    printf("\r%s  [%ld]\233K", name, size); fflush(stdout);
    FH=Open(name,MODE_OLDFILE);
    if(FH==NULL)    { printf(" - Open-Error !\n"); return; }
    for(toget=gotten=0;gotten<size;gotten+=toget)
	{
	toget=size-gotten;
	if(toget>READBUFFSIZE)  toget=READBUFFSIZE;
	really_read=Read(FH,ReadBuffer,toget);
	if(really_read!=toget)
	    {
	    printf(" - Read-Error near position %ld\n",gotten+really_read);
	    break;
	    }
	if(CheckBreak())    break;
	}
    Close(FH);
}

void tree(STRPTR fullname)
{
    struct FileInfoBlock *eintrag;
    BPTR lock;
    char *newfullname, *to_append;
    short newfn_len=strlen(fullname) + sizeof(eintrag->fib_FileName) + 2;

    if(!(lock=Lock(fullname,ACCESS_READ)))
	{
	printf("Error: couldn't lock %s\n", fullname);
	return;
	}
    if(eintrag=(struct FileInfoBlock *)
	AllocMem(sizeof(struct FileInfoBlock),MEMF_CLEAR))
	{
	if(Examine(lock,eintrag))
	    {
	    if(eintrag->fib_DirEntryType>0)
		{
		if(newfullname=AllocMem(newfn_len, MEMF_CLEAR) )
		    {
		    strcpy(newfullname,fullname);
		    if(fullname[0] && fullname[strlen(fullname)-1]!=':')
			strcat(newfullname,"/");
		    to_append=newfullname+strlen(newfullname);
		    ExNext(lock,eintrag);
		    while(IoErr()!=ERROR_NO_MORE_ENTRIES && !CheckBreak())
			{
			strcpy(to_append,eintrag->fib_FileName);
			if(eintrag->fib_DirEntryType<=0)
			     {
			     if(eintrag->fib_Protection & FIBF_READ)
				  printf("\rFile %s is read protected\n",
					 newfullname);
			     else Check(newfullname, eintrag->fib_Size);
			     }
			else tree(newfullname);
			ExNext(lock,eintrag);
			}
		    FreeMem(newfullname, newfn_len);
		    }
		else printf("no memory for full filename\n");
		}
	    }
	else printf("Error in Examine()'ing %s\n", fullname);
	FreeMem(eintrag, sizeof(struct FileInfoBlock));
	}
    else printf("Error: can't allocate a FIB\n");
    UnLock(lock);
}

int main(short argc, STRPTR argv[])
{
    BPTR OrgCD, BaseDir;

    if(argc!=2)
	{
	printf("Usage: %s <path>\n",argv[0]);
	return(RETURN_ERROR);
	}
    abort=FALSE;
    if(!(ReadBuffer=AllocMem(READBUFFSIZE,MEMF_PUBLIC)))
	{
	printf("Error: couldn't allocate %ld Bytes of Buffer\n",
	       READBUFFSIZE);
	return(RETURN_ERROR);
	}

    if((BaseDir=Lock(argv[1], ACCESS_READ))==NULL)
	printf("Error: couldn't lock %s\n", argv[1]);
    else{
	OrgCD=CurrentDir(BaseDir);
	tree("");
	CurrentDir(OrgCD);
	UnLock(BaseDir);
	printf("\r\233K");
	fflush(stdout);
	}

    FreeMem(ReadBuffer,READBUFFSIZE);
    return(RETURN_OK);
}
