|
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 |