1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/persistentdata/persistentstorage/sql/SRC/Server/SqlSrvFileData.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,293 @@
1.4 +// Copyright (c) 2006-2010 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +#include "SqlSrvFileData.h"
1.20 +#include "SqlSrvUtil.h"
1.21 +#include "SqlAssert.h"
1.22 +#include "SqlSrvStrings.h"
1.23 +#include "SqlSrvResourceProfiler.h"
1.24 +
1.25 +_LIT(KPrivateFmtStr, "\\private\\%08X\\");
1.26 +
1.27 +/**
1.28 +Creates SQL server private data path on the specified drive.
1.29 +
1.30 +The idea for calling it is to make sure that the server's private data path exists before making any other
1.31 +operation - attempting to create a database file there for example.
1.32 +
1.33 +@param aFs File session instance
1.34 +@param aDriveNumber Drive number on which the private path has to be created
1.35 +
1.36 +@internalComponent
1.37 +*/
1.38 +static void CreatePrivateDataPathL(RFs& aFs, TDriveNumber aDriveNumber)
1.39 + {
1.40 + TDriveInfo driveInfo;
1.41 + __SQLLEAVE_IF_ERROR2(aFs.Drive(driveInfo, aDriveNumber));
1.42 + if(!(driveInfo.iDriveAtt & KDriveAttRom))
1.43 + {
1.44 + TInt err = aFs.CreatePrivatePath(aDriveNumber);
1.45 + if(err != KErrNone && err != KErrAlreadyExists)
1.46 + {
1.47 + __SQLLEAVE2(err);
1.48 + }
1.49 + }
1.50 + }
1.51 +
1.52 +/**
1.53 +@return Zero if aDbFileName is a non-secure file name (contains the path), non-zero otherwise.
1.54 +
1.55 +@internalComponent
1.56 +*/
1.57 +static TBool IsSecureFileNameFmt(const TDesC& aDbFileName)
1.58 + {
1.59 + TParsePtrC parse(aDbFileName);//this call may panic if aDbFileName cannot be parsed, but SetL() already parsed it
1.60 + return !parse.PathPresent();
1.61 + }
1.62 +
1.63 +/**
1.64 +The function parses thr database file name argument and extracts the SID from it (if the name contains SID).
1.65 +The SID is expected to be found at position 0 of the file name and must have 8 hex digits.
1.66 +
1.67 +@param aDbFileName Database file name
1.68 +
1.69 +@return Database security UID or KNullUid if the database name does not contain SID.
1.70 +
1.71 +@internalComponent
1.72 +*/
1.73 +static TUid ExtractSID(const TDesC& aDbFileName)
1.74 + {
1.75 + TParsePtrC parse(aDbFileName);//this call may panic if aDbFileName cannot be parsed, but SetL() already parsed it
1.76 + TPtrC dbName = parse.Name();
1.77 + TInt pos1 = dbName.Locate(TChar('['));
1.78 + TInt pos2 = dbName.Locate(TChar(']'));
1.79 + if(pos1 == 0 && pos2 == 9) //position 0 for '[', 8 digits SID, position 9 for ']'
1.80 + {
1.81 + TLex lex(dbName.Mid(pos1 + 1, pos2 - pos1 - 1));
1.82 + TUid securityUid;
1.83 + TInt err = lex.Val(*(TUint32*)&securityUid, EHex);
1.84 + if(err == KErrNone)
1.85 + {
1.86 + return securityUid;
1.87 + }
1.88 + }
1.89 + return KNullUid;
1.90 + }
1.91 +
1.92 +/**
1.93 +@return ETrue if the aDbFileName argument contains aPrivatePath as a first directory in the file path, EFalse otherwise.
1.94 +
1.95 +@internalComponent
1.96 +*/
1.97 +static TBool IsPrivatePathInFileName(const TDesC& aDbFileName, const TDesC& aPrivatePath)
1.98 + {
1.99 + TInt pos = aDbFileName.FindF(aPrivatePath);
1.100 + return (TUint)pos <= (TUint)KMaxDriveName;
1.101 + }
1.102 +
1.103 +/**
1.104 +The method parses aFileName argument and constructs the full database file name (including the path) there.
1.105 +The full file name will be constructed in aFileName input/output argument.
1.106 +
1.107 +@param aDbFileName Input/Output. Database file name will be constructed there.
1.108 +@param aSysDrivePrivatePath SQL server private path on the system drive.
1.109 +@param aDrive Output parameter. The drive number.
1.110 +
1.111 +@leave KErrBadName Missing file name.
1.112 +
1.113 +@panic SqlDb 7 In _DEBUG mode - no drive in the final file path.
1.114 +
1.115 +@internalComponent
1.116 +*/
1.117 +static void DoFullFileNameL(TDes& aDbFileName, const TDesC& aSysDrivePrivatePath, TDriveNumber& aDrive)
1.118 + {
1.119 + TParse parse;
1.120 + __SQLLEAVE_IF_ERROR2(parse.Set(aDbFileName, &aSysDrivePrivatePath, NULL));
1.121 + if(!parse.NamePresent())
1.122 + {
1.123 + __SQLLEAVE2(KErrBadName);
1.124 + }
1.125 + aDbFileName.Copy(parse.FullName());
1.126 + TPtrC driveName = parse.Drive();
1.127 + __ASSERT_DEBUG(driveName.Length() > 0, __SQLPANIC2(ESqlPanicInternalError));
1.128 + TInt driveNumber = -1;
1.129 + __SQLLEAVE_IF_ERROR2(RFs::CharToDrive(driveName[0], driveNumber));
1.130 + aDrive = static_cast <TDriveNumber> (driveNumber);
1.131 + }
1.132 +
1.133 +/**
1.134 +Extracts file name properties, such as secure/non-secure file name, secure UID (SID).
1.135 +
1.136 +@param aDbFileName Database file name
1.137 +@param aServerPrivatePath SQL ser ver private path
1.138 +@param aIsSecureFileNameFmt Output. Initialized with non-zero if aDbFileName format is "[drive:]name"
1.139 +@param aSecureUid Output. Database secure UID. KNullUid for non-secure databases.
1.140 +
1.141 +@internalComponent
1.142 +*/
1.143 +static void GetFileNamePropertiesL(const TDesC& aDbFileName, const TDesC& aServerPrivatePath,
1.144 + TBool& aIsSecureFileNameFmt, TUid& aSecureUid)
1.145 + {
1.146 + //If SQL server private path is in the file name - leave
1.147 + if(::IsPrivatePathInFileName(aDbFileName, aServerPrivatePath))
1.148 + {
1.149 + __SQLLEAVE2(KErrArgument);
1.150 + }
1.151 + //Extract database SID from the name
1.152 + aIsSecureFileNameFmt = ::IsSecureFileNameFmt(aDbFileName);
1.153 + aSecureUid = KNullUid;
1.154 + if(aIsSecureFileNameFmt)
1.155 + {
1.156 + aSecureUid = ::ExtractSID(aDbFileName);
1.157 + }
1.158 + }
1.159 +
1.160 +/**
1.161 +Extracts configuration parameters from client's config string.
1.162 +For the rules how decision is made which parameter has to be used - from the config file or from the config string,
1.163 +please check the TSqlSrvConfig class' comments.
1.164 +If the client config string (aConfigStr argument) is NULL, then the config file parameters will be used (if there is a config file)
1.165 +or the build-time partameters. Again, check the TSqlSrvConfig class' comments.
1.166 +
1.167 +@see TSqlSrvConfig
1.168 +@see TSqlSrvConfigParams
1.169 +
1.170 +@param aConfigStr Client configuration string, can be NULL
1.171 +@param aConfigParams Output parameter, the place where config parameters will be stored
1.172 +@param aConfig TSqlSrvConfig object used for the production of the config parameters
1.173 +
1.174 +@see TSqlSrvConfig
1.175 +
1.176 +@internalComponent
1.177 +*/
1.178 +static void ExtractConfigParamsL(const TDesC8* aConfigStr, TSqlSrvConfigParams& aConfigParams, const TSqlSrvConfig& aConfig)
1.179 + {
1.180 + TPtrC8 ptr(aConfigStr ? *aConfigStr : KNullDesC8());
1.181 + aConfig.GetConfigParamsL(ptr, aConfigParams);
1.182 + }
1.183 +
1.184 +/**
1.185 +1. Reads the database file name which is in "aFileNameArgNum" argument of aMessage and
1.186 + initializes with it iFileName.
1.187 +2. Parses the file name and initializes iIsSecureFileNameFmt and iSecureUid.
1.188 +3. Creates the full file name in iFileName.
1.189 +4. Creates the server private directory on the related drive.
1.190 +
1.191 +@leave KErrBadName, the database file name length is invalid (not in [1..KMaxFileName] range);
1.192 + KErrArgument, the database file name contains the server private path;
1.193 + KErrArgument, the database file name format is secure but the name does not contain SID.
1.194 +
1.195 +@panic SqlDb 4 In _DEBUG mode. Invalid aFileNameArgNum value.
1.196 +@panic SqlDb 7 In _DEBUG mode. Invalid TSqlSrvFileData object. Not initialized system drive and path.
1.197 +*/
1.198 +void TSqlSrvFileData::SetL(const RMessage2& aMessage, TInt aFileNameLen, TInt aFileNameArgNum,
1.199 +#ifdef SQLSRV_STARTUP_TEST
1.200 + const TDesC& aDbFileName,
1.201 +#endif
1.202 + const TDesC8* aConfigStr)
1.203 + {
1.204 + __ASSERT_DEBUG((TUint)aFileNameArgNum < KMaxMessageArguments, __SQLPANIC(ESqlPanicBadArgument));
1.205 + __ASSERT_DEBUG(iSysDrivePrivatePath.DriveAndPath().Length() > 0, __SQLPANIC(ESqlPanicInternalError));
1.206 +
1.207 + if(aFileNameLen < 1 || aFileNameLen > KMaxFileName)
1.208 + {
1.209 + __SQLLEAVE(KErrBadName);
1.210 + }
1.211 +#ifdef SQLSRV_STARTUP_TEST
1.212 + //To prevent compiler warning
1.213 + aMessage.Int0();
1.214 + aFileNameArgNum = aFileNameArgNum;
1.215 + //
1.216 + iFileName.Copy(aDbFileName);
1.217 +#else
1.218 + aMessage.ReadL(aFileNameArgNum, iFileName);
1.219 +#endif
1.220 + SQLPROFILER_REPORT_IPC(ESqlIpcRead, (aFileNameLen * sizeof(TText)));
1.221 + TParse parsedFileName;
1.222 + __SQLLEAVE_IF_ERROR(parsedFileName.Set(iFileName, 0, 0));//prophylactic check, leave if the file name cannot be parsed
1.223 + ::GetFileNamePropertiesL(iFileName, iSysDrivePrivatePath.Path(), iIsSecureFileNameFmt, iSecureUid);
1.224 + ::DoFullFileNameL(iFileName, iSysDrivePrivatePath.DriveAndPath(), iDrive);
1.225 + iFileName.Append(TChar(0));
1.226 + if(iIsSecureFileNameFmt)
1.227 + {
1.228 + if(iSecureUid == KNullUid)
1.229 + {
1.230 + __SQLLEAVE(KErrArgument);
1.231 + }
1.232 + ::CreatePrivateDataPathL(iFs, iDrive);
1.233 + }
1.234 + iReadOnly = ::IsReadOnlyFileL(iFs, FileName());
1.235 + ::ExtractConfigParamsL(aConfigStr, iConfigParams, iConfig);
1.236 + }
1.237 +
1.238 +/**
1.239 +1. Initializes iFileName with the database file name.
1.240 +2. Initializes iDrive.
1.241 +3. Checks that iFileName really refers to a file belonging to application's private data cage.
1.242 +
1.243 +Since the file to be created/opened is a file which belongs to the client application's private data cage
1.244 +and the file has been created/opened already on the client side, iFileName is formatted to contain useful
1.245 +information for the OS layer, such as file handle, file session handle, etc. The information is passed
1.246 +to the OS layer in this strange way (formatted string treted as a file name), because the infomation goes
1.247 +through the SQLITE library first.
1.248 +The format of iFileName is:
1.249 +@code
1.250 +Bytes:01 2 10 11 20 Last byte (before the terminating 0)
1.251 + |<R/O flag><RMessage2 pointer><drive><app SID><file_name><file_ext>|
1.252 +@endcode
1.253 +
1.254 +'|' is a symbol which cannot be placed in normal file names, so here it is used as an indication that the
1.255 +string is not a file name (the string contains other information - handles message pointers, etc).
1.256 +
1.257 +@leave KErrBadName, the database file name length is invalid (not in [1..KMaxFileName] range);
1.258 + KErrPermissionDenied, the database file name is not in the application's private data cage.
1.259 +*/
1.260 +void TSqlSrvFileData::SetFromHandleL(const RMessage2& aMessage, const TDesC& aDbFileName, TBool aCreated, TBool aReadOnly,
1.261 + const TDesC8* aConfigStr)
1.262 + {
1.263 + TParse parsedFileName;
1.264 + __SQLLEAVE_IF_ERROR(parsedFileName.Set(aDbFileName, 0, 0));//prophylactic check, leave if the file name cannot be parsed
1.265 + iCreated = aCreated;
1.266 + iReadOnly = aReadOnly;
1.267 + iIsSecureFileNameFmt = EFalse;
1.268 + iSecureUid = KNullUid;
1.269 + iFileName.Copy(aDbFileName);
1.270 + TParsePtrC parse(iFileName);
1.271 + if(!parse.DrivePresent() || !parse.PathPresent())
1.272 + {
1.273 + __SQLLEAVE(KErrBadName);
1.274 + }
1.275 + //Get the drive number
1.276 + TPtrC driveName = parse.Drive();
1.277 + TInt driveNumber = -1;
1.278 + __SQLLEAVE_IF_ERROR(RFs::CharToDrive(driveName[0], driveNumber));
1.279 + iDrive = static_cast <TDriveNumber> (driveNumber);
1.280 + ::CreatePrivateDataPathL(iFs, iDrive);
1.281 + //Create in "buf" variable calling application's private data path
1.282 + TBuf<KMaxFileName + 1> buf;
1.283 + buf.Format(KPrivateFmtStr(), aMessage.SecureId().iId);
1.284 + //Check that the file name refers to a file which is in the application's private data cage
1.285 + TInt pos = iFileName.FindF(buf);
1.286 + if((TUint)pos > (TUint)KMaxDriveName)
1.287 + {
1.288 + __SQLLEAVE(KErrPermissionDenied);
1.289 + }
1.290 + //Form a new unique name for the database. It will be used when creating transaction rollback files, etc.
1.291 + TPtrC nameAndExt = parse.NameAndExt();
1.292 + buf.Format(KFileHandleFmt(), iReadOnly ? 1 : 0, &aMessage, &driveName, aMessage.SecureId().iId, &nameAndExt);
1.293 + iFileName.Copy(buf);
1.294 + ::ExtractConfigParamsL(aConfigStr, iConfigParams, iConfig);
1.295 + }
1.296 +