// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// f32test\server\t_virus.cpp
// 
//

#include <f32file.h>
#include <e32test.h>
#include <e32svr.h>
#include <f32dbg.h>
#include "t_server.h"

GLREF_C void TestIfEqual( TInt aValue, TInt aExpected, TInt aLine, char aFileName[]);

#define TEST_FOR_ERROR( r )	TestIfEqual( r, KErrNone, __LINE__, __FILE__)
#define TEST_FOR_VALUE( r, expected ) TestIfEqual( r, expected, __LINE__, __FILE__)

_LIT( KValueTestFailMsg, "ERROR Got %d expected %d" );
GLDEF_C void TestIfEqual( TInt aValue, TInt aExpected, TInt aLine, char aFileName[])
	{
	if( aExpected != aValue )
		{
		TText filenameU[512];
		TUint i = 0;
		for (; (i < sizeof(filenameU)) && (aFileName[i] != (char)0); i++)
			{
			filenameU[i]=aFileName[i];
			}
		filenameU[i]=0;
		test.Printf( KValueTestFailMsg, aValue, aExpected );
		test.operator()( EFalse, aLine, &filenameU[0]);
		}
	}

GLDEF_D RTest test(_L("T_VIRUS"));


void CleanupFiles()
	{
	test.Next(_L("Delete any files leftover from a previous run"));

	TheFs.SetAtt(_L("C:\\sys\\bin\\t_vshook.pxt"),0, KEntryAttReadOnly);
	TheFs.Delete(_L("C:\\sys\\bin\\t_vshook.pxt"));

	TheFs.SetAtt(_L("C:\\virusdef.txt"),0, KEntryAttReadOnly);
	TheFs.Delete(_L("C:\\virusdef.txt"));
	
	TheFs.SetAtt(_L("virus1.txt"),0, KEntryAttReadOnly);
	TheFs.Delete(_L("virus1.txt"));

	TheFs.SetAtt(_L("virus2.txt"),0, KEntryAttReadOnly);
	TheFs.Delete(_L("virus2.txt"));

	TheFs.SetAtt(_L("c:\\virus3.txt"),0, KEntryAttReadOnly);
	TheFs.Delete(_L("c:\\virus3.txt"));

	TheFs.SetAtt(_L("clean.txt"),0, KEntryAttReadOnly);
	TheFs.Delete(_L("clean.txt"));
	}

void CopyFilesL()
	{
	//So that we have the same file on WINS and a platform,
	//we expect to find all the files on Z:\test.  We then
	//copy the virus scanner vsh and the definition file to
	//the C: drive and the files to be scanned to whatever
	//drive we're testing on.
	test.Next(_L("Copying files to the appropriate places"));

	TInt r = TheFs.MkDirAll(_L("C:\\sys\\bin\\"));
	if (r != KErrAlreadyExists)
		TEST_FOR_ERROR(r);

	//If we're not currently on drive C, make a sys\\bin directory
	//so we can test attempting to rename it
	r = TheFs.MkDirAll(_L("\\sys\\bin\\"));
	if (r != KErrAlreadyExists)
		TEST_FOR_ERROR(r);

	CFileMan* pFileMan = CFileMan::NewL(TheFs);
	r = pFileMan->Copy(_L("Z:\\test\\t_vshook.pxt"), _L("C:\\sys\\bin\\t_vshook.pxt"));
	TEST_FOR_ERROR(r);

	r = pFileMan->Copy(_L("Z:\\test\\virusdef.txt"), _L("C:\\virusdef.txt"));
	TEST_FOR_ERROR(r);

	r = pFileMan->Copy(_L("Z:\\test\\virus1.txt"), _L("virus1.txt"));
	TEST_FOR_ERROR(r);

	r = pFileMan->Copy(_L("Z:\\test\\virus2.txt"), _L("virus2.txt"));
	TEST_FOR_ERROR(r);

	r = pFileMan->Copy(_L("Z:\\test\\clean.txt"), _L("clean.txt"));
	TEST_FOR_ERROR(r);

	delete pFileMan;
	}

void TestFileAccessBeforeVirusScanner()
	{

	//Check that we can read all the files we want before the
	//virus scanner is loaded.
	test.Next(_L("Test opening files before virus scanner is installed"));

	RFile file;
	TBuf8<512> buffer;

	TInt r = file.Open(TheFs, _L("C:\\virusdef.txt"), EFileShareAny);

	TEST_FOR_ERROR(r);
	r = file.Read(buffer);
	TEST_FOR_ERROR(r);
	file.Close();

	r = file.Open(TheFs, _L("virus1.txt"), EFileShareAny);
	TEST_FOR_ERROR(r);
	r = file.Read(buffer);
	TEST_FOR_ERROR(r);
	file.Close();

	r = file.Open(TheFs, _L("virus2.txt"), EFileShareAny);
	TEST_FOR_ERROR(r);
	r = file.Read(buffer);
	TEST_FOR_ERROR(r);
	file.Close();

	r = file.Open(TheFs, _L("clean.txt"), EFileShareAny);
	TEST_FOR_ERROR(r);
	r = file.Read(buffer);
	TEST_FOR_ERROR(r);
	file.Close();
	}

void TestLoadingOfVirusScanner()
	{
	test.Next(_L("Test the loading of the virus scanner"));

	// Try loading the virus scanner.
	TInt r = TheFs.AddPlugin(_L("t_vshook"));
	TEST_FOR_ERROR(r);

	// Try loading the virus scanner again.
	r = TheFs.AddPlugin(_L("t_vshook"));
	TEST_FOR_VALUE(r, KErrAlreadyExists);


	// Try mounting the virus scanner.
	r = TheFs.MountPlugin(_L("VsHook"));
	TEST_FOR_ERROR(r);


	//Test the name functions
	TFullName vsName;
	r = TheFs.PluginName(vsName,0,0);
	test.Printf(_L("Virus scanner name is: %S\n"), &vsName);

	}

void TestUnloadingOfVirusScanner()
	{
	test.Next(_L("Test unloading the virus scanner"));

	//Unload the virus scanner
	//Wait for it to empty it's input queue.
	User::After(3000000);

	TInt r = TheFs.DismountPlugin(_L("VsHook"));
	TEST_FOR_ERROR(r);

	r = TheFs.DismountPlugin(_L("VsHook"));
	TEST_FOR_VALUE(r, KErrNotFound);

	r = TheFs.RemovePlugin(_L("VsHook"));
	TEST_FOR_ERROR(r);

	r = TheFs.RemovePlugin(_L("VsHook"));
	TEST_FOR_VALUE(r, KErrNotFound);
	}


void TestFileAccessDuringVirusScannerL()
	{

	RFile file;
	TBuf8<512> buffer;

	test.Next(_L("Test opening files with the virus scanner installed"));

	TInt r = file.Open(TheFs, _L("C:\\virusdef.txt"), EFileShareAny);
	TEST_FOR_VALUE(r, KErrAccessDenied);

	r = file.Open(TheFs, _L("virus1.txt"), EFileShareAny);
	TEST_FOR_VALUE(r, KErrAccessDenied);

	r = file.Open(TheFs, _L("virus2.txt"), EFileShareAny);
	TEST_FOR_VALUE(r, KErrAccessDenied);

	r = file.Open(TheFs, _L("C:\\sys\\bin\\t_vshook.pxt"), EFileShareAny);
	TEST_FOR_VALUE(r, KErrAccessDenied);

	// Set up a change notifier
	// - The virus scanner renames files before scanning, so check that the
	//	 internal rename operation hasn't caused a notification.
	TRequestStatus reqStat;
	TheFs.NotifyChange(ENotifyAll, reqStat, _L("C:\\F32-TST\\"));
	TEST_FOR_VALUE(reqStat.Int(), KRequestPending);

	r = file.Open(TheFs, _L("clean.txt"), EFileShareAny);
	TEST_FOR_ERROR(r);
	r = file.Read(buffer);
	TEST_FOR_ERROR(r);
	file.Close();

	// Verify that cleaning file didn't cause a notification
	TEST_FOR_VALUE(reqStat.Int(), KRequestPending);
	TheFs.NotifyChangeCancel(reqStat);

	//Files on Z: are not scanned, so we should be able to open
	//an infected file
	r = file.Open(TheFs, _L("Z:\\test\\virus1.txt"), EFileShareAny);
	TEST_FOR_ERROR(r);
	r = file.Read(buffer);
	TEST_FOR_ERROR(r);
	file.Close();

	test.Next(_L("Test opening of scanner files"));
	r = file.Open(TheFs, _L("C:\\sys\\bin\\t_vshook.pxt"), EFileShareAny);
	TEST_FOR_VALUE(r, KErrAccessDenied);

	r = file.Open(TheFs, _L("C:\\virusdef.txt"), EFileShareAny);
	TEST_FOR_VALUE(r, KErrAccessDenied);



	test.Next(_L("Test renaming of infected files"));
	//With RFs::Rename()
	r = TheFs.Rename(_L("virus1.txt"), _L("renamed1.txt"));
	TEST_FOR_VALUE(r, KErrAccessDenied);

	//Test RFs::Replace()
	r = TheFs.Replace(_L("virus1.txt"), _L("renamed1.txt"));
	TEST_FOR_VALUE(r, KErrAccessDenied);

	//CFileMan opens the file for exclusive access,
	//so wait for the virus scanner to finish.
	User::After(1000000);

	//With CFileMan
	CFileMan* pFileMan = CFileMan::NewL(TheFs);
	r = pFileMan->Rename(_L("virus1.txt"), _L("renamed1.txt"));
	TEST_FOR_VALUE(r, KErrAccessDenied);

	test.Next(_L("Test renaming virus scanner files"));
	//Test renaming of virus definition file
	r = TheFs.Rename(_L("C:\\virusdef.txt"), _L("C:\\renameddef.txt"));
	TEST_FOR_VALUE(r, KErrAccessDenied);

	//With CFileMan
	r = pFileMan->Rename(_L("C:\\virusdef.txt"), _L("C:\\renameddef.txt"));
	TEST_FOR_VALUE(r, KErrAccessDenied);

	//Test renaming of virus scanner hook
	r = TheFs.Rename(_L("C:\\sys\\bin\\t_vshook.pxt"), _L("C:\\sys\\bin\\renames.pxt"));
	TEST_FOR_VALUE(r, KErrAccessDenied);

	//With CFileMan
	r = pFileMan->Rename(_L("C:\\sys\\bin\\t_vshook.pxt"), _L("C:\\sys\\bin\\renames.pxt"));
	TEST_FOR_VALUE(r, KErrAccessDenied);


	test.Next(_L("Test deleting an infected file"));
	r = TheFs.SetAtt(_L("virus2.txt"), 0,KEntryAttReadOnly); 
	TEST_FOR_ERROR(r);
	r = TheFs.Delete(_L("virus2.txt"));
	TEST_FOR_ERROR(r);

	test.Next(_L("Test closing an infected file"));
	r = file.Create(TheFs, _L("c:\\virus3.txt"), EFileWrite | EFileShareAny);
	TEST_FOR_ERROR(r);
	r = file.Write(_L8("This a generated infected file."));
	TEST_FOR_ERROR(r);
	file.Close();

	//Test renaming a directory
	test.Next(_L("Test renaming a directory"));
	r = TheFs.Rename(_L("\\sys\\bin\\"), _L("\\virusdir1\\"));
	TEST_FOR_VALUE(r, KErrAccessDenied);

	delete pFileMan;
	}

void TestReadFileSectionInterceptL()
	{
	TBuf8<16> testDes;

	test.Next(_L("Test ReadFileSection intercept GetName and GetFileAccessInfo support"));	
	// trigger RFs::ReadFileSection intercept
	TInt r = TheFs.ReadFileSection(_L("clean.txt"),0,testDes,8);
	test(r==KErrNone);
	}


void TestFileAccessAfterVirusScanner()
	{

	test.Next(_L("Test opening files after virus scanner is uninstalled"));

	RFile file;
	TBuf8<512> buffer;

	test.Next(_L("Test the virus definition file"));
	TInt r = file.Open(TheFs, _L("C:\\virusdef.txt"), EFileShareAny);
	TEST_FOR_ERROR(r);
	r = file.Read(buffer);
	TEST_FOR_ERROR(r);
	file.Close();

	if (buffer.Length() == buffer.MaxLength())
		{
		//The definition file should be less than 512 bytes in length.
		r = KErrOverflow;
		TEST_FOR_ERROR(r);
		}

	//Make sure that the virus scanner has not "fixed" this file
	r = buffer.Find(_L8("infection"));
	TEST_FOR_VALUE(r, KErrNotFound);

	test.Next(_L("Test the clean file has not been corrected"));
	r = file.Open(TheFs, _L("clean.txt"), EFileShareAny);
	TEST_FOR_ERROR(r);
	r = file.Read(buffer);
	TEST_FOR_ERROR(r);
	file.Close();

	if (buffer.Length() == buffer.MaxLength())
		{
		//The clean file should be less than 512 bytes in length.
		r = KErrOverflow;
		TEST_FOR_ERROR(r);
		}

	//Make sure that the virus scanner has not "fixed" this file
	r = buffer.Find(_L8("infection"));
	TEST_FOR_VALUE(r, KErrNotFound);
	

	//Virus2.txt should have been successfully deleted.
	r = file.Open(TheFs, _L("virus2.txt"), EFileRead);
	TEST_FOR_VALUE(r, KErrNotFound);

	//Virus1.txt should have been corrected several times.
	//Here's the order in which we did things to it in
	//TestFileAccessDuringVirusScannerL():
	//1. Open for read.
	//2. Rename using RFS
	//3. Rename using CFileMan
	test.Next(_L("Test the infected file has been corrected"));
	r = file.Open(TheFs, _L("virus1.txt"), EFileShareAny);
	TEST_FOR_ERROR(r);
	r = file.Read(buffer);
	TEST_FOR_ERROR(r);
	file.Close();

	if (buffer.Length() == buffer.MaxLength())
		{
		//The infected file should be less than 512 bytes in length.
		r = KErrOverflow;
		TEST_FOR_ERROR(r);
		}

	//Make sure that the virus scanner has "fixed" this file,
	//and that the fixing order is correct.
	TInt fixPos1 = buffer.Find(_L8("infection detected - file open"));
	if (fixPos1 < 0)
		{
		TEST_FOR_ERROR(fixPos1);
		}
	TInt fixPos2 = buffer.Find(_L8("infection detected - file rename"));
	if (fixPos2 < 0)
		{
		TEST_FOR_ERROR(fixPos2);
		}
	//The -32 is the length of the "infection detected - file rename"
	TPtrC8 rightPart = buffer.Right((buffer.Length() - fixPos2) - 32);
	TInt fixPos3 = rightPart.Find(_L8("infection detected - file rename"));
	fixPos3 += fixPos2 + 32;
	if (fixPos3 < 0)
		{
		TEST_FOR_ERROR(fixPos3);
		}
	
	if (!(fixPos3 > fixPos2 && fixPos3 > fixPos1 && fixPos2 > fixPos1))
		{
		//The fixes have not been written to the file in the correct
		//order
		r = KErrGeneral;
		TEST_FOR_ERROR(r);
		}


	test.Next(_L("Test a generated infection is detected"));
	r = file.Open(TheFs, _L("c:\\virus3.txt"), EFileShareAny);
	TEST_FOR_ERROR(r);
	r = file.Read(buffer);
	TEST_FOR_ERROR(r);
	file.Close();

	if (buffer.Length() == buffer.MaxLength())
		{
		//The clean file should be less than 512 bytes in length.
		r = KErrOverflow;
		TEST_FOR_ERROR(r);
		}

	//Make sure that the virus scanner has "fixed" this file
	r = buffer.Find(_L8("infection detected - file close"));
	if (r < 0)
		TEST_FOR_ERROR(r);
	}

void DeleteFiles()
	{

	test.Next(_L("Cleanup files"));
	//Delete all of the files created using CopyFilesL() so
	//that the test can run multiple times.
	TInt r = TheFs.SetAtt(_L("C:\\sys\\bin\\t_vshook.pxt"),0, KEntryAttReadOnly);
	TEST_FOR_ERROR(r);
	r = TheFs.Delete(_L("C:\\sys\\bin\\t_vshook.pxt"));
	TEST_FOR_ERROR(r);

	r = TheFs.RmDir(_L("\\sys\\bin\\"));
	if (r != KErrInUse)
		TEST_FOR_ERROR(r);

	r = TheFs.SetAtt(_L("C:\\virusdef.txt"),0, KEntryAttReadOnly);
	TEST_FOR_ERROR(r);
	r = TheFs.Delete(_L("C:\\virusdef.txt"));
	TEST_FOR_ERROR(r);

	r = TheFs.SetAtt(_L("virus1.txt"),0, KEntryAttReadOnly);
	TEST_FOR_ERROR(r);
	r = TheFs.Delete(_L("virus1.txt"));
	TEST_FOR_ERROR(r);

	r = TheFs.SetAtt(_L("c:\\virus3.txt"),0, KEntryAttReadOnly);
	TEST_FOR_ERROR(r);
	r = TheFs.Delete(_L("c:\\virus3.txt"));
	TEST_FOR_ERROR(r);

	r = TheFs.SetAtt(_L("clean.txt"),0, KEntryAttReadOnly);
	TEST_FOR_ERROR(r);
	r = TheFs.Delete(_L("clean.txt"));
	TEST_FOR_ERROR(r);
	}	


GLDEF_C void CallTestsL()
	{

	CleanupFiles();
	CopyFilesL();

	TestFileAccessBeforeVirusScanner();

	TestLoadingOfVirusScanner();

	TestFileAccessDuringVirusScannerL();

	TestReadFileSectionInterceptL();

	TestUnloadingOfVirusScanner();

	TestFileAccessAfterVirusScanner();

	DeleteFiles();

	}

