/**********************************************************************/
/*                                                                    */
/* verify - Version 1.2                                               */
/*                                                                    */
/* January 15 1989 - Joel Swank
/* This program is freely copyable and distributable.                 */
/*                                                                    */
/* Directory Search taken from Rodney Lewis' Find program.            */
/*                                                                    */
/*                                                                    */
/**********************************************************************/

/**********************************************************************/
/*                                                                    */
/* verify  - searches the directory hierachy reading all files.  Any  */
/*           files that cannot be read in entirity are reported on    */
/*           stdout.                                                  */
/*                                                                    */
/**********************************************************************/

#include <exec/types.h>
#include <exec/memory.h>
#include <libraries/dosextens.h>
#include <stdio.h>
#include <functions.h>
#include <fcntl.h>
#include "verify.h"

#define BUFSIZE 8192L

int breakflag = FALSE;

char *buf = NULL;
char path[80] = "";				/* memory to hold full path name */
char vfmsg[] = "Verify Fail: ";
int goodct = 0, badct = 0;


main(argc, argv)
int argc;
char *argv[];
{
	register struct FileLock *start;
	register i;

	if (argc < 2) {
		fprintf(stderr,"Usage:verify path . . .\n");
		fprintf(stderr,"Read all files in all directories\n");
		exit(1);
		}

	/* search each path-name specified */

	for (i = 1 ; i < argc; i++)
		{
		if (argv[i][0] == '.' && argv[i][1] == '\0')
			{		/* add '.' for cwd JHS 9-21-88 */
			struct Process *MyProcess;
			MyProcess = (struct Process *) FindTask(0L);
			start = DupLock(MyProcess->pr_CurrentDir);
			}
		else start = Lock(argv[i], ACCESS_READ);
		if (start == NULL) {
			fprintf(stderr, "verify: can't access '%s'\n", argv[i]);
			continue;
			}

		search(start);
		pwd(start);
		fprintf(stdout,"%s\n",path);
		fprintf(stdout,"%d Good Files\n",goodct);
		fprintf(stdout,"%d Bad Files\n",badct);
		goodct = 0; badct = 0;
		path[0] = '\0';
		UnLock(start);
		}

	if (buf)
		FreeMem(buf, BUFSIZE);
	exit(0);
}

/* search the given directory and read each file
 * 
 */

search(lock)
register struct FileLock *lock;
{
	register struct FileInfoBlock *fib;
	register struct FileLock *nlock = NULL, *par = NULL;
	char *prev, file[200];
	int Err;

	fib = (struct FileInfoBlock *) AllocMem((long)
		sizeof(struct FileInfoBlock), MEMF_CLEAR);
	if (fib == NULL) {
		fprintf(stderr, "verify: can't allocate file info block\n");
		return(0);
	}

	/* save current position in full path name */

	prev = path + strlen(path);

	if (*path == '\0' && pwd(par = ParentDir(lock)) == 0) {
		FreeMem(fib, (long) sizeof(struct FileInfoBlock));
		return(0);
	}

	if (par) UnLock(par); /* JHS 12/3/89 */

	/* examine initial path name */

	if (Examine(lock, fib)) {


		if (fib->fib_DirEntryType > 0) {

			/* set up printable path name */

			if (*path) {
				strcat(path, fib->fib_FileName);
				strcat(path, "/");
			}
			else if (pwd(lock) == 0) {
				*prev = '\0';
				FreeMem(fib, (long) sizeof(struct FileInfoBlock));
				return(0);
			}
		}

		else {

			/* if initial path name is not a directory then we just return */

			*prev = '\0';
			FreeMem(fib, (long) sizeof(struct FileInfoBlock));
			fprintf(stderr, "verify: not a directory - %s\n", file);
			return(0);
		}

		/* examine directory contents */

		while(ExNext(lock, fib)) {
			if (breakflag) break;

			/* recurse if we have found a directory */

			strcpy(file, path);
			strcat(file, fib->fib_FileName);
			if (fib->fib_DirEntryType > 0) {
				nlock = Lock(file, ACCESS_READ);
				if (nlock == NULL)
					fprintf(stderr, "verify: locking error - %s\n", file);
				else {
					search(nlock);
					UnLock(nlock);
				}
			}
			else
				read_file(file);

			if (SetSignal(0L, 0L) & SIGBREAKF_CTRL_C) {
				breakflag = TRUE;
				break;
			}
		}
		Err = (int) IoErr();
		if (Err != ERROR_NO_MORE_ENTRIES)
			fprintf(stderr, "verify: directory error - %s\n", path);
	}else 
		fprintf(stderr, "verify: directory error - %s\n", path);


	*prev = '\0';
	FreeMem(fib, (long) sizeof(struct FileInfoBlock));
}

/*
 *  read the file described by path and fib->fib_FileName
 */

read_file(file)
char *file;
{
	int ret;
  	struct FileHandle *f1;

	if (buf == NULL) {    /* get buffer first time only */
		buf = (char *)AllocMem(BUFSIZE, MEMF_PUBLIC|MEMF_CLEAR);
		if (buf == NULL) {
			fprintf(stderr,"verify: No memory for buffers\n");
			return;
			}
		}


	f1 = Open(file, MODE_OLDFILE);

	if (f1 == NULL) {
		fputs(vfmsg,stderr);
		ierror(file,205);
		return;
		badct++;
		}

	while ((ret = Read(f1, buf, BUFSIZE)) > 0L );

	if (ret < 0)
		{
		int Err = (int) IoErr();
		fputs(vfmsg,stderr);
		ierror(file, Err);
		badct++;
		}
	else  goodct++;

	Close(f1);


}


/* find the full path name of the given lock */

pwd(dir)
register struct FileLock *dir;
{
	register struct FileLock *par = NULL;
	register struct FileInfoBlock *fib;

	if (dir == NULL) {
		*path = '\0';
		return(1);
	}

	fib = (struct FileInfoBlock *) AllocMem((long)
			sizeof(struct FileInfoBlock), MEMF_CLEAR);
	if (fib == NULL) {
		fprintf(stderr, "verify: can't allocate a FileInfoBlock\n");
		return(0);
	}

	if (!Examine(dir, fib)) {
		fprintf(stderr, "verify: examine failed\n");
		FreeMem(fib, (long) sizeof(struct FileInfoBlock));
		return(0);
	}

	if (par = ParentDir(dir)) {

		/* find full path name of parent */

		if (pwd(par) == 0) {
			UnLock(par); /* JHS 12/3/89 */
			FreeMem(fib, (long) sizeof(struct FileInfoBlock));
			return(0);
		}

		/* add current name */

		strcat(path, fib->fib_FileName);
		strcat(path, "/");
		UnLock(par); /* JHS 12/3/89 */
	}
	else {

		/* found the root name */

		strcpy(path, fib->fib_FileName);
		strcat(path, ":");
	}

	FreeMem(fib, (long) sizeof(struct FileInfoBlock));
	return(1);
}

 
/*
 *   Matt Dillons error routines
 */

 
ierror(str, err)
register char *str;
int err;
{
   register struct PERROR *per = Perror;
 
   if (err > 0) {
      for (; per->errstr; ++per) {
         if (per->errnum == err) {
            fprintf (stderr, "%s%s%s\n",
        	  per->errstr,
        	  (str) ? ": " : "",
        	  (str) ? str : "");
            return;
        }
      }
      fprintf (stderr, "Unknown DOS error %d %s\n", err, (str) ? str : "");
   }
   return;
}
 
