/*
Auto:		sc <file>
Auto:		Protect <file> ADD P
*/

/* $Revision Header built automatically *************** (do not edit) ************
**
** © Copyright by GuntherSoft
**
** File             : SnakeSYS:CPrgs/Unlock/Unlock.c
** Created on       : Mittwoch, 11.01.95 11:27:56
** Created by       : Kai Iske
** Current revision : V37.0
**
**
** Purpose
** -------
**     This little program removes all the locks from a given
**     directory.
**
** Revision V37.0
** --------------
** created on Mittwoch, 11.01.95 11:27:56  by  Kai Iske.   LogMessage :
**     --- Initial release ---
**
*********************************************************************************/
#define REVISION "37.0"
#define REVDATE  "11.01.95"
#define REVTIME  "11:27:56"
#define AUTHOR   "Kai Iske"
#define VERNUM   37
#define REVNUM   0


#include	<string.h>
#include	<stdlib.h>
#include	<stdarg.h>
#include	<exec/types.h>
#include	<proto/exec.h>
#include	<proto/dos.h>
#include	<exec/memory.h>
#include	<exec/execbase.h>
#include	<dos/dos.h>
#include	<dos/dosextens.h>


/**********************************************************************/
/*                        Version and Template                        */
/**********************************************************************/
static	const char	*Version	= "$VER: UnLock "REVISION" ("REVDATE")\0";
static	const char	*Template	= "DIR/M,SHOW/S";
enum	{OBJECT_ARG, SHOW_ARG, LAST_ARG};




/**********************************************************************/
/*                        Function prototypes                         */
/**********************************************************************/
static ULONG UnLockEntry(char *Pattern, char *NameBuffer, char *SpareBuffer, BOOL Show, BOOL *Error);
static void __stdargs SPrintF(STRPTR buffer, STRPTR formatString,...);
static BOOL ComposeName(BPTR ObjLock, char *NameBuffer, LONG *FileSize);



/**********************************************************************/
/*                           Library bases                            */
/**********************************************************************/
struct	DosLibrary	*DOSBase	= NULL;





/**********************************************************************/
/*                          The main program                          */
/**********************************************************************/
int __saveds DoUnLock(void)
{
	struct	ExecBase	*SysBase	= *((struct ExecBase **)0x4L);
	struct	Process		*MyProc		= (struct Process *)SysBase->ThisTask;
	struct	RDArgs		*RDArgs;
	BPTR			OutHandle;
	APTR			*Args,
				*OldWindow	= NULL;
	char			*Pattern,
				*NameBuffer,
				*SpareBuffer,
				**FromPtr;
	BOOL			Error		= TRUE,
				ShowMode;


		// Ignore startup from WB

	if(!(MyProc->pr_CLI))
	{
		struct	Message	*MyMsg;

		WaitPort(&MyProc->pr_MsgPort);
		MyMsg = GetMsg(&MyProc->pr_MsgPort);
		Disable();
		ReplyMsg(MyMsg);
		return(10);
	}

		// Do the wild thing

	if((DOSBase = (struct DosLibrary *)OpenLibrary("dos.library", 37)))
	{
		OutHandle	= Output();


			// Allocate buffers

		if((Pattern = AllocVec(1024, MEMF_CLEAR)) && (NameBuffer = AllocVec(1024, MEMF_CLEAR)) && (SpareBuffer = AllocVec(1024, MEMF_CLEAR)))
		{
				// Get buffer for ReadArgs()

			if((Args = AllocVec((LAST_ARG * sizeof(ULONG)), MEMF_CLEAR)))
			{
					// Parse commandline

				if((RDArgs = ReadArgs((char *)Template, (LONG *)Args, NULL)))
				{
					Error	= FALSE;

						// Show lock(s)?

					ShowMode	= (BOOL)Args[SHOW_ARG];

						// No object supplied?
						// Try to show locks

					if(!Args[OBJECT_ARG])
						UnLockEntry(NULL, NameBuffer, SpareBuffer, TRUE, &Error);
					else
					{
						FromPtr	= (char **)Args[OBJECT_ARG];

							// Loop through dirs

						while(*FromPtr && !Error)
						{
							char		*NamePtr;

							NamePtr		= *FromPtr;


							if(CheckSignal(SIGBREAKF_CTRL_C))
							{
								FPuts(OutHandle, "\nUnLock: ^C...\n\n");
								break;
							}


								// No Pattern found and no absolute path?
								// This is within the current directory

							if(!ParsePatternNoCase(*FromPtr, Pattern, 1024) && !strchr(*FromPtr, ':'))
							{
								BPTR	TestLock;

									// Try to lock object

								if((TestLock = Lock(*FromPtr, ACCESS_READ)))
								{
									if(ComposeName(TestLock, NameBuffer, NULL))
										NamePtr	= NameBuffer;
									UnLock(TestLock);
								}
							}


								// Create Pattern
								// ...and try to unlock

							if(ParsePatternNoCase(NamePtr, Pattern, 1024) != -1)
							{
								ULONG	NumUnlocked;

								if(!ShowMode)
								{
									Write(OutHandle, NamePtr, strlen(NamePtr));
									Write(OutHandle, "... ", 3);
								}

									// Try to unlock first instance...

								if((NumUnlocked = UnLockEntry(Pattern, NameBuffer, SpareBuffer, ShowMode, &Error)))
								{
										// Unlocked more than once?

									if(NumUnlocked > 1)
									{
										SPrintF(NameBuffer, "%ld times unlocked\n", NumUnlocked);
										FPuts(OutHandle, NameBuffer);
									}
									else
										FPuts(OutHandle, "unlocked\n");
								}
								else
								{
									if(!ShowMode)
										FPuts(OutHandle, "not unlocked; wasn`t locked\n");
								}
							}
							else
								PrintFault(IoErr(), "\nUnLock ");

								// Next directory

							FromPtr++;
						}
					}

					FreeArgs(RDArgs);
				}
				else
					PrintFault(IoErr(), "\nUnLock ");

					// Free Argument Buffer

				FreeVec(Args);
			}
			else
				PrintFault(ERROR_NO_FREE_STORE, "\nUnLock ");
		}
		else
			PrintFault(ERROR_NO_FREE_STORE, "\nUnLock ");


		if(Pattern)
			FreeVec(Pattern);

		if(NameBuffer)
			FreeVec(NameBuffer);

		if(SpareBuffer)
			FreeVec(SpareBuffer);


			// Close DOSLibrary

		CloseLibrary((struct Library *)DOSBase);
	}

		// Restore old window pointer (if any)

	if(OldWindow)
		MyProc->pr_WindowPtr	= OldWindow;


		// Depending on this flag return appropriate return code

	if(Error)
		return(0);
	else
		return(10);
}





/**********************************************************************/
/*                         My special sprintf                         */
/**********************************************************************/
static void __stdargs SPrintF(STRPTR buffer, STRPTR formatString,...)
{
	va_list varArgs;
	va_start(varArgs,formatString);
	RawDoFmt(formatString,varArgs,(void (*)())(void (*))"\x16\xC0\x4E\x75",buffer);
	va_end(varArgs);
}





/**********************************************************************/
/*                          Unlock an entry                           */
/**********************************************************************/
static ULONG UnLockEntry(char *Pattern, char *NameBuffer, char *SpareBuffer, BOOL Show, BOOL *Error)
{
	struct	DosList				*DList;
	BPTR					OutHandle	= Output();
	ULONG					Num		= 0;
	BOOL					Breaked		= FALSE;


		// Get pointer to DosList

	if((DList = LockDosList(LDF_VOLUMES|LDF_READ)))
	{
		char			*NamePtr;
		BPTR			TestLock,
					LoopLock,
					OldLock;

			// Print header

		if(Show)
		{
			FPuts(OutHandle, "Lock                                 Type Mode  Size       Address\n");
			FPuts(OutHandle, "------------------------------------------------------------------\n");
		}


			// Loop through list

		while((DList = NextDosEntry(DList, LDF_VOLUMES|LDF_READ)))
		{
			memset(NameBuffer, 0, 1024);

				// Create name of volume

			NamePtr	= BADDR(DList->dol_Name);
			strncpy(NameBuffer, (NamePtr + 1), *NamePtr);
			strcat(NameBuffer, ":");


				// Get lock on volume

			if((TestLock = Lock(NameBuffer, ACCESS_READ)))
			{
					// Start with this first lock

				LoopLock	= OldLock	= TestLock;

					// Loop through all locks on this device

				while(LoopLock && !Breaked)
				{
					LONG	FileSize	= -1;
					BOOL	SkipNext;

					SkipNext	= FALSE;


						// Check for control-C

					if(CheckSignal(SIGBREAKF_CTRL_C))
					{
						Breaked	= TRUE;
						break;
					}

						// Compose file/dir name

					if(ComposeName(LoopLock, NameBuffer, &FileSize))
					{
							// Write information about lock

						if(Show)
						{
							BOOL	DoShow	= TRUE;

							if(Pattern)
							{
								if(!MatchPatternNoCase(Pattern, NameBuffer))
									DoShow	= FALSE;
							}

							if(DoShow)
							{
								if(FileSize != -1)
									SPrintF(SpareBuffer, "%-36.36s FILE %s %8.8ld %8.8lx\n", NameBuffer, (((struct FileLock *)BADDR(LoopLock))->fl_Access == ACCESS_READ) ? "READ " : "WRITE", FileSize, BADDR(LoopLock));
								else
									SPrintF(SpareBuffer, "%-36.36s DIR  %s -------- %8.8lx\n", NameBuffer, (((struct FileLock *)BADDR(LoopLock))->fl_Access == ACCESS_READ) ? "READ " : "WRITE", BADDR(LoopLock));

								FPuts(OutHandle, SpareBuffer);
								Num++;
							}
						}
						else
						{
								// This one to unlock?

							if(MatchPatternNoCase(Pattern, NameBuffer))
							{
								BPTR		UnLocking	= LoopLock;

								LoopLock	= (BPTR)((struct FileLock *)BADDR(LoopLock))->fl_Link;
								SkipNext	= TRUE;

								Num++;

								UnLock(UnLocking);
							}
						}
					}

					if(!SkipNext)
						LoopLock	= (BPTR)((struct FileLock *)BADDR(LoopLock))->fl_Link;

					if(LoopLock == OldLock)
						break;
				}

					// Unlock volume

				UnLock(TestLock);
			}
		}

			// Unlock DOSList

		UnLockDosList(LDF_VOLUMES|LDF_READ);
	}
	else
		FPuts(OutHandle, "\nUnLock : Couldn`t lock DosList\n");


	if(!Breaked)
	{
			// Display how many patterns were found

		if(Show)
		{
			if(Num > 1)
			{
				SPrintF(SpareBuffer, "\n%ld locks found\n\n", Num);
				FPuts(OutHandle, SpareBuffer);
			}
			else if(Num == 1)
				FPuts(OutHandle, "\nOne lock found\n\n");
			else
				FPuts(OutHandle, "\nNo lock found\n\n");

			return(0);
		}

		return(Num);
	}
	else
	{
		*Error	= TRUE;
		FPuts(OutHandle, "\nUnLock: ^C...\n\n");
	}

	return(0);
}





/**********************************************************************/
/*                  Compose a full name from a lock                   */
/**********************************************************************/
static BOOL ComposeName(BPTR ObjLock, char *NameBuffer, LONG *FileSize)
{
	struct	FileInfoBlock	__aligned	FIB;
	BPTR					NameLock;
	BOOL					GoOn	= FALSE;

	if((NameLock = DupLock(ObjLock)))
	{
			// Get FileInfo

		if(Examine(NameLock, &FIB))
		{
				// Is it a file?

			if(FIB.fib_DirEntryType < 0 && FileSize)
				*FileSize	= FIB.fib_Size;
		}

		GoOn	= NameFromLock(NameLock, NameBuffer, 1024);

		UnLock(NameLock);
	}

	return(GoOn);
}