/* Filename:	restore.c
 * Author:		Mark R. Rinfret
 * Date:		08/02/87
 * Description:	Restore processing module for MRBackup
 */


#include <libraries/dosextens.h>
#include <exec/memory.h>
#include <functions.h>

extern char conmsg[];
extern char backpath[], homepath[];
#ifdef DEBUG
extern char debugmsg[];
#endif
extern char destpath[], destvol[];
extern unsigned do_compress;
extern struct DateStamp *since;
extern char srcpath[], srcvol[];

static char fullbackpath[256], fullhomepath[256];

static unsigned home_is_device;		/* true => home is "DH<N>:" */
static char temp[256];

/* Restore files from floppy disk. */

int
Restore()
{
	int status = 0;

	Speak("And away we go!");

	BreakPath(backpath, srcvol, srcpath);

	if (homepath[strlen(homepath)-1] == ':')
		home_is_device = 1;
	else
		home_is_device = 0;

	status = RestoreFile(srcpath);
	if (status == 0) {
		sprintf(conmsg,"Restore completed successfully\n");
		Speak("I have completed my mission successfully.\n");
	}
	else {
		sprintf(conmsg,"Restore terminated with status %d\n",status);
		Speak("Perhaps you should check things out and try it again.\n");
	}
	WriteConsole(conmsg);
}
^L
/* Restore all the files in a directory.
 * Called with:
 *		lock:		lock on the directory
 *		fib:		pointer to file info block
 *		path:		directory pathname (without volume)
 * Returns:
 *		status (0 => success)
 */
int
RestoreDir(lock, fib, path)
	struct Lock *lock; struct FileInfoBlock *fib; char *path;
{
	struct Lock *dirlock = NULL, *filelock = NULL;
	char newpath[256];
	int status = 0;

	strcpy(temp, homepath);
	if (*path) {
		if (!home_is_device) strcat(temp, "/");
		strcat(temp, path);
	}
#ifdef DEBUG
	sprintf(debugmsg,"Checking for directory %s\n",temp);
	DebugWrite(debugmsg);
#endif
	if (!(dirlock = Lock(temp, SHARED_LOCK))) {
		if ((status = IoErr()) == ERROR_OBJECT_NOT_FOUND) {
#ifdef DEBUG
			sprintf(debugmsg,"Creating directory %s\n",temp);
			DebugWrite(debugmsg);
#endif
			if (!(dirlock = CreateDir(temp))) {
				status = IoErr();
				sprintf(conmsg,"Unable to create directory %s: %d\n",
						temp, status);
				TypeAndSpeak(conmsg);
				goto done;
			}
			status = 0;
		}
		else {
			sprintf(conmsg,"RestoreDir cannot lock %s: %d\n",temp, status);
			TypeAndSpeak(conmsg);
			return status;
		}
	}
	if (dirlock) UnLock(dirlock);

	while (ExNext(lock,fib)) {
		strcpy(newpath, path);
		if (*newpath)
			strcat(newpath, "/");
		strcat(newpath, fib->fib_FileName);
		if (status = RestoreFile(newpath)) {

			/* filter out "permissable:" errors */

			if (status == ERROR_OBJECT_IN_USE ||
				status == ERROR_WRITE_PROTECTED)
				status = 0;
			else
				break;
		}
	}
done:
	return status;
}
^L
/* Restore one or more files according to the calling pathname.
 * The path argument does not contain the backup volume name.
 */
int
RestoreFile(path)
	char *path;
{
	struct FileInfoBlock *fib = NULL, *fib2 = NULL;
	UBYTE exists = FALSE, ignore = FALSE;
	struct Lock *lock = NULL;
	USHORT namelength;
	UBYTE savechar;
	int status = 0;

	if (status = CheckStop()) return status;

	if (!(fib = (struct FileInfoBlock *)
		AllocMem((long) sizeof (struct FileInfoBlock), 
					MEMF_PUBLIC | MEMF_CHIP))) {
		TypeAndSpeak("RestoreFile could not allocate FIB!\n");
		return ERROR_NO_FREE_STORE;
	}

	sprintf(fullbackpath, "%s:%s",srcvol,path);
	strcpy(fullhomepath, homepath);
	if (*path) {
		if (!home_is_device) strcat(fullhomepath, "/");
		strcat(fullhomepath, path);
	}

#ifdef DEBUG
		sprintf(conmsg,"fullbackpath = %s\n",fullbackpath);
		DebugWrite(conmsg);
		sprintf(conmsg,"fullhomepath = %s\n",fullhomepath);
		DebugWrite(conmsg);
#endif

	if (!(lock = Lock(fullbackpath, SHARED_LOCK))) {
		status = IoErr();
		sprintf(conmsg, "RestoreFile: can't lock %s: %d\n",
				fullbackpath, status);
		TypeAndSpeak(conmsg);
		goto done;
	}

	if (!Examine(lock, fib)) {
		status = IoErr();
		sprintf(conmsg, "RestoreFile can't examine %s: %d\n", 
				fullbackpath, status);
		TypeAndSpeak(conmsg);
		goto done;
	}

	if (fib->fib_DirEntryType > 0) {	/* path is a directory */
		status = RestoreDir(lock, fib, path);
		UnLock(lock);
		lock = NULL;
	}
	else {
		UnLock(lock);
		lock = NULL;
/*#define NOCOPY*/
#ifndef NOCOPY
		/* If this file exists, then check its modification date.  If
		 * it's newer than the backup, don't replace it.
		 */

		if ((lock = Lock(fullhomepath, SHARED_LOCK))) {

			if (!(fib2 = (struct FileInfoBlock *)
				AllocMem((long) sizeof (struct FileInfoBlock), 
							MEMF_PUBLIC | MEMF_CHIP))) {
				TypeAndSpeak("RestoreFile could not allocate FIB!\n");
				status = ERROR_NO_FREE_STORE;
				goto done;
			}
			Examine(lock, fib2);
			UnLock(lock);
			lock = NULL;
			if (CompareDS(&fib2->fib_Date, &fib->fib_Date) >= 0)
				ignore = TRUE;
		}
		if (ignore) {
			sprintf(conmsg,"Skipping %s.  Current version is newer.\n",
					path);
			TypeAndSpeak(conmsg);
		}
		else {
			if (!do_compress || !IsCompressed(fullhomepath)) {
copyfile:
				sprintf(conmsg,"Copying %s\n", fullbackpath);
				WriteConsole(conmsg);
				status = CopyFile(fullbackpath, fullhomepath);
			}
			else {
				/* truncate the destination pathname (remove ".z") */

				namelength = strlen(fullhomepath);
				fullhomepath[namelength-2] = '\0';
				sprintf(conmsg, "Decompressing %s\n", fullbackpath);
				WriteConsole(conmsg);
				if (decompress(fullbackpath, fullhomepath)) {
					sprintf(conmsg, 
						"Decompression of %s failed - will copy.\n",
						fullbackpath);
					TypeAndSpeak(conmsg);
					/* restore ".z" to name */
					fullhomepath[namelength-2] = '.'; 
					goto copyfile;
				}
				CopyFileDate(fullbackpath, fullhomepath);
			}
		}
#endif
	}
done:
	if (lock) UnLock(lock);
	if (fib) FreeMem(fib, (long) sizeof(struct FileInfoBlock));
	if (fib2) FreeMem(fib2, (long) sizeof(struct FileInfoBlock));
	return ) an(i)stioer thane
