diff -r 000000000000 -r 08ec8eefde2f persistentstorage/sql/SRC/Client/SqlDbSession.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/persistentstorage/sql/SRC/Client/SqlDbSession.cpp Fri Jan 22 11:06:30 2010 +0200 @@ -0,0 +1,857 @@ +// 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 "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: +// + +#include +#include +#include +#include +#include +#include "IPCBuf.h" //HIpcBuf +#include "SqlDbSession.h" //RSqlDbSession +#include "SqlSrvStartup.h" //StartSqlServer() +#include "SqlResourceTest.h" //TSqlResourceTestData +#include "SqlSecurityImpl.h" //CSqlSecurityPolicy + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////// TSqlFhCmdFunctor /////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** +TSqlFhCmdFunctor derived classes are used by RSqlDbSession for sending to SQL server localy created/opened +file handles. + +@see RSqlDbSession +@see RSqlDbSession::CreateAndSendFileHandle() + +@internalComponent +*/ +NONSHARABLE_CLASS(TSqlFhCmdFunctor) + { +public: + TSqlFhCmdFunctor(RSqlDbSession& aDbSession, const TDesC& aDbFileName, const TDesC8* aConfig=NULL) : + iDbSession(aDbSession), + iDbFileName(aDbFileName), + iConfig(aConfig) // ownership not transferred + { + } + virtual TInt operator()(RFile64& aFile, TBool aCreated, TBool aReadOnly) = 0; + +public: + RSqlDbSession& iDbSession; + const TDesC& iDbFileName; + const TDesC8* iConfig; + }; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////// TSqlFhOpenCmdFunctor ////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** +Implements the sending of ESqlSrvDbOpenFromHandle command to the SQL server. + +@internalComponent +*/ +NONSHARABLE_CLASS(TSqlFhOpenCmdFunctor) : public TSqlFhCmdFunctor + { +public: + TSqlFhOpenCmdFunctor(RSqlDbSession& aDbSession, const TDesC& aDbFileName,const TDesC8* aConfig=NULL) : + TSqlFhCmdFunctor(aDbSession, aDbFileName, aConfig) + { + } + virtual TInt operator()(RFile64& aDbFile, TBool aCreated, TBool aReadOnly); + + }; + +/** +Sends a command to the SQL server to use the supplied file session and file handles for adopting, +when opening/creating a database. + +Usage of the IPC call arguments: + - Arg 0: [out] The 32 bits of the argument are used as follow: + @code + MSB LSB + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + Ro Cr C C C C C C C C C C C C C C F F F F F F F F F F F F F F F F + @endcode + Where: + @code + - "Ro" - read-only flag, true if the file is read-only; + - "Cr" - create/open flag, true if the file was created, false if the file was opened; + - "C" - config string length; + - "F" - database file name length; + @endcode + - Arg 1: [out] database file name + configuration string (if there is a configuration string) + - Arg 2: [out] file session handle + - Arg 3: [out] database file handle +*/ +TInt TSqlFhOpenCmdFunctor::operator()(RFile64& aDbFile, TBool aCreated, TBool aReadOnly) + { + const TInt KConfigStrLen = iConfig ? iConfig->Length() : 0; + if(KConfigStrLen > KSqlSrvMaxConfigStrLen) + { + return KErrArgument; + } + TIpcArgs ipcArgs; + HBufC* arg1Buf = HBufC::New(iDbFileName.Length() + KConfigStrLen); + if(!arg1Buf) + { + return KErrNoMemory; + } + TPtr arg1 = arg1Buf->Des(); + arg1.Copy(iDbFileName); + if(iConfig) + { + TBuf cfgBuf; + cfgBuf.Copy(*iConfig); + arg1.Append(cfgBuf); + } + TUint32 arg0 = iDbFileName.Length() | (KConfigStrLen << 16); + if(aReadOnly) + { + arg0 |= 0x80000000; + } + if(aCreated) + { + arg0 |= 0x40000000; + } + ipcArgs.Set(0, arg0); + ipcArgs.Set(1, &arg1); + TInt err = aDbFile.TransferToServer(ipcArgs, 2, 3); + if(err == KErrNone) + { + err = iDbSession.SendReceive(ESqlSrvDbOpenFromHandle, ipcArgs); + } + delete arg1Buf; + return err; + } + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////// TSqlFhAttachCmdFunctor //////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** +Implements the sending of ESqlSrvDbAttachFromHandle command to the SQL server. + +@internalComponent +*/ +NONSHARABLE_CLASS(TSqlFhAttachCmdFunctor) : public TSqlFhCmdFunctor + { +public: + TSqlFhAttachCmdFunctor(RSqlDbSession& aDbSession, const TDesC& aDbFileName, + const TDesC& aDbName) : + TSqlFhCmdFunctor(aDbSession, aDbFileName), + iDbName(aDbName) + { + } + virtual TInt operator()(RFile64& aDbFile, TBool aCreated, TBool aReadOnly); + +private: + void SerializeToStreamL(RWriteStream& aStream); + +private: + const TDesC& iDbName; + + }; + +/** +Sends a command to the SQL server to use the supplied file session and file handles for adopting, +when attaching a database. + +Usage of the IPC call arguments: + - Arg 0: [out] The 32 bits of the argument are used as follow: + @code + MSB LSB + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + Ro F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F + @endcode + Where: + @code + - "Ro" - read-only flag, true if the file is read-only; + - "F" - database file name length; + @endcode + - Arg 1: [out] db names buffer + - Arg 2: [out] file session handle + - Arg 3: [out] database file handle +*/ +TInt TSqlFhAttachCmdFunctor::operator()(RFile64& aDbFile, TBool /*aCreated*/, TBool aReadOnly) + { + const TInt KMaxBufLen = iDbFileName.Length() * sizeof(TText) + iDbName.Length() * sizeof(TText) + 32;//"32" should be enough for all additional data like name length, alignment, etc. + HBufC8* buf = HBufC8::New(KMaxBufLen); + if(!buf) + { + return KErrNoMemory; + } + TPtr8 bufPtr = buf->Des(); + RDesWriteStream out(bufPtr); + TRAPD(err, SerializeToStreamL(out)); + if(err == KErrNone) + { + TUint32 arg0 = (TUint32)bufPtr.Length() | (aReadOnly ? 0x80000000 : 0); + TIpcArgs ipcArgs(arg0, &bufPtr); + err = aDbFile.TransferToServer(ipcArgs, 2, 3); + if(err == KErrNone) + { + err = iDbSession.SendReceive(ESqlSrvDbAttachFromHandle, ipcArgs); + } + } + delete buf; + return err; + } + +/** +Serializes TSqlFhAttachCmdFunctor object content to a stream (aStream parameter). +*/ +void TSqlFhAttachCmdFunctor::SerializeToStreamL(RWriteStream& aStream) + { + aStream << iDbFileName; + aStream << iDbName; + aStream.CommitL(); + } + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//Database type. +enum TDbType + { + EDbTypeUnknown, //The database resides outside the client's private data cage + EDbTypeClientPrivate //The database resides in the client's private data cage + }; + +/** +Returns the database type. + +@param aDbFileName Database file name, including the path. If it is a request for creating/opening + secure database, then the name format is :<[SID]database_file_name>. + +@return EDbTypeClientPrivate If the database resides in the client's private data cage; + EDbTypeUnknown This may be a database in the SQL server private data cage or somewhere else; + If the error code is less than 0, then the function cannot determine the database type + (the function was unable to connect the local file session instance). + +@internalComponent +*/ +static TInt GetDbType(const TDesC& aDbFileName) + { + RFs fs; + TInt err = fs.Connect(); + if(err == KErrNone) + { + TFileName clientPrivatePath; + err = fs.PrivatePath(clientPrivatePath); + fs.Close(); + if(err == KErrNone) + { + TInt pos = aDbFileName.FindF(clientPrivatePath); + return (TUint)pos <= (TUint)KMaxDriveName ? EDbTypeClientPrivate : EDbTypeUnknown; + } + } + return err; + } + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////// RSqlDbSession ///////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** +Establishes a connection with the SQL server. + +The method initializes RSqlDbSession object establishing a connection with the SQL server. +If the connection has established successfully, the method sends a message to the server to +create or open (depending on aFunction parameter) a database file with aDbFileName name. + +@param aFunction Specifies which operation has to be performed: + ESqlSrvDbCreate - Create a shared non-secure or private secure database; + ESqlSrvDbCreateSecure - Create a shared secure database; + ESqlSrvDbOpen - Open a shared non-secure, shared secure or private secure database; + +@param aDbFileName Database file name, including the path. If it is a request for creating/opening + secure database, then the name format is :<[SID]database_file_name>. +@param aSecurityPolicyData Security policy data. Non-empty descriptor only for secure databases +@param aConfig the configuration string "PARAM=VALUE;...." + +@return KErrNone, the operation completed successfully; + KErrNoMemory, an out of memory condition has occured; + KErrBadName, bad database file name: zero length, directory name; + KErrAlreadyExists, database file already exists; + KErrNotReady, the drive does not exist or is not ready; + KErrInUse, the file has been opened already; + KErrNotFound, file not found; + KErrGeneral, no or invalid security policies (if the database to be opened is a secure database with bad security data); + KErrNotSupported, incompatible sql security version (if the database to be opened is a secure database with bad security data); + KErrPermissionDenied, the caller does not satisfy the relevant database security policies. + Note that database specific errors categorised as ESqlDbError, and + other system-wide error codes may also be returned. + KErrArgument invalid config string or config string length exceeds KSqlSrvMaxConfigStrLen. + +Usage of the IPC call arguments: + - Arg 0: [out] database file name length + - Arg 1: [out] database file name + - Arg 2: [out] security policies buffer length if aFunction is ESqlSrvDbCreateSecure + - Arg 3: [out] security policies buffer if aFunction is ESqlSrvDbCreateSecure +*/ +TInt RSqlDbSession::Connect(TSqlSrvFunction aFunction, const TDesC& aDbFileName, const TDesC8& aSecurityPolicyData, const TDesC8* aConfig) + { + const TInt KDefaultMsgBufLen = 128; + iLastErrorMessage = HBufC::New(KDefaultMsgBufLen); + if(!iLastErrorMessage) + { + return KErrNoMemory; + } + TInt err = DoCreateSession(); + if(err == KErrNone) + { + err = InitResourceTestData(); + if(err == KErrNone) + { + err = ::GetDbType(aDbFileName); + if(err >= 0) + { + if(err == EDbTypeClientPrivate) + {//The database is in the client's private data cage. Set err = KErrPermissionDenied. + err = KErrPermissionDenied; + } + else + {//Unknown database type. Try to connect. + err = DoConnect(aFunction, aDbFileName, aSecurityPolicyData, aConfig); + } + if(err == KErrPermissionDenied && aFunction != ESqlSrvDbCreateSecure) + { + //What do we have here now? - the operation is create/open non-secure, the error is KErrPermissionDenied. + //So, the dll will try now to create/open the database in the application's private data cage. + //What if the used database file name was "C:MyDb.db"!? - the dll will try to create/open + //"C:MyDb.db" in the application's data cage and there + //is a possibility that this operation my return a result, like KErrNotFound, which will hide the original + //error code (KErrPermissionDenied). + //The dll shall not try to create/open file in the application's data cage, if the format of the + //database file name is secure. + TParsePtrC parse(aDbFileName);//this call may panic if aDbFileName cannot be parsed, but it will panic the client + if(parse.PathPresent()) + { + //The caller or the SQL server has no enough rights to create or open the database with aDbFileName name. + //One of the reasons may be that the database file is in the caller's private data cage where the SQL + //server cannot create/open the database file. + //The SQL dll will try to create/open the database file on the client side and pass the file handle to the + //SQL server. + TSqlFhOpenCmdFunctor fhOpenCmdSender(*this, aDbFileName, aConfig); + err = CreateAndSendFileHandle(fhOpenCmdSender, + aFunction == ESqlSrvDbCreate ? RSqlDbSession::EDbfCreate : RSqlDbSession::EDbfOpen); + } + } + } + } + } + if(err != KErrNone) + { + Close(); + } + return err; + } + +/** +Sends a command to the server to attach an existing database to the current connection. + +The database can be: +@code + - shared secure database; + - shared non-secure database; + - private secure database; +@endcode + +@param aDbFileName Database file name. +@param aDbName Logical database name. + +@return KErrNone, the operation completed successfully; + KErrNoMemory, an out of memory condition has occured; + KErrBadName, bad database file name: zero length, directory name; + KErrNotReady, the drive does not exist or is not ready; + KErrInUse, the file has been opened already; + KErrNotFound, file not found; + KErrGeneral, no or invalid security policies (if the database to be opened is a secure database with bad security data); + KErrNotSupported, incompatible sql security version (if the database to be opened is a secure database with bad security data); + KErrPermissionDenied, the caller does not satisfy the relevant database security policies. + Note that database specific errors categorised as ESqlDbError, and + other system-wide error codes may also be returned. + +Usage of the IPC call arguments: +Arg 0: [out] Database file name length. +Arg 1: [out] Database file name. +Arg 2: [out] Logical database name length. +Arg 3: [out] Logical database name. +*/ +TInt RSqlDbSession::Attach(const TDesC& aDbFileName, const TDesC& aDbName) + { + TInt err = ::GetDbType(aDbFileName); + if(err >= 0) + { + if(err == EDbTypeClientPrivate) + {//The database is in the client's private data cage. Set err = KErrPermissionDenied. + err = KErrPermissionDenied; + } + else + {//Unknown database type. Try to attach. + err = SendReceive(ESqlSrvDbAttach, TIpcArgs(aDbFileName.Length(), &aDbFileName, aDbName.Length(), &aDbName)); + } + if(err == KErrPermissionDenied) + { + //What do we have here now? - the operation is "attach", the error is KErrPermissionDenied. + //Which means, it is (possibly) a secure database in the server private data cage and the caller + //failed to pass the security checks. + //So, the dll will try now to open the database assuming it is in the application's private data cage + //and pass the file and session handles to the server which will try to attach the database using the handles. + //What if the used database file name was "C:MyDb.db"!? (which means that the client's intention was + //to attach a public shared secure database) + //The dll will try to open "C:MyDb.db" in the application's data cage and there + //is a possibility that this operation may return a result, like KErrNotFound, which will + //hide the original error code (KErrPermissionDenied). + //The dll shall not try to attach a database from the application's data cage, if the format of the + //database file name is secure. + TParsePtrC parse(aDbFileName);//this call may panic if aDbFileName cannot be parsed, but it will panic the client + if(parse.PathPresent()) + { + TSqlFhAttachCmdFunctor fhAttachCmdSender(*this, aDbFileName, aDbName); + err = CreateAndSendFileHandle(fhAttachCmdSender, RSqlDbSession::EDbfOpen); + } + } + } + return err; + } + +/** +Copies a database. + +The method establishes a temporary connection with the SQL server and issues a request for copying +aSrcDbFileName database file to aDestDbFileName file. After the server completes the request +CopyDatabase() closes the connection. + +@param aSrcDbFileName Source database file name. +@param aDestDbFileName Destination database file name. + +@return KErrNone, the operation completed successfully; + KErrNoMemory, an out of memory condition has occured; + KErrBadName, bad database file name: zero length, directory name; + KErrAlreadyExists, target database file already exists; + KErrNotReady, the drive does not exist or is not ready; + KErrInUse, the file has been opened already; + KErrNotFound, file not found; + KErrPermissionDenied, the SID of the calling application does not match the SID of source or destination database. + Note that other system-wide error codes may also be returned. + +Usage of the IPC call arguments: +Arg 0: [out] source database file name length +Arg 1: [out] source database file name +Arg 2: [out] destination database file name length +Arg 3: [out] destination database file name +*/ +TInt RSqlDbSession::CopyDatabase(const TDesC& aSrcDbFileName, const TDesC& aDestDbFileName) + { + RSqlDbSession sess; + TInt err = sess.DoCreateSession(); + if(err == KErrNone) + { + err = sess.InitResourceTestData(); + if(err == KErrNone) + { + err = sess.SendReceive(ESqlSrvDbCopy, TIpcArgs(aSrcDbFileName.Length(), &aSrcDbFileName, aDestDbFileName.Length(), &aDestDbFileName)); + } + sess.Close(); + } + return err; + } + +/** +Deletes a database. + +The database can be: +@code + - shared secure database; + - shared non-secure database; + - private secure database; +@endcode + +The method establishes a temporary connection with the SQL server and issues a "delete" request regarding +aDbFileName database file. After the server completes the request DeleteDatabase() closes the connection. + +@param aDbFileName Database file name. It must include the path if it is not a secure database. + +@return KErrNone, the operation completed successfully; + KErrNoMemory, an out of memory condition has occured; + KErrBadName, bad database file name: zero length, directory name; + KErrNotReady, the drive does not exist or is not ready; + KErrInUse, the file has been opened already; + KErrNotFound, file not found; + KErrAccessDenied, access to the database file is denied (it might be a read-only file); + KErrPermissionDenied, the SID of the calling application does not match the SID of the database. + Note that other system-wide error codes may also be returned. + +Usage of the IPC call arguments: +Arg 0: [out] database file name length +Arg 1: [out] database file name +*/ +TInt RSqlDbSession::DeleteDatabase(const TDesC& aDbFileName) + { + RSqlDbSession sess; + TInt err = sess.DoCreateSession(); + if(err == KErrNone) + { + err = sess.InitResourceTestData(); + if(err == KErrNone) + { + err = ::GetDbType(aDbFileName); + if(err >= 0) + { + if(err == EDbTypeClientPrivate) + {//The database is in the client's private data cage. Set err = KErrPermissionDenied. + err = KErrPermissionDenied; + } + else + {//Unknown database type. Try to delete. + err = sess.SendReceive(ESqlSrvDbDelete, TIpcArgs(aDbFileName.Length(), &aDbFileName)); + } + if(err == KErrPermissionDenied) + { + //What do we have here now? - the operation is "delete db", the error is KErrPermissionDenied. + //So, the dll will try now to delete a database with the same name from the application's private data cage. + //What if the used database file name was "C:MyDb.db" and there is a such file in server's private + //data cage? - the dll will try to delete a file with name "C:MyDb.db" from the application's data cage + //and there is a possibility that this operation my pass or may return strange result, like KErrNotFound. + //Bith cases are not what the user would expect. + //The dll shall not try to delete a file from the application's data cage, if the format of the + //database file name is secure. + TParsePtrC parse(aDbFileName);//this call may panic if aDbFileName cannot be parsed, but it will panic the client + if(parse.PathPresent()) + { + //The caller or the SQL server has no enough rights to delete the database with aDbFileName name. + //One of the reasons may be that the database file is in the caller's private data cage where the SQL + //server cannot delete the database file. + //The SQL dll will try to delete the database file on the client side. + RFs fs; + err = fs.Connect(); + if(err == KErrNone) + { + err = fs.Delete(aDbFileName); + fs.Close(); + } + } + } + } + } + sess.Close(); + } + return err; + } + +/** +Retrieves a reference to the textual description of the error returned by the +most recent call to any of the functions: +- RSqlDatabase::Exec() +- RSqlStatement::Exec() +- RSqlStatement::Next() +- RSqlStatement::Reset() + +Note that the function can only return a reference to text for +database-specific type errors, i.e. those errors that are categorised as of +type ESqlDbError. + +If an error occurs during the retrieval of the last error message, the function silently ignores the error +and returns a NULL descriptor. + +@return A non-modifiable pointer descriptor representing the most recent error + message. Note that message may be NULL, i.e. the descriptor may have + zero length. + +Usage of the IPC call arguments: +Arg 0: [out] max length of the message buffer +Arg 1: [in/out] buffer for the last error message +*/ +TPtrC RSqlDbSession::LastErrorMessage() + { + TPtr msg(iLastErrorMessage->Des()); + msg.Zero(); + TInt size = 0; + while((size = SendReceive(ESqlSrvLastErrorMsg, TIpcArgs(msg.MaxLength(), &msg))) > KSqlClientBufOverflowCode) + { + HBufC* newMsgBuf = iLastErrorMessage->ReAlloc(size - KSqlClientBufOverflowCode); + if(!newMsgBuf) + { + break; + } + iLastErrorMessage = newMsgBuf; + msg.Set(iLastErrorMessage->Des()); + } + return msg; + } + +/** +Returns the ROWID of the most recent successful INSERT into the database +from this database connection. + +@return >0, the ROWID of the most recent successful INSERT into the database + from this database connection; + 0, if no successful INSERTs have ever occurred from this database connection + <0, if one of the system-wide error codes is returned + +Usage of the IPC call arguments: +Arg 0: [in/out] the receiving buffer for the last inserted ROWID +*/ +TInt64 RSqlDbSession::LastInsertedRowId() + { + TInt64 res; + TPtr8 ptr(reinterpret_cast (&res), sizeof(res)); + TInt err = SendReceive(ESqlSrvDbLastInsertedRowId, TIpcArgs(&ptr)); + return err == KErrNone ? res : err; + } + +/** +Retrieves the database security policies. + +@return A pointer to the created and internalized CSqlSecurityPolicy instance. + +@return KErrNone, the operation has completed successfully; + KErrNoMemory, an out of memory condition has occurred; + Note that the function may leave with some database specific errors categorised as + ESqlDbError or other system-wide error codes. + +Usage of the IPC call arguments: +Arg 0: [out] security policy buffer size +Arg 1: [in/out] buffer for the database security policies +*/ +TInt RSqlDbSession::GetSecurityPolicy(RSqlBufFlat& aSecurityPolicyBuf) + { + TPtr8 ptr(aSecurityPolicyBuf.BufPtr()); + TInt rc = KErrNone; + while((rc = SendReceive(ESqlSrvDbGetSecurityPolicy, TIpcArgs(ptr.MaxLength(), &ptr))) > KSqlClientBufOverflowCode) + { + rc = aSecurityPolicyBuf.ReAlloc(rc - KSqlClientBufOverflowCode); + if(rc != KErrNone) + { + break; + } + ptr.Set(aSecurityPolicyBuf.BufPtr()); + } + return rc; + } + +/** +Closes the database and releases the connection with the database server. +*/ +void RSqlDbSession::Close() + { + if(Handle()) + { + (void)SendReceive(ESqlSrvDbClose); + } + TSqlResourceTestData::Release(); + delete iLastErrorMessage; + iLastErrorMessage = NULL; + RSessionBase::Close(); + } + +/** +The method establishes a connection with the SQL server. + +@return KErrNone, The connection was established successfully; + KErrAlreadyExists, the connection already exists. + The function may also return some other system-wide error codes. +*/ +TInt RSqlDbSession::DoCreateSession() + { + const TInt KTimesToRetryConnection = 2; + TInt retry = KTimesToRetryConnection; + for(;;) + { + TInt err = CreateSession(KSqlSrvName, ::SqlSrvVersion()); + if(err != KErrNotFound && err != KErrServerTerminated) + { + return err; + } + if(--retry == 0) + { + return err; + } + err = ::StartSqlServer(); + if(err != KErrNone && err != KErrAlreadyExists) + { + return err; + } + } + } + +/** +The method gets called immediatelly after the establishing client-server connection but before the +create/open database message. +If a request was made by the client (using TSqlResourceTester methods) to test the server under out of memory +conditions, InitResourceTestData() will send this request to the server, putting the just created connection +in a "out of memory" test mode. +*/ +TInt RSqlDbSession::InitResourceTestData() + { + TInt err = KErrNone; +#ifdef _DEBUG + TSqlResourceTestData* data = TSqlResourceTestData::Instance(); + if(data) + { + data->Init(*this); + } + else + { + err = KErrNoMemory; + } +#endif + return err; + } + +/** +Creates/opens database file locally and sends the file handle to the SQL server. + +This function is used only when the SQL server fails to create/open/attach the requested database file with +KErrPermissionDenied error. One of the reasons for that error may be that the database file is in the +calling application's private data cage. In this case an attempt is made to create/open the database file locally +and if the operation completes successfully, then the file handle is passed to the SQL server. + +@param aFhCmdSender A reference to a functor instance which is used for sending the file handles to the SQL server. +@param aDbfAction It is set by the caller to RSqlDbSession::EDbfCreate if the database file has to be created or + to RSqlDbSession::EDbfOpen if the database file already exists and has to be opened + +@return KErrNone, the operation completed successfully; + KErrNoMemory, an out of memory condition has occured; + KErrBadName, bad database file name: zero length, directory name, missing drive in the file name; + KErrAlreadyExists, database file already exists; + KErrNotReady, the drive does not exist or is not ready; + KErrInUse, the file has been opened already; + KErrNotFound, file not found; + KErrPermissionDenied, the caller does not satisfy the relevant database security policies. + Note that database specific errors categorised as ESqlDbError, and + other system-wide error codes may also be returned. +*/ +TInt RSqlDbSession::CreateAndSendFileHandle(TSqlFhCmdFunctor& aFhCmdSender, RSqlDbSession::TDbfAction aDbfAction) + { + //Create a file session + RFs fs; + TInt err = fs.Connect(); + if(err != KErrNone) + { + return err; + } + //Share the file session + err = fs.ShareProtected(); + if(err != KErrNone) + { + fs.Close(); + return err; + } + //Create/open the database file locally + TBool readOnly = EFalse; + TBool fileCreated = EFalse; + RFile64 dbFile; + if(aDbfAction == RSqlDbSession::EDbfCreate) + {//Create the database file in R/W mode + err = dbFile.Create(fs, aFhCmdSender.iDbFileName, EFileShareAny | EFileWrite); + if(err == KErrNone) + { + fileCreated = ETrue; + } + } + else //aDbfAction == RSqlDbSession::EDbfOpen + {//Open the database file in shared R/W mode + err = dbFile.Open(fs, aFhCmdSender.iDbFileName, EFileShareAny | EFileWrite); + if(err != KErrNone) + {//If the the database open operation in R/W mode has failed - try to open the database in shared read-only mode. + readOnly = ETrue; + err = dbFile.Open(fs, aFhCmdSender.iDbFileName, EFileShareReadersOnly); + } + } + if(err == KErrNone) + {//Successful create/open database file operation. Send the database file and session handles to the server. + err = aFhCmdSender(dbFile, fileCreated, readOnly); + dbFile.Close(); + } + if(err != KErrNone && fileCreated) + { + dbFile.Close(); + TInt err2 = fs.Delete(aFhCmdSender.iDbFileName); + if(err2 != KErrNone) + {//Sometimes it is not possible the file to be deleted, the reported error is - KErrInUse. + fs.Close(); + User::After(100000); + err2 = fs.Connect(); + if(err2 == KErrNone) + { + (void)fs.Delete(aFhCmdSender.iDbFileName); + } + } + } + fs.Close(); + return err; + } + +/** +Prepares the "security & configuration" string and sends the command to the SQL server. + +@param aFunction Specifies which operation has to be performed: + ESqlSrvDbCreate - Create a shared non-secure or private secure database; + ESqlSrvDbCreateSecure - Create a shared secure database; + ESqlSrvDbOpen - Open a shared non-secure, shared secure or private secure database; + +@param aDbFileName Database file name, including the path. If it is a request for creating/opening + secure database, then the name format is :<[SID]database_file_name>. +@param aSecurityPolicyData Security policy data. Non-empty descriptor only for secure databases +@param aConfig the configuration string "PARAM=VALUE;...." + +@return KErrNone, the operation completed successfully; + KErrNoMemory, an out of memory condition has occured; + KErrArgument invalid config string or config string length exceeds KSqlSrvMaxConfigStrLen. + Other system-wide error codes may also be returned. + +*/ +TInt RSqlDbSession::DoConnect(TSqlSrvFunction aFunction, const TDesC& aDbFileName, const TDesC8& aSecurityPolicyData, const TDesC8* aConfig) + { + const TInt KConfigStrLen = aConfig ? aConfig->Length() : 0; + if(KConfigStrLen > KSqlSrvMaxConfigStrLen) + { + return KErrArgument; + } + const TInt KSecPolicyLen = aFunction == ESqlSrvDbCreateSecure ? aSecurityPolicyData.Length() : 0; + TIpcArgs ipcArgs(aDbFileName.Length(), &aDbFileName); + // pack the length xxxxyyyy where xxxx is the policy length + // and yyyy is the config length. + ipcArgs.Set(2, (TUint)(KSecPolicyLen << 16) | (TUint)KConfigStrLen); + const TInt KTotalLen = KConfigStrLen + KSecPolicyLen; + ipcArgs.Set(3, 0); + HBufC8* arg3Buf = NULL; + if(KTotalLen > 0) + { + arg3Buf = HBufC8::New(KTotalLen); + if(!arg3Buf) + { + return KErrNoMemory; + } + TPtr8 arg3Ptr = arg3Buf->Des(); + if(KSecPolicyLen > 0) + { + arg3Ptr.Copy(aSecurityPolicyData); + } + if(KConfigStrLen > 0) + { + //coverity[DEADCODE] + //The ASSERT might be useful in catching future defect in this function + __SQLASSERT(aConfig != NULL, ESqlPanicInternalError); + arg3Ptr.Append(*aConfig); + } + ipcArgs.Set(3, &arg3Ptr); + } + TInt err = SendReceive(aFunction, ipcArgs); + delete arg3Buf; + return err; + }