persistentstorage/sql/SRC/Server/SqlSrvFileData.cpp
changeset 0 08ec8eefde2f
child 9 667e88a979d7
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include "SqlSrvFileData.h"
       
    17 #include "SqlSrvUtil.h"
       
    18 #include "SqlPanic.h"
       
    19 #include "SqlSrvStrings.h"
       
    20 #include "SqlSrvResourceProfiler.h"
       
    21 
       
    22 _LIT(KPrivateFmtStr, "\\private\\%08X\\");
       
    23 
       
    24 /**
       
    25 Creates SQL server private data path on the specified drive.
       
    26 
       
    27 The idea for calling it is to make sure that the server's private data path exists before making any other 
       
    28 operation - attempting to create a database file there for example. 
       
    29 
       
    30 @param aFs File session instance
       
    31 @param aDriveNumber Drive number on which the private path has to be created
       
    32 
       
    33 @internalComponent
       
    34 */
       
    35 static void CreatePrivateDataPathL(RFs& aFs, TDriveNumber aDriveNumber)
       
    36 	{
       
    37 	TDriveInfo driveInfo;
       
    38 	__SQLLEAVE_IF_ERROR(aFs.Drive(driveInfo, aDriveNumber));
       
    39 	if(!(driveInfo.iDriveAtt & KDriveAttRom))
       
    40 		{
       
    41 		TInt err = aFs.CreatePrivatePath(aDriveNumber);
       
    42 		if(err != KErrNone && err != KErrAlreadyExists)
       
    43 			{
       
    44 			__SQLLEAVE(err);
       
    45 			}
       
    46 		}
       
    47 	}
       
    48 
       
    49 /**
       
    50 @return Zero if aDbFileName is a non-secure file name (contains the path), non-zero otherwise.
       
    51 
       
    52 @internalComponent
       
    53 */
       
    54 static TBool IsSecureFileNameFmt(const TDesC& aDbFileName)
       
    55 	{
       
    56 	TParsePtrC parse(aDbFileName);//this call may panic if aDbFileName cannot be parsed, but SetL() already parsed it
       
    57 	return !parse.PathPresent();
       
    58 	}
       
    59 
       
    60 /**
       
    61 The function parses thr database file name argument and extracts the SID from it (if the name contains SID).
       
    62 The SID is expected to be found at position 0 of the file name and must have 8 hex digits.
       
    63 
       
    64 @param aDbFileName Database file name
       
    65 
       
    66 @return Database security UID or KNullUid if the database name does not contain SID.
       
    67 
       
    68 @internalComponent
       
    69 */
       
    70 static TUid ExtractSID(const TDesC& aDbFileName)
       
    71 	{
       
    72 	TParsePtrC parse(aDbFileName);//this call may panic if aDbFileName cannot be parsed, but SetL() already parsed it
       
    73 	TPtrC dbName = parse.Name();
       
    74 	TInt pos1 = dbName.Locate(TChar('['));
       
    75 	TInt pos2 = dbName.Locate(TChar(']'));
       
    76 	if(pos1 == 0 && pos2 == 9)	//position 0 for '[', 8 digits SID, position 9 for ']'
       
    77 		{
       
    78 		TLex lex(dbName.Mid(pos1 + 1, pos2 - pos1 - 1));
       
    79 		TUid securityUid;
       
    80 		TInt err = lex.Val(*(TUint32*)&securityUid, EHex);
       
    81 		if(err == KErrNone)
       
    82 			{
       
    83 			return securityUid;	
       
    84 			}
       
    85 		}
       
    86 	return KNullUid;
       
    87 	}
       
    88 
       
    89 /**
       
    90 @return ETrue if the aDbFileName argument contains aPrivatePath as a first directory in the file path, EFalse otherwise.
       
    91 
       
    92 @internalComponent
       
    93 */
       
    94 static TBool IsPrivatePathInFileName(const TDesC& aDbFileName, const TDesC& aPrivatePath)
       
    95 	{
       
    96 	TInt pos = aDbFileName.FindF(aPrivatePath);
       
    97 	return (TUint)pos <= (TUint)KMaxDriveName;
       
    98 	}
       
    99 
       
   100 /**
       
   101 The method parses aFileName argument and constructs the full database file name (including the path) there.
       
   102 The full file name will be constructed in aFileName input/output argument.
       
   103 
       
   104 @param aDbFileName Input/Output. Database file name will be constructed there.
       
   105 @param aSysDrivePrivatePath SQL server private path on the system drive.   
       
   106 @param aDrive Output parameter. The drive number.
       
   107 				
       
   108 @leave KErrBadName Missing file name.
       
   109 
       
   110 @panic SqlDb 7 In _DEBUG mode - no drive in the final file path.
       
   111 
       
   112 @internalComponent
       
   113 */
       
   114 static void DoFullFileNameL(TDes& aDbFileName, const TDesC& aSysDrivePrivatePath, TDriveNumber& aDrive)
       
   115 	{
       
   116 	TParse parse;
       
   117 	__SQLLEAVE_IF_ERROR(parse.Set(aDbFileName, &aSysDrivePrivatePath, NULL));
       
   118 	if(!parse.NamePresent())
       
   119 		{
       
   120 		__SQLLEAVE(KErrBadName);	
       
   121 		}
       
   122 	aDbFileName.Copy(parse.FullName());
       
   123 	TPtrC driveName = parse.Drive();
       
   124 	__SQLASSERT(driveName.Length() > 0, ESqlPanicInternalError);
       
   125 	TInt driveNumber = -1;
       
   126 	__SQLLEAVE_IF_ERROR(RFs::CharToDrive(driveName[0], driveNumber));
       
   127 	aDrive = static_cast <TDriveNumber> (driveNumber);
       
   128 	}
       
   129 
       
   130 /**
       
   131 Extracts file name properties, such as secure/non-secure file name, secure UID (SID).
       
   132 
       
   133 @param aDbFileName Database file name
       
   134 @param aServerPrivatePath SQL ser ver private path
       
   135 @param aIsSecureFileNameFmt Output. Initialized with non-zero if aDbFileName format is "[drive:]name"
       
   136 @param aSecureUid Output. Database secure UID. KNullUid for non-secure databases.
       
   137 
       
   138 @internalComponent
       
   139 */
       
   140 static void GetFileNamePropertiesL(const TDesC& aDbFileName, const TDesC& aServerPrivatePath, 
       
   141 								   TBool& aIsSecureFileNameFmt, TUid& aSecureUid)
       
   142 	{
       
   143 	//If SQL server private path is in the file name - leave
       
   144 	if(::IsPrivatePathInFileName(aDbFileName, aServerPrivatePath))
       
   145 		{
       
   146 		__SQLLEAVE(KErrArgument);
       
   147 		}
       
   148 	//Extract database SID from the name
       
   149 	aIsSecureFileNameFmt = ::IsSecureFileNameFmt(aDbFileName);
       
   150 	aSecureUid = KNullUid;
       
   151 	if(aIsSecureFileNameFmt)
       
   152 		{
       
   153 		aSecureUid = ::ExtractSID(aDbFileName);
       
   154 		}
       
   155 	}
       
   156 
       
   157 /**
       
   158 Extracts configuration parameters from client's config string.
       
   159 For the rules how decision is made which parameter has to be used - from the config file or from the config string,
       
   160 please check the TSqlSrvConfig class' comments.
       
   161 If the client config string (aConfigStr argument) is NULL, then the config file parameters will be used (if there is a config file)
       
   162 or the build-time partameters. Again, check the TSqlSrvConfig class' comments. 
       
   163 
       
   164 @see TSqlSrvConfig
       
   165 @see TSqlSrvConfigParams
       
   166 
       
   167 @param aConfigStr Client configuration string, can be NULL
       
   168 @param aConfigParams Output parameter, the place where config parameters will be stored
       
   169 @param aConfig TSqlSrvConfig object used for the production of the config parameters
       
   170 
       
   171 @see TSqlSrvConfig
       
   172 
       
   173 @internalComponent
       
   174 */
       
   175 static void ExtractConfigParamsL(const TDesC8* aConfigStr, TSqlSrvConfigParams& aConfigParams, const TSqlSrvConfig& aConfig)
       
   176 	{
       
   177 	TPtrC8 ptr(aConfigStr ? *aConfigStr : KNullDesC8());
       
   178 	aConfig.GetConfigParamsL(ptr, aConfigParams);
       
   179 	}
       
   180 
       
   181 /**
       
   182 1. Reads the database file name which is in "aFileNameArgNum" argument of aMessage and
       
   183 	initializes with it iFileName.
       
   184 2. Parses the file name and initializes iIsSecureFileNameFmt and iSecureUid.
       
   185 3. Creates the full file name in iFileName.
       
   186 4. Creates the server private directory on the related drive.
       
   187 
       
   188 @leave KErrBadName, the database file name length is invalid (not in [1..KMaxFileName] range);
       
   189 	   KErrArgument, the database file name contains the server private path;
       
   190        KErrArgument, the database file name format is secure but the name does not contain SID.
       
   191 
       
   192 @panic SqlDb 4 In _DEBUG mode. Invalid aFileNameArgNum value.
       
   193 @panic SqlDb 7 In _DEBUG mode. Invalid TSqlSrvFileData object. Not initialized system drive and path.
       
   194 */
       
   195 void TSqlSrvFileData::SetL(const RMessage2& aMessage, TInt aFileNameLen, TInt aFileNameArgNum, const TDesC8* aConfigStr)
       
   196 	{
       
   197 	__SQLASSERT((TUint)aFileNameArgNum < KMaxMessageArguments, ESqlPanicBadArgument);
       
   198 	__SQLASSERT(iSysDrivePrivatePath.DriveAndPath().Length() > 0, ESqlPanicInternalError);
       
   199 	
       
   200 	if(aFileNameLen < 1 || aFileNameLen > KMaxFileName)
       
   201 		{
       
   202 		__SQLLEAVE(KErrBadName);
       
   203 		}
       
   204 	aMessage.ReadL(aFileNameArgNum, iFileName);
       
   205 	SQLPROFILER_REPORT_IPC(ESqlIpcRead, (aFileNameLen * sizeof(TText)));
       
   206 	TParse parsedFileName;
       
   207 	__SQLLEAVE_IF_ERROR(parsedFileName.Set(iFileName, 0, 0));//prophylactic check, leave if the file name cannot be parsed
       
   208 	::GetFileNamePropertiesL(iFileName, iSysDrivePrivatePath.Path(), iIsSecureFileNameFmt, iSecureUid);
       
   209 	::DoFullFileNameL(iFileName, iSysDrivePrivatePath.DriveAndPath(), iDrive);
       
   210 	iFileName.Append(TChar(0));
       
   211 	if(iIsSecureFileNameFmt)
       
   212 		{
       
   213 		if(iSecureUid == KNullUid)		
       
   214 			{
       
   215 			__SQLLEAVE(KErrArgument);	
       
   216 			}
       
   217 		::CreatePrivateDataPathL(iFs, iDrive);
       
   218 		}
       
   219 	iReadOnly = ::IsReadOnlyFileL(iFs, FileName());
       
   220 	::ExtractConfigParamsL(aConfigStr, iConfigParams, iConfig);
       
   221 	}
       
   222 
       
   223 /**
       
   224 1. Initializes iFileName with the database file name.
       
   225 2. Initializes iDrive.
       
   226 3. Checks that iFileName really refers to a file belonging to application's private data cage.
       
   227 
       
   228 Since the file to be created/opened is a file which belongs to the client application's private data cage
       
   229 and the file has been created/opened already on the client side, iFileName is formatted to contain useful
       
   230 information for the OS layer, such as file handle, file session handle, etc. The information is passed
       
   231 to the OS layer in this strange way (formatted string treted as a file name), because the infomation goes
       
   232 through the SQLITE library first.
       
   233 The format of iFileName is:
       
   234 @code
       
   235 Bytes:01         2                  10     11       20                   Last byte (before the terminating 0)
       
   236       |<R/O flag><RMessage2 pointer><drive><app SID><file_name><file_ext>|
       
   237 @endcode
       
   238 
       
   239 '|' is a symbol which cannot be placed in normal file names, so here it is used as an indication that the
       
   240 string is not a file name (the string contains other information - handles message pointers, etc).
       
   241 
       
   242 @leave KErrBadName, the database file name length is invalid (not in [1..KMaxFileName] range);
       
   243        KErrPermissionDenied, the database file name is not in the application's private data cage.
       
   244 */
       
   245 void TSqlSrvFileData::SetFromHandleL(const RMessage2& aMessage, const TDesC& aDbFileName, TBool aCreated, TBool aReadOnly,
       
   246 									 const TDesC8* aConfigStr)
       
   247 	{
       
   248 	TParse parsedFileName;
       
   249 	__SQLLEAVE_IF_ERROR(parsedFileName.Set(aDbFileName, 0, 0));//prophylactic check, leave if the file name cannot be parsed
       
   250 	iCreated = aCreated;
       
   251 	iReadOnly = aReadOnly;
       
   252 	iIsSecureFileNameFmt = EFalse;
       
   253 	iSecureUid = KNullUid;
       
   254 	iFileName.Copy(aDbFileName);
       
   255 	TParsePtrC parse(iFileName);
       
   256 	if(!parse.DrivePresent() || !parse.PathPresent())
       
   257 		{
       
   258 		__SQLLEAVE(KErrBadName);
       
   259 		}
       
   260 	//Get the drive number
       
   261 	TPtrC driveName = parse.Drive();
       
   262 	TInt driveNumber = -1;
       
   263 	__SQLLEAVE_IF_ERROR(RFs::CharToDrive(driveName[0], driveNumber));
       
   264 	iDrive = static_cast <TDriveNumber> (driveNumber);
       
   265 	::CreatePrivateDataPathL(iFs, iDrive);
       
   266 	//Create in "buf" variable calling application's private data path
       
   267 	TBuf<KMaxFileName + 1> buf;
       
   268 	buf.Format(KPrivateFmtStr(), aMessage.SecureId().iId);
       
   269 	//Check that the file name refers to a file which is in the application's private data cage
       
   270 	TInt pos = iFileName.FindF(buf);
       
   271 	if((TUint)pos > (TUint)KMaxDriveName)
       
   272 		{
       
   273 		__SQLLEAVE(KErrPermissionDenied);
       
   274 		}
       
   275 	//Form a new unique name for the database. It will be used when creating transaction rollback files, etc.
       
   276 	TPtrC nameAndExt = parse.NameAndExt();
       
   277 	buf.Format(KFileHandleFmt(), iReadOnly ? 1 : 0, &aMessage, &driveName, aMessage.SecureId().iId, &nameAndExt);
       
   278 	iFileName.Copy(buf);
       
   279 	::ExtractConfigParamsL(aConfigStr, iConfigParams, iConfig);
       
   280 	}
       
   281