kerneltest/f32test/fileshare/t_handshare.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 30 8aab599e3476
parent 0 a41df078684a
child 43 c1f20ce4abcf
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// Copyright (c) 1996-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_handshare.cpp
// 
//

#include <f32file.h>
#include <e32test.h>
#include "t_server.h"
#include "handshare.h"

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

LOCAL_D TInt drivenum;



// test of (deprecated) RFile::Adopt()
//
// Request an open file (read only)
//
GLDEF_C void RequestFileDeprecatedAdopt()
	{
	test.Next(_L("RFile::Adopt()"));

	TInt r;
	RFileHandleSharer handsvr;
	do
		{
		r=handsvr.Connect();
		}
		while(r==KErrNotFound);
	test(r==KErrNone);
	r=handsvr.SetTestDrive(drivenum);
	test(r==KErrNone);
	TInt ssh;
	RFs fs1;
	TInt fsh = handsvr.GetFileHandle(ssh, EFileRead);

	r = fs1.SetReturnedHandle(fsh);
	test(r==KErrNone);
	
	RFile file;
	r=file.Adopt(fs1,ssh);
	test(r==KErrNone);
	
	TBuf8<100> rbuf;
	r=file.Read(0,rbuf);
	test(r==KErrNone);
	
	r=rbuf.CompareF(KTestData1());
	test(r==KErrNone);
	
	r=file.Write(KTestData());
	test(r==KErrAccessDenied);
	
	r=file.ChangeMode(EFileWrite);
	test(r==KErrArgument);
	
	r=file.Rename(_L("\\newname.txt"));
	test(r==KErrPermissionDenied || r==KErrAccessDenied);

	file.Close();

	fsh = handsvr.GetFileHandle(ssh, EFileRead);
	r = fs1.SetReturnedHandle(fsh);
	test(r==KErrNone);

	// Adopt a bad sub-session handle

	r=file.Adopt(fs1, KNullHandle);
	test(r==KErrBadHandle);

	r=file.Adopt(fs1, -1);
	test(r==KErrBadHandle);


	handsvr.Close();
	file.Close();
	RDebug::Print(_L("End Of Tests"));
	fs1.Close();
	}



// Cloning tests
GLDEF_C void Duplicate()
	{
	test.Next(_L("RFile::Duplicate()"));

	RFs fs;
	TInt r=fs.Connect();
	test(r==KErrNone);

	// Check the number of open file handles
	TInt resCount = fs.ResourceCount();
	test(resCount == 0);

	// create a file & fill it with data	
	RFile file1;
	r=file1.Replace(fs,KCliFileName,EFileWrite);
	test(r==KErrNone);
	r=file1.Write(KTestData());
	test(r==KErrNone);
	file1.Close();

	// open the file for read
	r = file1.Open(fs,KCliFileName,EFileRead);
	test(r==KErrNone);
	TBuf8<100> rbuf;
	r = file1.Read(0,rbuf);
	test(r==KErrNone);
	r=rbuf.CompareF(KTestData);
	test(r==KErrNone);


	// clone the file
	RFile file2;
	r = file2.Duplicate(file1);
	test(r==0);

	// make sure file positions are the same
	TInt pos1 = 0;
	r = file1.Seek(ESeekCurrent, pos1);
	test(r==KErrNone);
	TInt pos2 = 0;
	r = file2.Seek(ESeekCurrent, pos2);
	test(r==KErrNone);
	test(pos1 == pos2);

	// change the position on the duplcated file handle & 
	// verify that the original file handle's position is unchanged
	TInt oldPos1 = pos1;
	
	const TInt newPos2 = 5;
	pos2 = newPos2;
	r = file2.Seek(ESeekStart, pos2);
	test(r==KErrNone);
	
	pos1 = 0;
	r = file1.Seek(ESeekCurrent, pos1);
	test(r==KErrNone);
	test(pos1 == oldPos1);
	
	pos2 = 0;
	r = file2.Seek(ESeekCurrent, pos2);
	test(r==KErrNone);
	test(pos2 == newPos2);
	test(pos1 != pos2);

	// close the parent file and check we can still use the duplicated one.
	file1.Close();

	// Check the number of open file handles - should be 1 (the duplicated one)
	resCount = fs.ResourceCount();
	test(resCount == 1);

	fs.Close();

	rbuf.FillZ();

	// reset to pos 0
	pos2 = 0;
	r = file2.Seek(ESeekStart, pos2);
	test(r==KErrNone);
	
	r=file2.Read(0,rbuf);
	test(r==KErrNone);
	r=rbuf.CompareF(KTestData);
	test(r==KErrNone);
	file2.Close();

	// start again - this time we're going to close the duplicated file first
	// and check we can still use the parent file

	r = fs.Connect();
	test(r==KErrNone);

	// Make a note of the number of open resources
	fs.ResourceCountMarkStart();

	// open the file for read
	r = file1.Open(fs,KCliFileName,EFileRead);
	test(r==KErrNone);


	// clone the file & check we can read it
	r = file2.Duplicate(file1, EOwnerThread);
	test(r==0);
	rbuf.FillZ();
	r = file2.Read(0,rbuf);
	test(r==KErrNone);
	r=rbuf.CompareF(KTestData);
	test(r==KErrNone);


	// close the duplicated file and check we can still use the parent one.
	file2.Close();

	rbuf.FillZ();

	// check we can read the parent file
	r=file1.Read(0,rbuf);
	test(r==KErrNone);
	r=rbuf.CompareF(KTestData);
	test(r==KErrNone);

	// close the parent
	file1.Close();

	// Check the number of open file handles
	fs.ResourceCountMarkEnd();
	resCount = fs.ResourceCount();
	test(resCount == 0);

	fs.Close();
	}


// Request an open file (write mode) from the server
// using RFile::AdoptFromServer()
GLDEF_C void RequestFileWrite()
	{
	TInt r;
	RFileHandleSharer handsvr;
	do
		{
		r=handsvr.Connect();
		}
	while(r==KErrNotFound);
	test(r==KErrNone);

	r=handsvr.SetTestDrive(drivenum);
	test(r==KErrNone);

	TInt ssh;
	TInt fsh = handsvr.GetFileHandle2(ssh, EFileWrite);
	test (fsh >= 0);

	// Closing the handle to the server ensures the server has closed it's
	// RFs and RFile handles - this provides a means of testing whether we 
	// can still adopt the RFile even if the server has closed it's one.

	handsvr.Sync(); // make sure server has finished doing what it's doing
	handsvr.Close();

	// adopt the file handle from FHServer
	test.Next(_L("RFile::AdoptFromServer()"));

	RFile file;
	r=file.AdoptFromServer(fsh, ssh);
	test(r==KErrNone);

	TBuf8<100> rbuf;
	r=file.Read(0,rbuf);
	test(r==KErrNone);

	// server should write KTestData1 ("Server Write Server Write") to file
	r=rbuf.CompareF(KTestData1);
	test(r==KErrNone);

	// reset to pos 0
	TInt pos = 0;
	r = file.Seek(ESeekStart, pos);
	test(r==KErrNone);
	
	// overwrite with KTestData ("Client Write Client Write") to file
	r=file.Write(KTestData());
	test(r==KErrNone);
	rbuf.FillZ();
	r=file.Read(0,rbuf);
	test(r==KErrNone);
	r=rbuf.CompareF(KTestData);
	test(r==KErrNone);

// !!! Disable platform security tests until we get the new APIs
//	r=file.Rename(_L("\\newname.txt"));
//	test(r==KErrPermissionDenied);

	test.Next(_L("RFile::Name()"));

	// retrieve the file name from the server
	TFileName name;
	r = file.Name(name);
	test(r==KErrNone);
	r = name.Compare(KSvrFileName());
	test(r==0);
	

	test.Next(_L("RFile::Duplicate()"));
	RFile file2;
	r = file2.Duplicate(file);
	test(r==0);


	TInt pos1 = 0;
	r = file.Seek(ESeekCurrent, pos1);
	test(r==KErrNone);
	TInt pos2 = 0;
	r = file2.Seek(ESeekCurrent, pos2);
	test(r==KErrNone);
	test(pos1 == pos2);

	// close the parent file and check we can still use the duplicated one.
	file.Close();

	rbuf.FillZ();

	// reset to pos 0
	pos2 = 0;
	r = file2.Seek(ESeekStart, pos2);
	test(r==KErrNone);
	
	r=file2.Read(0,rbuf);
	test(r==KErrNone);
	r=rbuf.CompareF(KTestData);
	test(r==KErrNone);
	file2.Close();
	}


// Request a test file & test what we can do with it
// i.e CFileMan::Copy, RFile::Rename() and RFs:Delete()
//
void RequestFileTest()
	{
	TInt r;

	RFs fs;
	r=fs.Connect();
	test(r==KErrNone);
	r=fs.ShareProtected();
	test(r==KErrNone);

	
	// define a filename in our private path
	TPath newPath;
	fs.PrivatePath(newPath);
	TFileName newFileName;
	newFileName = newPath;
	newFileName.Append(_L("newname.txt"));
	
	r=fs.CreatePrivatePath(drivenum);
	test(r==KErrNone);
	r=fs.SetSessionToPrivate(drivenum);

	RFileHandleSharer handsvr;
	do
		{
		r=handsvr.Connect();
		}
	while(r==KErrNotFound);
	test(r==KErrNone);

	r=handsvr.SetTestDrive(drivenum);
	test(r==KErrNone);

	// Next verify that we can copy a file retrieved from the server
	// using CFileMan::Copy()

	test.Next(_L("CFileMan::Copy()"));

	TInt ssh;
	TInt fsh = handsvr.GetFileHandle2(ssh, EFileRead);
	test (fsh >= 0);

	RFile file;
	r=file.AdoptFromServer(fsh, ssh);
	test(r==KErrNone);


	CFileMan* fileMan = NULL;
	TRAP(r, fileMan = CFileMan::NewL(fs));
	test(r == KErrNone && fileMan != NULL);

	// copy to file, overwrite 
	r = fileMan->Copy(file, newFileName, CFileMan::EOverWrite);
	test(r == KErrNone);

	// copy to file, don't overwrite 
	r = fileMan->Copy(file, newFileName, 0);	
	test(r == KErrAlreadyExists);

	// copy to file, overwrite
	r = fileMan->Copy(file, newFileName, CFileMan::EOverWrite);
	test(r == KErrNone);

	// copy to path
	r = fileMan->Copy(file, newPath, CFileMan::EOverWrite);	
	test(r == KErrNone);

	// copy to file, overwrite, asynchnonous
	TRequestStatus status(KRequestPending);
	r = fileMan->Copy(file, newFileName, CFileMan::EOverWrite, status);
	test(r == KErrNone);
	User::WaitForRequest(status);
	test(status == KErrNone);


	// Negative tests...
	TPath newLongPath;
	TInt len;

	// copy to very long but valid path (no filename) which will overflow
	// when the filename is appended to it
	newLongPath = newPath;
	for (len=newLongPath.Length(); len< KMaxPath -4; len = newLongPath.Length())
		newLongPath.Append(_L("x\\"));
	r = fileMan->Copy(file, newLongPath, CFileMan::EOverWrite);	
	test(r == KErrBadName);

	// copy to very long but valid path (no filename) which will overflow
	// when drive letter is pre-pended to it
	newLongPath = newPath;
	for (len=newLongPath.Length(); len< KMaxPath -2; len = newLongPath.Length())
		newLongPath.Append(_L("x\\"));
	r = fileMan->Copy(file, newLongPath, CFileMan::EOverWrite);	
	test(r == KErrBadName);

	// copy to very long but valid path and filename which will overflow
	// when drive letter is pre-pended to it
	newLongPath.Append(_L("y"));
	r = fileMan->Copy(file, newLongPath, CFileMan::EOverWrite);	
	test(r == KErrBadName);

	// copy to badly formed path 
	newLongPath = newPath;
	newLongPath.Append(_L("\\y"));
	r = fileMan->Copy(file, newLongPath, CFileMan::EOverWrite);	
	test(r == KErrBadName);

	// copy to correctly formed path which doesn't exist
	newLongPath = newPath;
	newLongPath.Append(_L("x\\y\\z"));
	r = fileMan->Copy(file, newLongPath, CFileMan::EOverWrite);	
	test(r == KErrPathNotFound);

	delete fileMan; fileMan = NULL;

	file.Close();

	
	// First verify that we CANNOT rename a file retrieved from the server
	// that has not been opened in EFileShareExclusive mode

	test.Next(_L("negative test of RFile::Rename()"));

	fsh = handsvr.GetFileHandle2(ssh, TFileMode(EFileShareAny | EFileWrite));
	test (fsh >= 0);

	// adopt the file handle from FHServer
	r=file.AdoptFromServer(fsh, ssh);
	test(r==KErrNone);

	r=file.Rename(_L("newname.txt"));
	test(r==KErrPermissionDenied || r==KErrAccessDenied);

	// delete the file before we try to rename anything to it
	r = fs.Delete(newFileName);
	test(r == KErrNone || r == KErrNotFound);

	r=file.Rename(newFileName);
	test(r==KErrPermissionDenied || r==KErrAccessDenied);

	file.Close();


	// Next verify that we CAN rename a file retrieved from the server
	// that HAS been opened in EFileShareExclusive mode

	test.Next(_L("RFile::Rename()"));

	fsh = handsvr.GetFileHandle2(ssh, EFileWrite);
	test (fsh >= 0);

	r=file.AdoptFromServer(fsh, ssh);
	test(r==KErrNone);

	// delete the file before we try to rename anything to it
	r = fs.Delete(newFileName);
	test(r == KErrNone || r == KErrNotFound);

	r=file.Rename(newFileName);
	test(r==KErrNone);

	file.Close();

	// Next verify that we can delete the file (which should now 
	// have been moved to our private directory)
	test.Next(_L("RFs::Delete()"));
	r = fs.Delete(newFileName);
	test(r == KErrNone);

	handsvr.Close();

	fs.Close();
	}

//
// Pass an open file to the server 
// The server will use RFile::AdoptFromClient()
//
GLDEF_C void PassFile()
	{
	RFs fs;
	TInt r=fs.Connect();
	test(r==KErrNone);

	// Check the number of open file handles
	TInt resCount = fs.ResourceCount();
	test(resCount == 0);

	r=fs.ShareProtected();
	test(r==KErrNone);

	r=fs.CreatePrivatePath(drivenum);
	test(r==KErrNone);
	r=fs.SetSessionToPrivate(drivenum);
	
	
	RFile file1;
	r=file1.Replace(fs,KCliFileName,EFileWrite);
	test(r==KErrNone);
	r=file1.Write(KTestData());
	test(r==KErrNone);
	file1.Close();

	RFileHandleSharer handsvr;
	do
		{
		r=handsvr.Connect();
		}
	while(r==KErrNotFound);
	test(r==KErrNone);

	r=handsvr.SetTestDrive(drivenum);
	test(r==KErrNone);

	r=fs.SetSessionToPrivate(drivenum);
	test(r==KErrNone);

	r=file1.Open(fs,KCliFileName,EFileRead);
	test(r==KErrNone);
	
	// pass the file handle to FHServer
	test.Next(_L("RFile::TransferToServer()"));

	TIpcArgs ipcArgs;
	file1.TransferToServer(ipcArgs, 0, 1);

	r = handsvr.PassFileHandle(ipcArgs);


	// verify that the original file handle's position is unchanged
	TInt pos = 0;
	r = file1.Seek(ESeekCurrent, pos);
	test(r==KErrNone);
	test(pos == 0);

	// make sure we can still use it
	TBuf8<100> rbuf;
	r=file1.Read(0,rbuf);
	test(r==KErrNone);

	// Close the file
	file1.Close();	

	handsvr.Close();

	r=fs.MkDir(_L("C:\\mdir"));
	test(r==KErrNone || r==KErrAlreadyExists);
	
	// Check the number of open file handles
	resCount = fs.ResourceCount();
	test(resCount == 0);

	fs.Close();
	}


//
// Pass an invalid file handle to the server 
// The server will use RFile::AdoptFromClient()
//
GLDEF_C void PassInvalidFile()
	{

	RFs fs;
	TInt r=fs.Connect();
	test(r==KErrNone);

	// Check the number of open file handles
	TInt resCount = fs.ResourceCount();
	test(resCount == 0);

	r=fs.ShareProtected();
	test(r==KErrNone);

	r=fs.CreatePrivatePath(drivenum);
	test(r==KErrNone);
	r=fs.SetSessionToPrivate(drivenum);
	
	
	RFile file1;
	r=file1.Replace(fs,KCliFileName,EFileWrite);
	test(r==KErrNone);
	r=file1.Write(KTestData());
	test(r==KErrNone);
	file1.Close();

	RFileHandleSharer handsvr;
	do
		{
		r=handsvr.Connect();
		}
	while(r==KErrNotFound);
	test(r==KErrNone);

	r=handsvr.SetTestDrive(drivenum);
	test(r==KErrNone);

	r=fs.SetSessionToPrivate(drivenum);
	test(r==KErrNone);

	r=file1.Open(fs,KCliFileName,EFileRead);
	test(r==KErrNone);
	
	// check the resoure count - there should be 1 open file handle
	resCount = fs.ResourceCount();
	test(resCount == 1);

	// pass an invalid file handle to FHServer
	// by overwriting the IPC slots
	test.Next(_L("PassInvalidFileHandle - RFile::TransferToServer()"));

	TIpcArgs ipcArgs;

	// Pass a bad RFs handle
	file1.TransferToServer(ipcArgs, 0, 1);

	// check the resoure count - there should be 2 open file handles
	resCount = fs.ResourceCount();
	test(resCount == 2);

	ipcArgs.Set(0, 0);	// invalidate the RFs handle
	r = handsvr.PassInvalidFileHandle(ipcArgs);
	test (r == KErrBadHandle);

	// Pass a bad RFile handle
	file1.TransferToServer(ipcArgs, 0, 1);

	// check the resoure count - there should be 3 open file handles
	resCount = fs.ResourceCount();
	test(resCount == 3);

	ipcArgs.Set(1, 0);	// invalidate the RFile handle
	r = handsvr.PassInvalidFileHandle(ipcArgs);
	test (r == KErrBadHandle);

	// Pass bad RFs and RFile handles
	file1.TransferToServer(ipcArgs, 0, 1);

	// check the resoure count - there should be 4 open file handles
	resCount = fs.ResourceCount();
	test(resCount == 4);


	ipcArgs.Set(0, 0);	// invalidate the RFs handle
	ipcArgs.Set(1, 0);	// invalidate the RFile handle
	r = handsvr.PassInvalidFileHandle(ipcArgs);
	test (r == KErrBadHandle);

	// Close the file
	handsvr.Close();
	file1.Close();	

	// Check the number of open file handles
	resCount = fs.ResourceCount();
	test(resCount == 3);

	fs.Close();
	}


// Pass RFs/RFile handles to the server using
// process parameter slots (RProcess::SetParameter()),
// resume the process and wait for it to read the file...
// The server will use RFile::AdoptFromCreator()
GLDEF_C void PassFile(RProcess& aProcess)
	{
	
	RFs fs;
	TInt r=fs.Connect();
	test(r==KErrNone);

	// Check the number of open file handles
	TInt resCount = fs.ResourceCount();
	test(resCount == 0);

	r=fs.ShareProtected();
	test(r==KErrNone);

	r=fs.CreatePrivatePath(drivenum);
	test(r==KErrNone);
	r=fs.SetSessionToPrivate(drivenum);
	
	
	RFile file1;
	r=file1.Replace(fs,KCliFileName,EFileWrite);
	test(r==KErrNone);
	r=file1.Write(KTestData());
	test(r==KErrNone);
	file1.Close();

	r=file1.Open(fs, KCliFileName, EFileWrite);

	test(r==KErrNone);
	
	// NB slot 0 is reserved for the command line

	test.Next(_L("RFile::TransferToProcess()"));

	r = file1.TransferToProcess(aProcess, 1, 2);

	r = aProcess.SetParameter(3, drivenum);
	test(r==KErrNone);

	r=fs.SetSessionToPrivate(drivenum);
	test(r==KErrNone);

	// make sure we can still read from the file
	TBuf8<100> rbuf;
	r=file1.Read(0,rbuf);
	test(r==KErrNone);
	r=rbuf.CompareF(KTestData());
	test(r==KErrNone);
	file1.Close();

	r=fs.MkDir(_L("C:\\mdir"));
	test(r==KErrNone || r==KErrAlreadyExists);
	
	// Check the number of open file handles - 
	// should be 1 (the one duplicated for the other process)
	resCount = fs.ResourceCount();
	test(resCount == 1);

	fs.Close();

	// Start the server thread
	aProcess.Resume();



	// connect to the server
	RFileHandleSharer handsvr;
	do
		{
		r=handsvr.Connect();
		}
	while(r==KErrNotFound);
	test(r==KErrNone);


	r=handsvr.SetTestDrive(drivenum);
	test(r==KErrNone);

	// wait for server to read the file
	r = handsvr.PassFileHandleProcess();
	test (r == KErrNone);
	
	handsvr.Close();
	}



GLDEF_C void CallTestsL(void)
    {
	RFs::CharToDrive(gDriveToTest,drivenum);

	// make sure the session path exists
	RFs fs;
	TInt r = fs.Connect();
	test(r==KErrNone);

	TFileName sessionp;
	fs.SessionPath(sessionp);
	r = fs.MkDirAll(sessionp);
	test(r==KErrNone || r==KErrAlreadyExists);
	fs.Close();

	// Remember the number of open handles. Just for a sanity check ....
	TInt start_thc, start_phc;
	RThread().HandleCount(start_phc, start_thc);
	test.Printf(_L("Handles: start_phc %d, start_thc %d\n"), start_phc, start_thc);

	//create test server
	RProcess p;
	r = p.Create(_L("FHServer.exe"), KNullDesC);
	test(r==KErrNone);

	// RFile::Duplicate() tests
	Duplicate();

	// Pass RFs/RFile handles to the server using RFile::TransferToProcess()
	// process parameter slots (RProcess::SetParameter()),
	// resume the server process and wait for it to read the file...
	PassFile(p);
	
	// Transfer the file handle to FHServer using RFile::TransferToServer(). 
	// Get FHServer to transfer it to FHServer2
	PassFile();

	
	// Get an open writeable file from FHServer2 via FHServer 
	// using RFile::AdoptFromServer()
	RequestFileWrite();

	// Deprecated RFile::Adopt() test
	RequestFileDeprecatedAdopt();

	// negative test 
	// Pass an invalid file handle to the server 
	PassInvalidFile();


	// Get an open file handle from FHServer2 via FHServer 
	// and test whether we can copy/rename/delete it etc
	// be able to rename it.
	RequestFileTest();

	// stop the servers
	RFileHandleSharer handsvr;
	r=handsvr.Connect();
	test(r==KErrNone);
	r = handsvr.Exit();
	test(r == KErrNone);
	handsvr.Close();
	
	// delete the test file
	RFs cleanupfs;
	r=cleanupfs.Connect();
	test(r==KErrNone);
	r=cleanupfs.SetSessionToPrivate(drivenum);
	test(r==KErrNone);
	r=cleanupfs.Delete(KCliFileName);
	test(r==KErrNone || r==KErrNotFound);
	cleanupfs.Close();


	// wait for server process to end
	TRequestStatus status;
	p.Logon(status);
	User::WaitForRequest(status);
	test (status == KErrNone);

	// cleanup
	p.Close();

	// Sanity check for open handles
	TInt end_thc, end_phc;
	RThread().HandleCount(end_phc, end_thc);
	test.Printf(_L("Handles: end_phc %d, end_thc %d\n"), end_phc, end_thc);

	test(start_thc == end_thc);
	test(start_phc == end_phc);
	
	// and also for pending requests ...
	test(RThread().RequestCount() == 0);
	
	
	RDebug::Print(_L("End Of Tests"));
	}