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