diff -r 000000000000 -r 08ec8eefde2f persistentstorage/dbms/sdbms/SD_SESS.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/persistentstorage/dbms/sdbms/SD_SESS.CPP Fri Jan 22 11:06:30 2010 +0200 @@ -0,0 +1,1056 @@ +// Copyright (c) 1998-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: +// DBMS server-session and support classes +// +// + +#include +#include "SD_STD.H" +#include "Sd_DbList.h" + +using namespace DBSC; + +/* +CDbsSession class is updated now to with a support for DBMS security policies. +What idea sits behind the update: +1) DBMS server has a set of server side CDbsSession objects. +2) Each CDbsSession object has a list of CDbsSession::TEntry items. + Each CDbsSession::TEntry item holds a server side DBMS object, which is + used to perform client requests. +3) CDbsSession::TEntry object could be: + - EDbsDatabase - database object. It operates at database level. + OpenDatabaseL is the method, which creates it. + - EDbsIncremental - incremental object. It operates either at database or table level. + NewIncrementalL is the method, which creates it. + - EDbsCursor - cursor object. It operates at table level. + NewCursorL is the method, which creates it. + - EDbsConstraint - constraint object. It is used at table level and needs the same + security policy as its table. + - EDbsStream - stream object. It operates either at database or table level. + NewStreamL are the methods, which create it. + - EDbsObserver - observer object. It operates at database level. +4) When DBMS server is used in a security environment, database/table security policies + describe allowed W/R operations for the database/tables. +5) Each database/table has a security policy object assiciated with it. It may be accessed + using MPolicy interface. +6) There is a MPolicySpace interface, which holds a collection of MPolicy interfaces + for the database/tables. MPolicy interfaces can be queried using MPolicySpace methods. +7) All DBMS server side objects, described in (3), operate at database/table level. In a + security environment, the client's access rights has to be checked, before performing + particular database/table operation. + It is known at the moment of DBMS object creation, on which database/table it will operate. + The database/table cannot be changed during the DBMS object life time. + At the moment of DBMS object creation, the related database/table interface is queried and + stored in CDbsSession::TEntry::iPolicy data member. + It is an error if CDbsSession::TEntry item exists without a security policy. +8) Every time, when a client needs particular DBMS server functionality and CDbsSession::ServiceL + has been called, the session object will find which DBMS server object has to be used and + asserts client's access rights against its security policy. + If the client has not enough access rights to perform desired DBMS operation, the DBMS + session will leave with KErrPermissionDenied error code. + ====================================================================================== + In one sentence - every time, when an object from CDbsSession::TEntry list is about to + perform particular operation at database/table level, the associated database/table + security policy will be checked and the opration may be rejected. +*/ + +// Class CDbsSession::TEntry + +// +// release the object +// +void CDbsSession::TEntry::Release() + { + TDbsType t=Type(); + __ASSERT(t!=EDbsFree); + if (t==EDbsObserver) + delete STATIC_CAST(CDbsObserver::HObserver*,iObject); + else if (t==EDbsStream) + delete STATIC_CAST(HDbsStream*,iObject); + else + CDbObject::Destroy(STATIC_CAST(CDbObject*,iObject)); + iType=TUint8(EDbsFree); + iPolicy = NULL; + } + +#ifdef __DBDUMP__ +//Using CDbsSession::TEntry::Dump() method you can dump the TEntry's content +//into a stream. Note that the dump works only if you have __DBDUMP__ macro defined. +void CDbsSession::TEntry::Dump(RFile& aFile) const + { + _LIT8(KClassName, "CDbsSession::TEntry. this=%X"); + _LIT8(KType, "Type=%S"); + _LIT8(KMagic, "Magic=%d"); + _LIT8(KCrLf, "\r\n"); + _LIT8(KEnd, "===="); + TPtrC8 KDbsType[EDbsMaxType + 1] = {_L8("Free"), _L8("Database"), _L8("Incremental"), _L8("Cursor"), _L8("Constraint"), _L8("Stream"), _L8("Observer")}; + TBuf8<40> buf; + + buf.Format(KClassName, this); + (void)aFile.Write(buf); + (void)aFile.Write(KCrLf); + buf.Format(KType, &KDbsType[iType]); + (void)aFile.Write(buf); + (void)aFile.Write(KCrLf); + buf.Format(KMagic, iMagic); + (void)aFile.Write(buf); + (void)aFile.Write(KCrLf); + __ASSERT(iPolicy); + iPolicy->Dump(aFile); + (void)aFile.Write(KEnd); + (void)aFile.Write(KCrLf); + } +#endif//__DBDUMP__ + +// Class CDbsSession + +// +// Release all this clients resources +// Streams must be released before cursors, and everything before the connection +// +CDbsSession::~CDbsSession() + { + TEntry* const base=&iIx[0]; + if (base) + { + TInt type=EDbsMaxType; + do { + for (TEntry* e=base+iSize;--e>=base;) + { + if (e->iType==type) + e->Release(); + } + } while (--type>EDbsFree); + User::Free(base); + } + iDbPolicyRqColl.Close(); + delete iSessDriveSpace; + Server().RemoveSession(); + } + +/** +Overrides virtual CSession2::Create2(). +Creates iSessDriveSpace instance. +*/ +void CDbsSession::CreateL() + { + iSessDriveSpace = CDbsSessDriveSpace::NewL(Server().DriveSpaceCol()); + } + +// +// provide for CSession +// If this leaves, we complete message through ServiceError(...) +// +void CDbsSession::ServiceL(const RMessage2& aMessage) + { + //set received message in server so it can be used in cleanup when server panics. + CPolicyProxy& policyProxy = Server().PolicyProxy(); + TDbsFunction f=DbsFunction(aMessage.Function()); + if (f&KDbsObjectReturn) // may return a derived object + AllocL(); // ensure index space + TInt r=0;//object handle + TInt h=DbsHandle(aMessage.Function()); + if (h==KDbsSessionHandle) + { // session based requests + switch (f&~KDbsObjectReturn) + { + case EDbsResourceMark: + ResourceCountMarkStart(); + break; + case EDbsResourceCheck: + ResourceCountMarkEnd(aMessage); + break; + case EDbsResourceCount: + r=CountResources(); + break; + case EDbsSetHeapFailure: + User::__DbgSetAllocFail(RHeap::EUser,RHeap::TAllocFail(aMessage.Int0()),aMessage.Int1()); + break; + case EDbsOpenDatabase: + r=OpenDatabaseL(aMessage); + break; + case EDbsReserveDriveSpace: + ReserveDriveSpaceL(static_cast (aMessage.Int0())); + break; + case EDbsFreeReservedSpace: + FreeReservedSpace(static_cast (aMessage.Int0())); + break; + case EDbsReserveGetAccess: + GetReserveAccessL(static_cast (aMessage.Int0())); + break; + case EDbsReserveReleaseAccess: + ReleaseReserveAccess(static_cast (aMessage.Int0())); + break; + default: + r=ExtServiceL(aMessage, static_cast (f&~KDbsObjectReturn)); + break; + } + } + else + { // object based requests + TEntry& e=Object(h); + __ASSERT(e.iPolicy); + policyProxy.CheckL(aMessage, *e.iPolicy); + TDbsFunction dbmsFuncNo = static_cast (f & ~KDbsObjectReturn); + switch (dbmsFuncNo) + { + // the common close function + case EDbsClose: + //If this is a database object, remove the related pair (handle, uid) from iDbPolicyRqColl collection. + if(e.Type() == EDbsDatabase) + { + iDbPolicyRqColl.Remove(h); + } + Free(e); + break; + // database functions + case EDbsDatabaseAuthenticate: + { + __LEAVE(KErrNotSupported); + } + break; + case EDbsDatabaseDestroy: + r=e.Database().Destroy(); + break; + case EDbsDatabaseBegin: + r=e.Database().Begin(); + break; + case EDbsDatabaseCommit: + r=e.Database().Commit(); + break; + case EDbsDatabaseRollback: + e.Database().Rollback(); + break; + case EDbsDatabaseProperty: + r=e.Database().Property(CDbDatabase::TProperty(aMessage.Int0())); + break; + case EDbsDatabaseTables: + {//The new stream object will have the same security policy as the database + //Read only stream + CDbTableNames* names=CDbTableNames::NewLC(); + e.Database().TablesL(*names); + r=NewStreamL(names,Externalizer(names),aMessage,e.iPolicy); + } + break; + case EDbsDatabaseColumns: + {//The new stream object will have the same security policy as the database + //Read only stream + CDbColSet* set=CDbColSet::NewLC(); + e.Database().ColumnsL(*set,ReadName0L(0,aMessage)); + r=NewStreamL(set,Externalizer(set),aMessage,e.iPolicy); + } + break; + case EDbsDatabaseIndexes: + {//The new stream object will have the same security policy as the database + //Read only stream + CDbIndexNames* names=CDbIndexNames::NewLC(); + e.Database().IndexesL(*names,ReadName0L(0,aMessage)); + r=NewStreamL(names,Externalizer(names),aMessage,e.iPolicy); + } + break; + case EDbsDatabaseKeys: + {//The new stream object will have the same security policy as the database + //Read only stream + CDbKey* key=CDbKey::NewLC(); + e.Database().KeysL(*key,ReadName0L(0,aMessage),ReadName1L(1,aMessage)); + r=NewStreamL(key,Externalizer(key),aMessage,e.iPolicy); + } + break; + case EDbsDatabaseCreateTable: + { + const TDesC& name=ReadName0L(0,aMessage); + CDbColSet* set=ColSetLC(1,aMessage); + CDbKey* primary=0; + if (aMessage.Ptr2()) + primary=KeyLC(2,aMessage); + + e.Database().CreateTableL(name,*set,primary); + if (primary) + CleanupStack::PopAndDestroy(); // primary + CleanupStack::PopAndDestroy(); // set + } + break; + case EDbsDatabaseOpenObserver: + //The new observer object will have the same security policy as the database + r=Add(CDbsConnection::Source(e.Database()).ObserverL(),e.iPolicy); + break; + case EDbsDatabaseOpenUtility: + {//The new incremental object will have the same security policy as the database + TInt step; + r=NewIncrementalL(e.Database().UtilityL(CDbDatabase::TUtility(aMessage.Int0()),step),step,aMessage,e.iPolicy); + } + break; + case EDbsDatabaseOpenDropTable: + {//The new incremental object will have the same security policy as the database + TInt step; + const TDesC& name=ReadName0L(0,aMessage); + r=NewIncrementalL(e.Database().DropTableL(name,step),step,aMessage,e.iPolicy); + } + break; + case EDbsDatabaseOpenAlterTable: + {//The new incremental object will have the same security policy as the database + TInt step; + const TDesC& name=ReadName0L(0,aMessage); + CDbColSet* set=ColSetLC(1,aMessage); + r=NewIncrementalL(e.Database().AlterTableL(name,*set,step),step,aMessage,e.iPolicy); + CleanupStack::PopAndDestroy(); // set + } + break; + case EDbsDatabaseOpenCreateIndex: + {//The new incremental object will have the same security policy as the database + TInt step; + const TDesC& name=ReadName0L(0,aMessage); + const TDesC& table=ReadName1L(1,aMessage); + CDbKey* key=KeyLC(2,aMessage); + r=NewIncrementalL(e.Database().CreateIndexL(name,table,*key,step),step,aMessage,e.iPolicy); + CleanupStack::PopAndDestroy(); // key + } + break; + case EDbsDatabaseOpenDropIndex: + {//The new incremental object will have the same security policy as the database + TInt step; + const TDesC& name=ReadName0L(0,aMessage); + const TDesC& table=ReadName1L(1,aMessage); + r=NewIncrementalL(e.Database().DropIndexL(name,table,step),step,aMessage,e.iPolicy); + } + break; + case EDbsDatabaseExecute: + {//The new incremental object will have the same security policy as the database or table - sql dependent. + //In order EDbsDatabaseExecute request to be performed, the DBMS session has already + //checked the client capabilities at the database level. + //Now, the sql string will be parsed and the client capabilities will be checked + //again at more specific database or table level. + TInt init; + HBufC* sql=ReadHBufLC(0,aMessage); + const TDbPolicyRequest& rq = iDbPolicyRqColl[h]; + TPolicyType policyType = EPTNone; + const MPolicy* policy = policyProxy.SqlPolicyL(rq, *sql, policyType); + policyProxy.CheckL(policyType, aMessage, *policy); + r=NewIncrementalL(e.Database().ExecuteL(*sql,TDbTextComparison(aMessage.Int1()),init),init,aMessage,policy); + CleanupStack::PopAndDestroy(sql); + } + break; + case EDbsDatabasePrepareView: + {//The new cursor object will have the same security policy as the table in the sql string. + //In order EDbsDatabasePrepareView request to be performed, the DBMS session has already + //checked the client capabilities at the database level. + //Now, the sql string will be parsed and the client capabilities will be checked + //again at table level. + HBufC* sql=ReadHBufLC(0,aMessage); + const TDbPolicyRequest& rq = iDbPolicyRqColl[h]; + TPolicyType policyType = EPTNone; + const MPolicy* policy = policyProxy.SqlPolicyL(rq, *sql, policyType); + policyProxy.CheckL(policyType, aMessage, *policy); + TPckgBuf window; + aMessage.ReadL(2,window); + TInt mode=aMessage.Int1(); + CDbCursor* cursor=e.Database().ViewL(TDbQuery(*sql,TDbTextComparison(mode&0xff)),window(),RDbRowSet::TAccess(mode>>8)); + r=NewCursorL(cursor,aMessage,policy); + CleanupStack::PopAndDestroy(sql); + } + break; + case EDbsDatabaseOpenTable: + {//The new cursor object will have the same security policy as the table + const TDesC& name=ReadName0L(0,aMessage); + const TDbPolicyRequest& rq = iDbPolicyRqColl[h]; + const MPolicy* policy = policyProxy.TblPolicyL(rq, name); + //Check caller capabilities against the table policy + RDbRowSet::TAccess accessType = static_cast (aMessage.Int1()); + TPolicyType policyType = accessType == RDbRowSet::EReadOnly ? EPTRead : EPTWrite; + policyProxy.CheckL(policyType, aMessage, *policy); + //Create cursor + r=NewCursorL(e.Database().TableL(name,accessType),aMessage,policy); + } + break; + // Incremental functions + case EDbsIncrementalNext: + { + TPckgBuf step=aMessage.Int0(); + r=e.Incremental().NextL(step()); + aMessage.WriteL(1,step); + } + break; + // Observer functions + case EDbsObserverNotify: + e.Observer().Notify(aMessage); + return; // deferred completion of the message! + case EDbsObserverCancel: + e.Observer().Cancel(); + break; + // cursor functions + case EDbsCursorColumnTypes: + { + TInt count=e.Cursor().ColumnCount(); + TUint8* types=(TUint8*)User::AllocLC(count); + for (TInt ii=count;--ii>=0;) + types[ii]=TUint8(e.Cursor().ColumnType(ii+1)); + aMessage.WriteL(3,TPtrC8(types,count)); + CleanupStack::PopAndDestroy(); + } + break; + case EDbsCursorReset: + e.Cursor().Reset(); + break; + case EDbsCursorEvaluate: + r=e.Cursor().EvaluateL()?1:0; + break; + case EDbsCursorUnevaluated: + r=e.Cursor().Unevaluated()?1:0; + break; + case EDbsCursorSetIndex: + { + const TDesC* name=0; + if (aMessage.Ptr0()) + name=&ReadName0L(0,aMessage); + e.Cursor().SetIndexL(name); + } + break; + case EDbsCursorSeek: + { + TDbLookupKey* key=LookupKeyLC(0,aMessage.Int1(),aMessage); + r=e.Cursor().SeekL(*key,RDbTable::TComparison(aMessage.Int2()))?1:0; + CleanupStack::PopAndDestroy(); // key; + } + break; + case EDbsCursorAtBeginning: + r=e.Cursor().AtBeginning()?1:0; + break; + case EDbsCursorAtEnd: + r=e.Cursor().AtEnd()?1:0; + break; + case EDbsCursorAtRow: + r=e.Cursor().AtRow()?1:0; + break; + case EDbsCursorCount: + r=e.Cursor().CountL(RDbRowSet::TAccuracy(aMessage.Int0()))+1; + break; + case EDbsCursorGotoPos: + if (e.Cursor().GotoL(RDbRowSet::TPosition(aMessage.Int0()))) + { + e.Cursor().GetL(); + r=RetrieveRowL(e.Cursor(),aMessage); + } + break; + case EDbsCursorBookmark: + { + TPckgBuf mark; + e.Cursor().Bookmark(mark()); + aMessage.WriteL(3,mark); + } + break; + case EDbsCursorGotoBookmark: + { + TPckgBuf mark; + aMessage.ReadL(0,mark); + e.Cursor().GotoL(mark()); + } + break; + case EDbsCursorGet: + e.Cursor().GetL(); + r=RetrieveRowL(e.Cursor(),aMessage); + break; + case EDbsCursorInsert: + e.Cursor().InsertL(CDbCursor::TInsert(aMessage.Int0())); + r=RetrieveRowL(e.Cursor(),aMessage); + break; + case EDbsCursorUpdate: + e.Cursor().UpdateL(); + r=RetrieveRowL(e.Cursor(),aMessage); + break; + case EDbsCursorRetrieveRow: // pass the row buffer back to the client + r=RetrieveRowL(e.Cursor(),aMessage); + break; + case EDbsCursorCancel: + e.Cursor().Cancel(); + break; + case EDbsCursorPut: + PutRowL(e.Cursor(),aMessage); + e.Cursor().PutL(); + break; + case EDbsCursorDelete: + e.Cursor().DeleteL(); + break; + case EDbsCursorColumns: + {// reduce memory usage by extracting and stream columns individually + //Read only stream + RWriteStream strm(HBufBuf::NewLC()); + TInt count=e.Cursor().ColumnCount(); + strm.WriteInt32L(count); + TDbCol col; + for (TInt ii=0;++ii<=count;) + { + e.Cursor().ColumnDef(col,ii); + strm<SizeL(); + CleanupStack::Pop(); // stream + r=NewStreamL(strm.Sink(),aMessage,e.iPolicy,ext); + } + break; + case EDbsCursorColumnDef: + { + TPckgBuf col; + e.Cursor().ColumnDef(col(),aMessage.Int0()); + aMessage.WriteL(3,col); + } + break; + case EDbsCursorSetNull: + __ASSERT(TDbCol::IsLong(e.Cursor().ColumnType(aMessage.Int0()))); + e.Cursor().SetNullL(aMessage.Int0()); + break; + case EDbsCursorColumnSize: + __ASSERT(TDbCol::IsLong(e.Cursor().ColumnType(aMessage.Int0()))); + r=e.Cursor().ColumnSize(aMessage.Int0()); + break; + case EDbsCursorColumnSource: + __ASSERT(TDbCol::IsLong(e.Cursor().ColumnType(aMessage.Int0()))); + {//The new stream object will have the same security policy as the table + //Read only stream, used for large BLOB fields. + TDbColNo col=aMessage.Int0(); + CDbCursor& cursor=e.Cursor(); + r=NewStreamL(cursor.ColumnSourceL(col),aMessage,e.iPolicy,cursor.ColumnSize(col)); + } + break; + case EDbsCursorColumnSink: + //The new stream object will have the same security policy as the table + //Write stream, used for large BLOB fields. + r=NewStreamL(e.Cursor().ColumnSinkL(aMessage.Int0()),aMessage,e.iPolicy); + break; + case EDbsCursorOpenConstraint: + {//The new constraint object will have the same security policy as the table + HBufC* sql=ReadHBufLC(0,aMessage); + CDbRowConstraint* ct=e.Cursor().ConstraintL(TDbQuery(*sql,TDbTextComparison(aMessage.Int1()))); + CleanupStack::PopAndDestroy(); //sql + r=Add(ct, e.iPolicy); + } + break; + case EDbsCursorMatch: + r=e.Cursor().MatchL(Object(aMessage.Int0()).Constraint())?1:0; + break; + case EDbsCursorFind: + { + HBufC* sql=ReadHBufLC(0,aMessage); + TDbQuery q(*sql,TDbTextComparison(aMessage.Int1())); + r=e.Cursor().FindL(RDbRowSet::TDirection(aMessage.Int2()),q)-KErrNotFound; + CleanupStack::PopAndDestroy(); //sql + } + break; + // stream functions + case EDbsStreamRead: + { + r=e.Stream().ReadL(aMessage); + } + break; + case EDbsStreamWrite: + { + e.Stream().WriteL(aMessage); + } + break; + case EDbsStreamSize: + { + r=e.Stream().SizeL(); + } + break; + case EDbsStreamSynch: + { + e.Stream().SynchL(); + } + break; + // we don't know about any other functions + default: + r=KErrNotSupported; + break; + } + } + + // don't complete message if we have paniced client, just reset variable; + if (!aMessage.IsNull()) + aMessage.Complete(r); + } + + +// Handle an error from CDbsSession::ServiceL() +// A bad descriptor error implies a badly programmed client, so panic it; +// otherwise use the default handling (report the error to the client) +void CDbsSession::ServiceError(const RMessage2& aMessage,TInt aError) + { +#ifdef __DBDUMP__ + Dump(); +#endif//__DBDUMP__ + if (aError==KErrBadDescriptor) + { + // this completes message as well so we have to handle it in + // ServiceL + _LIT(KCategory,"DBMS-server"); + Server().Panic(KCategory,EDbsBadDescriptor); + } + CSession2::ServiceError(aMessage,aError); + } + +// Read aPtr as a name +const TDesC& CDbsSession::ReadName0L(TInt aIndex,const RMessage2& aMessage) + { + TDes& name=Server().Name0(); + aMessage.ReadL(aIndex,name); + return name; + } + +// Read Ptr1 as a name +const TDesC& CDbsSession::ReadName1L(TInt aIndex,const RMessage2& aMessage) + { + TDes& name=Server().Name1(); + aMessage.ReadL(aIndex,name); + return name; + } + +// Reads aPtr as a variable length 8-bit descriptor +HBufC8* CDbsSession::ReadHBuf8LC(TInt aIndex,const RMessage2& aMessage) + { + TInt len= aMessage.GetDesLengthL(aIndex); + HBufC8* buf=HBufC8::NewLC(len); + TPtr8 read(buf->Des()); + aMessage.ReadL(aIndex,read); + return buf; + } + +// Reads aPtr as a variable length build-width descriptor +HBufC* CDbsSession::ReadHBufLC(TInt aIndex,const RMessage2& aMessage) + { + TInt len= aMessage.GetDesLengthL(aIndex); + HBufC* buf=HBufC::NewLC(len); + TPtr read(buf->Des()); + aMessage.ReadL(aIndex,read); + return buf; + } + +// Pulls a column set from the client +CDbColSet* CDbsSession::ColSetLC(TInt aIndex,const RMessage2& aMessage) + { + CDbColSet* set=CDbColSet::NewLC(); + HBufC8* data=ReadHBuf8LC(aIndex,aMessage); + RDesReadStream strm(*data); + strm>>*set; + CleanupStack::PopAndDestroy(); // data + return set; + } + +// Pulls a key from the client +CDbKey* CDbsSession::KeyLC(TInt aIndex,const RMessage2& aMessage) + { + CDbKey* key=CDbKey::NewLC(); + HBufC8* data=ReadHBuf8LC(aIndex,aMessage); + RDesReadStream strm(*data); + strm>>*key; + CleanupStack::PopAndDestroy(); // data + return key; + } + +// Reconstructs a TDbLookupKey from the message parameter +TDbLookupKey* CDbsSession::LookupKeyLC(TInt aIndex,TInt aSize,const RMessage2& aMessage) + { + TDbLookupKey* key=(TDbLookupKey*)User::AllocLC(aSize); + TPtr8 pckg((TUint8*)key,aSize); + aMessage.ReadL(aIndex,pckg); + TDbLookupKey::SColumn* iter=CONST_CAST(TDbLookupKey::SColumn*,key->First()); + const TDbLookupKey::SColumn* end=iter+key->Count(); + if ((TUint8*)end-(TUint8*)keyiType) + { + default: + break; + case EDbColText8: + iter->iDes8.iPtr=(TUint8*)key+TInt(iter->iDes8.iPtr); + break; + case EDbColText16: + iter->iDes16.iPtr=(TUint16*)((TUint8*)key+TInt(iter->iDes8.iPtr)); + break; + }; + } while (++iter0 && size<=aMessage.Int2()) + aMessage.WriteL(3,TPtrC8((const TUint8*)aRow.First(),size)); + return size+1; // return 0 reserved for Goto + } + +// Returns a row to the client +TInt CDbsSession::RetrieveRowL(CDbCursor& aCursor,const RMessage2& aMessage) + { + RDbRow* pRow=aCursor.RowBuffer(); + if (pRow) // direct row transfer + return WriteRowL(*pRow,aMessage); + // need to retrieve columns independantly + RDbRow row; + row.PushL(); + TInt max=aCursor.ColumnCount(); + for (TInt ii=0;++ii<=max;) + TDbColumn(row,ii).SetL(aCursor.ColumnC(ii)); + TInt size=WriteRowL(row,aMessage); + CleanupStack::PopAndDestroy(); // row + return size; + } + +//This method creates new EDbsCursor type object. +//It is used at table level so it needs table object security policies. +//The related table MPolicy interface will be +//put together with the EDbsCursor object in TEntry list. +// +//Complete the cursor construction +TInt CDbsSession::NewCursorL(CDbCursor* aCursor,const RMessage2& aMessage, const MPolicy* aTblSecurityPolicy) + { + aCursor->PushL(); // it has a context: use safe cleanup + TPckgBuf cols; + TInt ii=cols().iCount=aCursor->ColumnCount(); + if (ii<=cols().EMax) + { + while (--ii>=0) + cols().iData[ii]=TUint8(aCursor->ColumnType(ii+1)); + } + aMessage.WriteL(3,cols); + CleanupStack::Pop(aCursor); + return Add(aCursor, aTblSecurityPolicy); + } + +//This method creates new EDbsIncremental type object. +//It is used either at database or table level so it needs database or table object +//security policies. The related database/table MPolicy interface will be +//put together with the EDbsIncremental object in TEntry list. +// +//Complete a message which returns an incremental object by writing the step back +//When there is no work to do, aIncremental may be 0: then return a null handle +TInt CDbsSession::NewIncrementalL(CDbIncremental* aIncremental, + TInt& aInit,const RMessage2& aMessage, + const MPolicy* aPolicy) + { + aIncremental->PushL(); // it has a context: use safe cleanup + aMessage.WriteL(3,TPckgC(aInit)); + CleanupStack::Pop(); + return aIncremental ? Add(aIncremental, aPolicy) : 0; + } + +//This method creates new EDbsStream type object. +//It is used either at database or table level so it needs either +//database or table object security policies. +//The related database/table MPolicy interface will be +//put together with the EDbsStream object in TEntry list. +// +//Complete a stream based message return +TInt CDbsSession::NewStreamL(MStreamBuf* aHost,const RMessage2& aMessage, + const MPolicy* aPolicy,TInt aExtent) + { + aHost->PushL(); + TPckgBuf buf; + if (aExtent>0) // read the first buffer-full + aHost->ReadL(buf().iData,Min(aExtent,KDbsStreamBufSize)); + TInt h=0; + if (aExtent<0 || aExtent>KDbsStreamBufSize) + { // create the stream object + HDbsStream* stream = new(ELeave) HDbsStream(aHost,KDbsStreamBufSize); + h=Add(stream, aPolicy); + CleanupStack::Pop(); // aHost + } + else // no more data to send + CleanupStack::PopAndDestroy(); // aHost + if (aExtent>=0) + { + buf().iExt=aExtent; + aMessage.WriteL(3,buf); + } + return h; + } + +//This method creates new EDbsStream type object. +//It is used at database level so it needs the database object security policies. +//The related database MPolicy interface will be +//put together with the EDbsStream object in TEntry list. +// +//Generic object passing code +//aPtr should be on the cleanup stack, aExter can externalize it +TInt CDbsSession::NewStreamL(TAny* aPtr,TExternalizeFunction aExter, + const RMessage2& aMessage, const MPolicy* aDbSecurityPolicy) + { + RWriteStream strm(HBufBuf::NewLC()); + aExter(aPtr,strm); + strm.CommitL(); + TInt ext=strm.Sink()->SizeL(); + CleanupStack::Pop(); // host + CleanupStack::PopAndDestroy(); // aPtr + TInt res = NewStreamL(strm.Sink(),aMessage,aDbSecurityPolicy,ext); + return res; + } + +//allocates a free entry if required +void CDbsSession::AllocL() + { + __ASSERT(TUint(iFree)<=TUint(iSize)); + if (iFree==iSize) + { + TInt size=iSize+EIndexGranularity; + if (size>KDbsIndexLimit) // maximum number of objects reached + __LEAVE(KErrNoMemory); + TEntry* ix=iIx=(TEntry*)User::ReAllocL(iIx,size*sizeof(TEntry)); + iSize=size; + for (TInt ii=iFree;iiiMagic,e->Type())!=aHandle) + e=0; + } + __ASSERT_ALWAYS(e && e->iPolicy,::Panic(EDbsBadHandle)); + return *e; + } + +// Reports how many objects are allocated by the client +TInt CDbsSession::CountResources() + { + TInt alloc=0; + const TEntry* const base=iIx; + if (base) + { + for (const TEntry* e=base+iSize;--e>=base;) + { + if (e->Type()!=EDbsFree) + ++alloc; + } + } + return alloc; + } + +#ifdef __DBDUMP__ +//Using CDbsSession::Dump() method you can dump the session content +//into a stream. Note that the dump works only if you have __DBDUMP__ macro defined. +void CDbsSession::Dump() + { + RFile dumpFile; + RFs fileSess; + TInt err = fileSess.Connect(); + if(err == KErrNone) + { + _LIT(KDumpFileName, "_:\\PUBLIC\\DBMS\\DUMP%X.TXT"); + TFileName dumpFileName(KDumpFileName); + dumpFileName[0] = 'A' + static_cast(RFs::GetSystemDrive()); + + TBuf<40> buf; + buf.Format(dumpFileName, this); + err = fileSess.MkDirAll(buf); + if(err == KErrNone || err == KErrAlreadyExists) + { + err = dumpFile.Replace(fileSess, buf, EFileWrite); + if(err == KErrNone) + { + TEntry* const base = iIx; + if(base) + { + for(TEntry* e=base+iSize;--e>=base;) + { + if(e->Type() != EDbsFree) + { + e->Dump(dumpFile); + } + } + }//end of - if(base) + }//end of - if(err == KErrNone) + } + }//end of - if(err == KErrNone) + dumpFile.Close(); + fileSess.Close(); + RDebug::Print(_L("CDbsSession::Dump() error=%d\n"), err); + __ASSERT_ALWAYS(err == KErrNone, User::Invariant()); + } +#endif//__DBDUMP__ + +/** +Reserves a prederfined amount of disk space on aDrive drive. +At the moment the max possible amount, allowed by the file server, is reserved on aDrive drive. + +Use this call to ensure that if your "delete records" transaction fails because of "out of +disk space" circumstances, you can get an access to the already reserved disk space and +complete your transaction successfully the second time. + +There is no strong, 100% guarantee, that the reserved disk space will always help the client +in "low memory" situations. + +This method processes EDbsReserveDriveSpace message. + +@param aDrive Drive number to reserve space on +@leave KErrArgument Invalid aDrive value. +@leave CDbsSessDriveSpace::ReserveL() leaving error codes +@see CDbsSessDriveSpace::ReserveL() +*/ +void CDbsSession::ReserveDriveSpaceL(TDriveNumber aDrive) + { + if(aDrive < EDriveA || aDrive > EDriveZ) + { + __LEAVE(KErrArgument); + } + iSessDriveSpace->ReserveL(aDrive); + } + +/** +The method frees the reserved by the DBMS session disk space. + +This method processes EDbsFreeReservedSpace message. + +@param aDrive Drive number, which reserved space has to be freed. +@see CDbsSessDriveSpace::Free() +@panic Client side panic "DBMS-server 10" in debug mode, if the drive number is invalid. +@panic In debug mode there will be a panic with the line number as an error code if + there is no reserved disk space for aDrive. +@panic In debug mode there will be a panic with the line number as an error code if + the reserved disk space is granted but not released. +*/ +void CDbsSession::FreeReservedSpace(TDriveNumber aDrive) + { + TBool valid = aDrive >= EDriveA && aDrive <= EDriveZ; + __ASSERT_DEBUG(valid, ::Panic(EDbsInvalidDrive)); + if(valid) + { + iSessDriveSpace->Free(aDrive); + } + } + +/** +Grants access to a given area on a given drive for CDbsSession session. +Note this session must have reserved space on this particular drive in order to be +granted access to the reserved area. + +This method processes EDbsReserveGetAccess message. + +@param aDrive Drive number with a reserved disk space, an access to which is requested. +@leave KErrArgument Invalid drive. +@leave CDbsSessDriveSpace::GrantAccessL() leaving error codes +@see CDbsSessDriveSpace::GrantAccessL() +*/ +void CDbsSession::GetReserveAccessL(TDriveNumber aDrive) + { + if(aDrive < EDriveA || aDrive > EDriveZ) + { + __LEAVE(KErrArgument); + } + iSessDriveSpace->GrantAccessL(aDrive); + } + +/** +Revokes access on a given drive for CDbsSession session. + +This method processes EDbsReserveReleaseAccess message. + +@param aDrive Drive number with a reserved disk space, the access to which has to be released. +@panic Client side panic "DBMS-server 10" in debug mode, if the drive number is invalid. +@panic In debug mode there will be a panic with the line number as an error code if + there is no reserved disk space for aDrive. +@panic In debug mode there will be a panic with the line number as an error code if + there is no granted access to the reserved disk space. +*/ +void CDbsSession::ReleaseReserveAccess(TDriveNumber aDrive) + { + TBool valid = aDrive >= EDriveA && aDrive <= EDriveZ; + __ASSERT_DEBUG(valid, ::Panic(EDbsInvalidDrive)); + if(valid) + { + iSessDriveSpace->ReleaseAccess(aDrive); + } + }