--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/persistentstorage/sql/SRC/Server/SqlSrvFileData.cpp Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,281 @@
+// Copyright (c) 2006-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 "SqlSrvFileData.h"
+#include "SqlSrvUtil.h"
+#include "SqlPanic.h"
+#include "SqlSrvStrings.h"
+#include "SqlSrvResourceProfiler.h"
+
+_LIT(KPrivateFmtStr, "\\private\\%08X\\");
+
+/**
+Creates SQL server private data path on the specified drive.
+
+The idea for calling it is to make sure that the server's private data path exists before making any other
+operation - attempting to create a database file there for example.
+
+@param aFs File session instance
+@param aDriveNumber Drive number on which the private path has to be created
+
+@internalComponent
+*/
+static void CreatePrivateDataPathL(RFs& aFs, TDriveNumber aDriveNumber)
+ {
+ TDriveInfo driveInfo;
+ __SQLLEAVE_IF_ERROR(aFs.Drive(driveInfo, aDriveNumber));
+ if(!(driveInfo.iDriveAtt & KDriveAttRom))
+ {
+ TInt err = aFs.CreatePrivatePath(aDriveNumber);
+ if(err != KErrNone && err != KErrAlreadyExists)
+ {
+ __SQLLEAVE(err);
+ }
+ }
+ }
+
+/**
+@return Zero if aDbFileName is a non-secure file name (contains the path), non-zero otherwise.
+
+@internalComponent
+*/
+static TBool IsSecureFileNameFmt(const TDesC& aDbFileName)
+ {
+ TParsePtrC parse(aDbFileName);//this call may panic if aDbFileName cannot be parsed, but SetL() already parsed it
+ return !parse.PathPresent();
+ }
+
+/**
+The function parses thr database file name argument and extracts the SID from it (if the name contains SID).
+The SID is expected to be found at position 0 of the file name and must have 8 hex digits.
+
+@param aDbFileName Database file name
+
+@return Database security UID or KNullUid if the database name does not contain SID.
+
+@internalComponent
+*/
+static TUid ExtractSID(const TDesC& aDbFileName)
+ {
+ TParsePtrC parse(aDbFileName);//this call may panic if aDbFileName cannot be parsed, but SetL() already parsed it
+ TPtrC dbName = parse.Name();
+ TInt pos1 = dbName.Locate(TChar('['));
+ TInt pos2 = dbName.Locate(TChar(']'));
+ if(pos1 == 0 && pos2 == 9) //position 0 for '[', 8 digits SID, position 9 for ']'
+ {
+ TLex lex(dbName.Mid(pos1 + 1, pos2 - pos1 - 1));
+ TUid securityUid;
+ TInt err = lex.Val(*(TUint32*)&securityUid, EHex);
+ if(err == KErrNone)
+ {
+ return securityUid;
+ }
+ }
+ return KNullUid;
+ }
+
+/**
+@return ETrue if the aDbFileName argument contains aPrivatePath as a first directory in the file path, EFalse otherwise.
+
+@internalComponent
+*/
+static TBool IsPrivatePathInFileName(const TDesC& aDbFileName, const TDesC& aPrivatePath)
+ {
+ TInt pos = aDbFileName.FindF(aPrivatePath);
+ return (TUint)pos <= (TUint)KMaxDriveName;
+ }
+
+/**
+The method parses aFileName argument and constructs the full database file name (including the path) there.
+The full file name will be constructed in aFileName input/output argument.
+
+@param aDbFileName Input/Output. Database file name will be constructed there.
+@param aSysDrivePrivatePath SQL server private path on the system drive.
+@param aDrive Output parameter. The drive number.
+
+@leave KErrBadName Missing file name.
+
+@panic SqlDb 7 In _DEBUG mode - no drive in the final file path.
+
+@internalComponent
+*/
+static void DoFullFileNameL(TDes& aDbFileName, const TDesC& aSysDrivePrivatePath, TDriveNumber& aDrive)
+ {
+ TParse parse;
+ __SQLLEAVE_IF_ERROR(parse.Set(aDbFileName, &aSysDrivePrivatePath, NULL));
+ if(!parse.NamePresent())
+ {
+ __SQLLEAVE(KErrBadName);
+ }
+ aDbFileName.Copy(parse.FullName());
+ TPtrC driveName = parse.Drive();
+ __SQLASSERT(driveName.Length() > 0, ESqlPanicInternalError);
+ TInt driveNumber = -1;
+ __SQLLEAVE_IF_ERROR(RFs::CharToDrive(driveName[0], driveNumber));
+ aDrive = static_cast <TDriveNumber> (driveNumber);
+ }
+
+/**
+Extracts file name properties, such as secure/non-secure file name, secure UID (SID).
+
+@param aDbFileName Database file name
+@param aServerPrivatePath SQL ser ver private path
+@param aIsSecureFileNameFmt Output. Initialized with non-zero if aDbFileName format is "[drive:]name"
+@param aSecureUid Output. Database secure UID. KNullUid for non-secure databases.
+
+@internalComponent
+*/
+static void GetFileNamePropertiesL(const TDesC& aDbFileName, const TDesC& aServerPrivatePath,
+ TBool& aIsSecureFileNameFmt, TUid& aSecureUid)
+ {
+ //If SQL server private path is in the file name - leave
+ if(::IsPrivatePathInFileName(aDbFileName, aServerPrivatePath))
+ {
+ __SQLLEAVE(KErrArgument);
+ }
+ //Extract database SID from the name
+ aIsSecureFileNameFmt = ::IsSecureFileNameFmt(aDbFileName);
+ aSecureUid = KNullUid;
+ if(aIsSecureFileNameFmt)
+ {
+ aSecureUid = ::ExtractSID(aDbFileName);
+ }
+ }
+
+/**
+Extracts configuration parameters from client's config string.
+For the rules how decision is made which parameter has to be used - from the config file or from the config string,
+please check the TSqlSrvConfig class' comments.
+If the client config string (aConfigStr argument) is NULL, then the config file parameters will be used (if there is a config file)
+or the build-time partameters. Again, check the TSqlSrvConfig class' comments.
+
+@see TSqlSrvConfig
+@see TSqlSrvConfigParams
+
+@param aConfigStr Client configuration string, can be NULL
+@param aConfigParams Output parameter, the place where config parameters will be stored
+@param aConfig TSqlSrvConfig object used for the production of the config parameters
+
+@see TSqlSrvConfig
+
+@internalComponent
+*/
+static void ExtractConfigParamsL(const TDesC8* aConfigStr, TSqlSrvConfigParams& aConfigParams, const TSqlSrvConfig& aConfig)
+ {
+ TPtrC8 ptr(aConfigStr ? *aConfigStr : KNullDesC8());
+ aConfig.GetConfigParamsL(ptr, aConfigParams);
+ }
+
+/**
+1. Reads the database file name which is in "aFileNameArgNum" argument of aMessage and
+ initializes with it iFileName.
+2. Parses the file name and initializes iIsSecureFileNameFmt and iSecureUid.
+3. Creates the full file name in iFileName.
+4. Creates the server private directory on the related drive.
+
+@leave KErrBadName, the database file name length is invalid (not in [1..KMaxFileName] range);
+ KErrArgument, the database file name contains the server private path;
+ KErrArgument, the database file name format is secure but the name does not contain SID.
+
+@panic SqlDb 4 In _DEBUG mode. Invalid aFileNameArgNum value.
+@panic SqlDb 7 In _DEBUG mode. Invalid TSqlSrvFileData object. Not initialized system drive and path.
+*/
+void TSqlSrvFileData::SetL(const RMessage2& aMessage, TInt aFileNameLen, TInt aFileNameArgNum, const TDesC8* aConfigStr)
+ {
+ __SQLASSERT((TUint)aFileNameArgNum < KMaxMessageArguments, ESqlPanicBadArgument);
+ __SQLASSERT(iSysDrivePrivatePath.DriveAndPath().Length() > 0, ESqlPanicInternalError);
+
+ if(aFileNameLen < 1 || aFileNameLen > KMaxFileName)
+ {
+ __SQLLEAVE(KErrBadName);
+ }
+ aMessage.ReadL(aFileNameArgNum, iFileName);
+ SQLPROFILER_REPORT_IPC(ESqlIpcRead, (aFileNameLen * sizeof(TText)));
+ TParse parsedFileName;
+ __SQLLEAVE_IF_ERROR(parsedFileName.Set(iFileName, 0, 0));//prophylactic check, leave if the file name cannot be parsed
+ ::GetFileNamePropertiesL(iFileName, iSysDrivePrivatePath.Path(), iIsSecureFileNameFmt, iSecureUid);
+ ::DoFullFileNameL(iFileName, iSysDrivePrivatePath.DriveAndPath(), iDrive);
+ iFileName.Append(TChar(0));
+ if(iIsSecureFileNameFmt)
+ {
+ if(iSecureUid == KNullUid)
+ {
+ __SQLLEAVE(KErrArgument);
+ }
+ ::CreatePrivateDataPathL(iFs, iDrive);
+ }
+ iReadOnly = ::IsReadOnlyFileL(iFs, FileName());
+ ::ExtractConfigParamsL(aConfigStr, iConfigParams, iConfig);
+ }
+
+/**
+1. Initializes iFileName with the database file name.
+2. Initializes iDrive.
+3. Checks that iFileName really refers to a file belonging to application's private data cage.
+
+Since the file to be created/opened is a file which belongs to the client application's private data cage
+and the file has been created/opened already on the client side, iFileName is formatted to contain useful
+information for the OS layer, such as file handle, file session handle, etc. The information is passed
+to the OS layer in this strange way (formatted string treted as a file name), because the infomation goes
+through the SQLITE library first.
+The format of iFileName is:
+@code
+Bytes:01 2 10 11 20 Last byte (before the terminating 0)
+ |<R/O flag><RMessage2 pointer><drive><app SID><file_name><file_ext>|
+@endcode
+
+'|' is a symbol which cannot be placed in normal file names, so here it is used as an indication that the
+string is not a file name (the string contains other information - handles message pointers, etc).
+
+@leave KErrBadName, the database file name length is invalid (not in [1..KMaxFileName] range);
+ KErrPermissionDenied, the database file name is not in the application's private data cage.
+*/
+void TSqlSrvFileData::SetFromHandleL(const RMessage2& aMessage, const TDesC& aDbFileName, TBool aCreated, TBool aReadOnly,
+ const TDesC8* aConfigStr)
+ {
+ TParse parsedFileName;
+ __SQLLEAVE_IF_ERROR(parsedFileName.Set(aDbFileName, 0, 0));//prophylactic check, leave if the file name cannot be parsed
+ iCreated = aCreated;
+ iReadOnly = aReadOnly;
+ iIsSecureFileNameFmt = EFalse;
+ iSecureUid = KNullUid;
+ iFileName.Copy(aDbFileName);
+ TParsePtrC parse(iFileName);
+ if(!parse.DrivePresent() || !parse.PathPresent())
+ {
+ __SQLLEAVE(KErrBadName);
+ }
+ //Get the drive number
+ TPtrC driveName = parse.Drive();
+ TInt driveNumber = -1;
+ __SQLLEAVE_IF_ERROR(RFs::CharToDrive(driveName[0], driveNumber));
+ iDrive = static_cast <TDriveNumber> (driveNumber);
+ ::CreatePrivateDataPathL(iFs, iDrive);
+ //Create in "buf" variable calling application's private data path
+ TBuf<KMaxFileName + 1> buf;
+ buf.Format(KPrivateFmtStr(), aMessage.SecureId().iId);
+ //Check that the file name refers to a file which is in the application's private data cage
+ TInt pos = iFileName.FindF(buf);
+ if((TUint)pos > (TUint)KMaxDriveName)
+ {
+ __SQLLEAVE(KErrPermissionDenied);
+ }
+ //Form a new unique name for the database. It will be used when creating transaction rollback files, etc.
+ TPtrC nameAndExt = parse.NameAndExt();
+ buf.Format(KFileHandleFmt(), iReadOnly ? 1 : 0, &aMessage, &driveName, aMessage.SecureId().iId, &nameAndExt);
+ iFileName.Copy(buf);
+ ::ExtractConfigParamsL(aConfigStr, iConfigParams, iConfig);
+ }
+