|
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 #include <bautils.h> |
|
16 #include <f32file.h> |
|
17 #include <s32file.h> |
|
18 #include "tmtptypeobjecthandle.h" |
|
19 #include <mtp/cmtpobjectmetadata.h> |
|
20 #include <mtp/cmtptypearray.h> |
|
21 #include <mtp/mmtpobjectmgr.h> |
|
22 #include <mtp/mtpdatatypeconstants.h> |
|
23 #include <mtp/mtpobjectmgrquerytypes.h> |
|
24 #include <mtp/mtpprotocolconstants.h> |
|
25 #include <mtp/tmtptypeuint32.h> |
|
26 #include "cmtphandleallocator.h" |
|
27 #include "cmtpobjectstore.h" |
|
28 #include "cmtpreferencemgr.h" |
|
29 #include "dbutility.h" |
|
30 #include "cmtpdataprovidercontroller.h" |
|
31 #include "cmtpdataprovider.h" |
|
32 #include "cmtpdpidstore.h" |
|
33 #include "cmtppkgidstore.h" |
|
34 #include "cmtpdeltadatamgr.h" |
|
35 #include <e32hashtab.h> |
|
36 #include "cmtpstoragemgr.h" |
|
37 |
|
38 _LIT(KMTPDbDriveLocation, "c:"); |
|
39 _LIT(KMTPBackSlash, "\\"); |
|
40 _LIT(KMTPHandleObjectDbName, "MTPObjectStore.db"); |
|
41 _LIT(KMTPNoBackupFolderName, "nobackup"); |
|
42 _LIT(KSQLHandleTableName, "HandleStore"); |
|
43 _LIT(KSQLCreateHandleTableText, "CREATE TABLE HandleStore (HandleId UNSIGNED INTEGER, SuidHash UNSIGNED INTEGER, Suid LONG VARCHAR, DataProviderId UNSIGNED TINYINT, FormatCode UNSIGNED SMALLINT, FormatSubCode UNSIGNED SMALLINT, StorageId UNSIGNED INTEGER, Modes UNSIGNED TINYINT, POUID BIGINT, ParentHandle UNSIGNED INTEGER, DPFlag UNSIGNED TINYINT, NonConsumable UNSIGNED TINYINT, Name VARCHAR(255))"); |
|
44 _LIT(KSQLHandleId, "HandleIndex"); |
|
45 _LIT(KSQLCreateHandleIndexText,"CREATE UNIQUE INDEX HandleIndex on HandleStore (HandleId)"); |
|
46 _LIT(KSQLSuidHash, "SuidIndex"); |
|
47 _LIT(KSQLCreateSuidIndexText,"CREATE INDEX SuidIndex on HandleStore (SuidHash)"); |
|
48 _LIT(KSQLParentHandle, "ParentHandleIndex"); |
|
49 _LIT(KSQLCreateParentHandleText,"CREATE INDEX ParentHandleIndex on HandleStore (ParentHandle)"); |
|
50 _LIT(KMTPFormat, "MTP"); |
|
51 __FLOG_STMT(_LIT8(KComponent,"MTPObjectStore");) |
|
52 const TInt KMaxLimitCommitInEnumeration = 1024; |
|
53 const TInt KMaxLimitCommitAfterEnumeration = 256; |
|
54 const TInt KMaxLimitCompactInEnumeration = 2048; |
|
55 const TInt KMaxLimitCompactAfterEnumeration = 1024; |
|
56 /** |
|
57 MTP object meta data store factory method. |
|
58 @return A pointer to a new CMTPObjectStore instance, ownership IS transferred. |
|
59 @leave One of the system wide error codes, if a processing failure occurs. |
|
60 */ |
|
61 CMTPObjectStore* CMTPObjectStore::NewL() |
|
62 { |
|
63 CMTPObjectStore* self = new (ELeave) CMTPObjectStore(); |
|
64 CleanupStack::PushL(self); |
|
65 self->ConstructL(); |
|
66 CleanupStack::Pop(self); |
|
67 return self; |
|
68 } |
|
69 |
|
70 /** |
|
71 Destructor. |
|
72 */ |
|
73 CMTPObjectStore::~CMTPObjectStore() |
|
74 { |
|
75 delete iCompactor; |
|
76 delete iReferenceMgr; |
|
77 delete iHandleAllocator; |
|
78 delete iMtpDeltaDataMgr; |
|
79 delete iDPIDStore; |
|
80 delete iPkgIDStore; |
|
81 delete iSentinal; |
|
82 TRAP_IGNORE(CommitTransactionL()); |
|
83 iDatabase.Compact(); |
|
84 iBatched.Close(); |
|
85 iBatched_SuidHashID.Close(); |
|
86 CloseDb(); |
|
87 iSingletons.Close(); |
|
88 iNonPersistentDPList.Close(); |
|
89 iEnumeratingCacheObjList.ResetAndDestroy(); |
|
90 __FLOG_CLOSE; |
|
91 } |
|
92 |
|
93 /** |
|
94 Provides a reference to the object meta data store database. |
|
95 @return The object information store database. |
|
96 */ |
|
97 RDbDatabase& CMTPObjectStore::Database() |
|
98 { |
|
99 return iDatabase; |
|
100 } |
|
101 |
|
102 /** |
|
103 Provides a reference to the DPID store object. |
|
104 @return The DPID store. |
|
105 */ |
|
106 CMTPDPIDStore& CMTPObjectStore::DPIDStore() const |
|
107 { |
|
108 return *iDPIDStore; |
|
109 } |
|
110 |
|
111 CMTPPkgIDStore& CMTPObjectStore::PkgIDStore() const |
|
112 { |
|
113 return *iPkgIDStore; |
|
114 } |
|
115 |
|
116 /** |
|
117 Provides a reference to the reference manager object. |
|
118 @return The reference manager. |
|
119 */ |
|
120 CMTPReferenceMgr& CMTPObjectStore::ReferenceMgr() const |
|
121 { |
|
122 return *iReferenceMgr; |
|
123 } |
|
124 |
|
125 /** |
|
126 Provides a reference to the MTP delta Data manager object. |
|
127 @return The MTP delta data manager. |
|
128 */ |
|
129 CMtpDeltaDataMgr* CMTPObjectStore:: MtpDeltaDataMgr() const |
|
130 { |
|
131 return iMtpDeltaDataMgr; |
|
132 } |
|
133 |
|
134 void CMTPObjectStore::RemoveNonPersistentObjectsL(TUint /*aDataProviderId*/) |
|
135 { |
|
136 } |
|
137 |
|
138 void CMTPObjectStore::MarkNonPersistentObjectsL(TUint aDataProviderId, TUint32) |
|
139 { |
|
140 TInt result = iNonPersistentDPList.InsertInOrder(aDataProviderId); |
|
141 if(result != KErrAlreadyExists) |
|
142 { |
|
143 User::LeaveIfError(result); |
|
144 } |
|
145 } |
|
146 |
|
147 void CMTPObjectStore::MarkDPLoadedL(TUint aDataProviderId, TBool aFlag) |
|
148 { |
|
149 __FLOG(_L8("MarkDPFlafFalseL - Entry")); |
|
150 if (!aFlag) |
|
151 { |
|
152 _LIT(KSQLMarkfalgDPFalse, "UPDATE HandleStore SET DPFlag = %u WHERE DataProviderId = %u"); |
|
153 iSqlStatement.Format(KSQLMarkfalgDPFalse, aFlag, aDataProviderId); |
|
154 User::LeaveIfError(iDatabase.Execute(iSqlStatement)); |
|
155 } |
|
156 __FLOG(_L8("MarkNonPersistentObjectsL - Exit")); |
|
157 } |
|
158 |
|
159 TBool CMTPObjectStore::FilterObject(const RDbTable& aCurrRow,const TUint32 aStorageID,const TUint32 aFormatCode,const TUint32 aDpID) const |
|
160 { |
|
161 return ( ((KMTPStorageAll==aStorageID) ||(aCurrRow.ColUint32(EObjectStoreStorageId)== aStorageID)) |
|
162 |
|
163 &&((0 == aFormatCode)||(aCurrRow.ColUint16(EObjectStoreFormatCode) == aFormatCode)) |
|
164 |
|
165 &&((aDpID==KMTPDataProviderAll)||(aCurrRow.ColUint8(EObjectStoreDataProviderId) == aDpID )) |
|
166 ); |
|
167 } |
|
168 |
|
169 |
|
170 void CMTPObjectStore::TraverseL(const TMTPObjectMgrQueryParams& aParams, MTraverseAction& action) const |
|
171 { |
|
172 RDbTable temp; |
|
173 CleanupClosePushL(temp); |
|
174 temp.Open(iDatabase, KSQLHandleTableName, RDbRowSet::EUpdatable); |
|
175 |
|
176 TUint32 tmpStorageID = 0; |
|
177 TBool bStorageAvailable = ETrue; |
|
178 |
|
179 if (aParams.iParentHandle == 0) |
|
180 {//ParentHandle is not used to filter the objects. Need to iterate throught all objects in the storage to filter based on format/dpid/storatgeid. |
|
181 //Do not using index to iterate through the whole storage is faster than index iteration. |
|
182 temp.FirstL(); |
|
183 while (!temp.AtEnd()) |
|
184 { |
|
185 temp.GetL(); |
|
186 if ((MTraverseAction::EAllDP == action.Target()) || (temp.ColUint8(EObjectStoreDPFlag) == 1))//If the DP is loaded or ation for all dps. |
|
187 { |
|
188 |
|
189 if((aParams.iStorageId == KMTPStorageAll) &&(aParams.iFormatCode == 0)&&(iSingletons.DpController().DataProviderL(temp.ColUint8(EObjectStoreDataProviderId)).SupportedCodes( EServiceIDs ).Count() != 0)) |
|
190 { |
|
191 temp.NextL(); |
|
192 continue; |
|
193 } |
|
194 |
|
195 //check StorageID ,DPID and Formatcode |
|
196 if ( !FilterObject(temp,aParams.iStorageId,aParams.iFormatCode,aParams.iDpId) ) |
|
197 { |
|
198 temp.NextL(); |
|
199 continue; |
|
200 } |
|
201 |
|
202 //verify the whether the storageID is validated. |
|
203 if(tmpStorageID != temp.ColUint32(EObjectStoreStorageId)) |
|
204 { |
|
205 tmpStorageID = temp.ColUint32(EObjectStoreStorageId); |
|
206 bStorageAvailable = iSingletons.StorageMgr().ValidStorageId( tmpStorageID ); |
|
207 } |
|
208 if(!bStorageAvailable) |
|
209 { |
|
210 temp.NextL(); |
|
211 continue; |
|
212 } |
|
213 |
|
214 action.DoL(temp); |
|
215 } |
|
216 temp.NextL(); |
|
217 } |
|
218 } |
|
219 else |
|
220 {//Fetch the root directory |
|
221 temp.SetIndex(KSQLParentHandle); |
|
222 if (temp.SeekL((TUint) aParams.iParentHandle)) |
|
223 {//every storageID has the same root directory handles.KMTPHandleNoParent, therefore, need to filter the storageID |
|
224 //if it is not KMTPStorageAll |
|
225 while (!temp.AtEnd()) |
|
226 { |
|
227 temp.GetL(); |
|
228 if (temp.ColUint32(EObjectStoreParentHandle) == aParams.iParentHandle) |
|
229 { |
|
230 if ((MTraverseAction::EAllDP == action.Target()) || (temp.ColUint8(EObjectStoreDPFlag) == 1))//If the DP is loaded or ation for all dps. |
|
231 { |
|
232 |
|
233 if((aParams.iStorageId == KMTPStorageAll) &&(aParams.iFormatCode == 0)&&(iSingletons.DpController().DataProviderL(temp.ColUint8(EObjectStoreDataProviderId)).SupportedCodes( EServiceIDs ).Count() != 0)) |
|
234 { |
|
235 temp.NextL(); |
|
236 continue; |
|
237 } |
|
238 |
|
239 //check StorageID ,DPID and Formatcode |
|
240 if ( !FilterObject(temp,aParams.iStorageId,aParams.iFormatCode,aParams.iDpId) ) |
|
241 { |
|
242 temp.NextL(); |
|
243 continue; |
|
244 } |
|
245 |
|
246 //verify the whether the storageID is validated. |
|
247 if(tmpStorageID != temp.ColUint32(EObjectStoreStorageId)) |
|
248 { |
|
249 tmpStorageID = temp.ColUint32(EObjectStoreStorageId); |
|
250 bStorageAvailable = iSingletons.StorageMgr().ValidStorageId( tmpStorageID ); |
|
251 } |
|
252 if(!bStorageAvailable) |
|
253 { |
|
254 temp.NextL(); |
|
255 continue; |
|
256 } |
|
257 |
|
258 action.DoL(temp); |
|
259 } |
|
260 temp.NextL(); |
|
261 } |
|
262 else |
|
263 { |
|
264 break;//has jumped over the range of handles with the same parent handle |
|
265 } |
|
266 } |
|
267 } |
|
268 } |
|
269 CleanupStack::PopAndDestroy(&temp); |
|
270 //Since we fetch all handles as requested, therefore, we do not open aContext to indicate the query is completed. |
|
271 } |
|
272 |
|
273 TUint CMTPObjectStore::CountL(const TMTPObjectMgrQueryParams& aParams) const |
|
274 { |
|
275 TUint i = 0; |
|
276 TCountAction action(i); |
|
277 TraverseL(aParams, action); |
|
278 return i; |
|
279 } |
|
280 |
|
281 void CMTPObjectStore::CommitReservedObjectHandleL(CMTPObjectMetaData& aObject) |
|
282 { |
|
283 //After the PutL called the cursor's position is not well defined. |
|
284 iCachedHandle = 0; |
|
285 iCachedSuidHash = 0; |
|
286 TInt64 id = iHandleAllocator->NextPOUIDL(); |
|
287 aObject.SetUint(CMTPObjectMetaData::EIdentifier, id); |
|
288 |
|
289 TFileName suid; |
|
290 suid.CopyLC(aObject.DesC(CMTPObjectMetaData::ESuid)); |
|
291 TUint32 suidHash = DefaultHash::Des16(suid); |
|
292 |
|
293 TUint32 handle = aObject.Uint(CMTPObjectMetaData::EHandle); |
|
294 CleanupStack::PushL(TCleanupItem(CMTPObjectStore::DBUpdateFailRecover, &iBatched)); |
|
295 iBatched.InsertL(); |
|
296 iBatched.SetColL(EObjectStoreHandleId, handle); |
|
297 iBatched.SetColL(EObjectStoreSUIDHash, suidHash); |
|
298 DbColWriteStreamL(iBatched, EObjectStoreSUID, aObject.DesC(CMTPObjectMetaData::ESuid)); |
|
299 iBatched.SetColL(EObjectStoreDataProviderId, aObject.Uint(CMTPObjectMetaData::EDataProviderId)); |
|
300 iBatched.SetColL(EObjectStoreFormatCode, aObject.Uint(CMTPObjectMetaData::EFormatCode)); |
|
301 iBatched.SetColL(EObjectStoreFormatSubCode, aObject.Uint(CMTPObjectMetaData::EFormatSubCode)); |
|
302 iBatched.SetColL(EObjectStoreStorageId, aObject.Uint(CMTPObjectMetaData::EStorageId)); |
|
303 iBatched.SetColL(EObjectStoreModes,aObject.Uint(CMTPObjectMetaData::EModes)); |
|
304 iBatched.SetColL(EObjectStorePOUID, id); |
|
305 iBatched.SetColL(EObjectStoreParentHandle, aObject.Uint(CMTPObjectMetaData::EParentHandle)); |
|
306 iBatched.SetColL(EObjectStoreDPFlag, 1); |
|
307 iBatched.SetColL(EObjectStoreNonConsumable, aObject.Uint(CMTPObjectMetaData::ENonConsumable)); |
|
308 iBatched.SetColL(EObjectStoreName, aObject.DesC(CMTPObjectMetaData::EName)); |
|
309 |
|
310 iBatched.PutL(); |
|
311 CleanupStack::Pop(&iBatched); |
|
312 IncTranOpsNumL(); |
|
313 |
|
314 } |
|
315 |
|
316 /* |
|
317 This API is designed intended for coping with the MTP operation GetObjectHandles which has 3 parameters. |
|
318 1. StorageID |
|
319 2. FormatCode |
|
320 3. ParentHandle. |
|
321 |
|
322 The first parameter contains the StorageID of the storage for which the list of Object Handles is desired. |
|
323 A value of 0xFFFFFFFF may be used to indicate that a list of Object Handles of all objects on all storages |
|
324 should be returned. If a storage is specified and the storage is unavailable, this operation should return Store_Not_Available. |
|
325 |
|
326 The second parameter is optional, and contains an Object Format datacode. Object Formats are described |
|
327 in section 4, "Object Formats". If the second parameter contains a non-0x00000000 value, it specifies that |
|
328 a list of object handles referencing objects of a certain object format is desired. If the parameter is not used, |
|
329 it should contain a value of 0x00000000 and objects should be included in the response dataset regardless |
|
330 of their object format. If this parameter is not supported, the responder should return a response code of |
|
331 Specification_By_Format_Unsupported. |
|
332 |
|
333 The third parameter may be used to restrict the list of objects that are returned by this operation to objects |
|
334 directly contained in a particular folder (Association). If this parameter contains a non-0x00000000 value, |
|
335 the responder should return a list of objects which have as their ParentObject the folder (Association) |
|
336 that is identified by this parameter. If the number of objects that are contained in the root of a storage is desired, |
|
337 a value of 0xFFFFFFFF may be passed in this operation, which indicates that only those objects with no ParentObject |
|
338 should be returned. If the first parameter indicates that all storages are included in this query, then a value of 0xFFFFFFFF |
|
339 should return a list of all objects at the root level of all storages. If this parameter is unused, it should contain a value of 0x00000000. |
|
340 |
|
341 If the third parameter is unsupported and a non-0x00000000 value is sent in this operation, a response of |
|
342 Parameter_Unsupported should be returned. If the use of the third parameter is supported, but the value |
|
343 contained does not reference an actual object on the device, a response of Invalid_ObjectHandle should be returned. |
|
344 If the use of the third parameter is supported and it contains a valid Object Handle, but the object referenced |
|
345 is not of type Association, then a response of Invalid_ParentObject should be returned. |
|
346 |
|
347 |
|
348 */ |
|
349 void CMTPObjectStore::GetObjectHandlesL(const TMTPObjectMgrQueryParams& aParams, RMTPObjectMgrQueryContext& /*aContext*/, RArray<TUint>& aHandles) const |
|
350 { |
|
351 TGetHandlesAction action(aHandles); |
|
352 TraverseL(aParams, action); |
|
353 } |
|
354 |
|
355 void CMTPObjectStore::GetObjectSuidsL(const TMTPObjectMgrQueryParams& aParams, RMTPObjectMgrQueryContext& /*aContext*/, CDesCArray& aSuids) const |
|
356 { |
|
357 //take the similar approach for GetObjectHandlesL, but need to pay attention for the memory usage, since every SUID might take |
|
358 //maximum 255 bytes, if there are totally 10K objects, the maximum memory usage will be 2.5M, consider to get it in multiple calls instead of one. |
|
359 TGetSuidsAction action(aSuids); |
|
360 TraverseL(aParams, action); |
|
361 } |
|
362 |
|
363 TUint32 CMTPObjectStore::HandleL(const TDesC& aSuid) const |
|
364 { |
|
365 TUint32 handle = KMTPHandleNone; |
|
366 if (LocateBySuidL(aSuid)) |
|
367 { |
|
368 handle = iBatched_SuidHashID.ColUint32(EObjectStoreHandleId); |
|
369 } |
|
370 return handle; |
|
371 } |
|
372 |
|
373 void CMTPObjectStore::DBUpdateFailRecover(TAny* aTable) |
|
374 { |
|
375 reinterpret_cast<RDbTable*> (aTable)->Cancel(); |
|
376 } |
|
377 |
|
378 void CMTPObjectStore::InsertObjectL(CMTPObjectMetaData& aObject) |
|
379 { |
|
380 //_LIT(KInsert, "CMTPObjectStore::InsertObjectL"); |
|
381 //volatile TTimer t(KInsert); |
|
382 __FLOG(_L8("InsertObjectL - Entry")); |
|
383 iCachedHandle = 0; |
|
384 iCachedSuidHash = 0; |
|
385 TBool needToInsert = EFalse; |
|
386 TBool needUpdateOwner = EFalse; |
|
387 TUint dpId(aObject.Uint(CMTPObjectMetaData::EDataProviderId)); |
|
388 TFileName suid; |
|
389 suid.CopyLC(aObject.DesC(CMTPObjectMetaData::ESuid)); |
|
390 TUint32 suidHash = DefaultHash::Des16(suid); |
|
391 TUint32 parentHandle = aObject.Uint(CMTPObjectMetaData::EParentHandle); |
|
392 TUint32 handle = KMTPHandleNone, handleInDB = KMTPHandleAll; |
|
393 TInt64 id = 0; |
|
394 // Check if the dp is enumerating |
|
395 if (iSingletons.DpController().EnumerateState() != CMTPDataProviderController::EEnumerated && iCacheExist) |
|
396 { |
|
397 //it is in the object enumeration phase. |
|
398 // if it's see if we have an object with the same SUID |
|
399 //When the MTP server startup the object enumeration, it will fetch all of the object's (SUIDHash and Handles) into in-memory ordered array. |
|
400 //this function is to try to match the handleID for the incoming suidHash/SUID/DPID, if matched in memory, it will return the handleID |
|
401 //considering the possible conflicting of the SUID for different file name, it need to consult the SUID in the table for eactly match. |
|
402 //Therefore, for each object matching, it need one table lookup and file name cope and match operation. |
|
403 //If it matched, do nothing for the table, but remove it from the in-memory ordered array. |
|
404 //if there is no match, it is a new object, insert it into table. |
|
405 iSentinal->iObjSuiIdHash = suidHash; |
|
406 iSentinal->iSuidPtr.Set(aObject.DesC(CMTPObjectMetaData::ESuid)); |
|
407 TInt found = iEnumeratingCacheObjList.FindInOrder(iSentinal, TLinearOrder<CEnumertingCacheItem>(CEnumertingCacheItem::Compare)); |
|
408 if (KErrNotFound != found) |
|
409 {//There is a match |
|
410 if(NULL == iEnumeratingCacheObjList[found]->iSuid) |
|
411 {//need extra check for hash collision |
|
412 handleInDB = HandleL(aObject.DesC(CMTPObjectMetaData::ESuid)); |
|
413 } |
|
414 handle = iEnumeratingCacheObjList[found]->iObjHandleId; |
|
415 if((handleInDB != KMTPHandleAll) && (handleInDB != handle)) //hash collision |
|
416 { |
|
417 needToInsert = ETrue; |
|
418 } |
|
419 else |
|
420 { |
|
421 aObject.SetUint(CMTPObjectMetaData::EHandle, handle); |
|
422 id = iEnumeratingCacheObjList[found]->iPOUID; |
|
423 aObject.SetUint(CMTPObjectMetaData::EIdentifier, id); |
|
424 if(iEnumeratingCacheObjList[found]->iFormatcode != aObject.Uint(CMTPObjectMetaData::EFormatCode)) |
|
425 {//have different owner |
|
426 needUpdateOwner = ETrue; |
|
427 } |
|
428 delete iEnumeratingCacheObjList[found]; |
|
429 iEnumeratingCacheObjList.Remove(found); |
|
430 } |
|
431 } |
|
432 else |
|
433 {//This is a totally new object. insert it after check the db to prevent user wrong operation |
|
434 handle = HandleL(aObject.DesC(CMTPObjectMetaData::ESuid)); |
|
435 if (handle == KMTPHandleNone) |
|
436 { |
|
437 needToInsert = ETrue; |
|
438 } |
|
439 else |
|
440 { |
|
441 User::Leave(KErrAlreadyExists); |
|
442 } |
|
443 } |
|
444 } |
|
445 else |
|
446 { |
|
447 handle = HandleL(aObject.DesC(CMTPObjectMetaData::ESuid)); |
|
448 if (handle != KMTPHandleNone) |
|
449 { |
|
450 //Leaves if id already exists in suid map table |
|
451 User::Leave(KErrAlreadyExists); |
|
452 } |
|
453 // dp is not enumerating, do a plain insert |
|
454 needToInsert = ETrue; |
|
455 } |
|
456 if (needToInsert)//needToInsert and needUpdateOwner can't be true at same time |
|
457 { |
|
458 TUint32 parentHandle(aObject.Uint(CMTPObjectMetaData::EParentHandle)); |
|
459 handle = iHandleAllocator->NextIdL(dpId); |
|
460 id = iHandleAllocator->NextPOUIDL(); |
|
461 aObject.SetUint(CMTPObjectMetaData::EHandle, handle); |
|
462 aObject.SetUint(CMTPObjectMetaData::EIdentifier, id); |
|
463 CleanupStack::PushL(TCleanupItem(CMTPObjectStore::DBUpdateFailRecover, &iBatched)); |
|
464 iBatched.InsertL(); |
|
465 iBatched.SetColL(EObjectStoreHandleId, handle); |
|
466 iBatched.SetColL(EObjectStoreSUIDHash, suidHash); |
|
467 DbColWriteStreamL(iBatched, EObjectStoreSUID, aObject.DesC(CMTPObjectMetaData::ESuid)); |
|
468 iBatched.SetColL(EObjectStoreDataProviderId, aObject.Uint(CMTPObjectMetaData::EDataProviderId)); |
|
469 iBatched.SetColL(EObjectStoreFormatCode, aObject.Uint(CMTPObjectMetaData::EFormatCode)); |
|
470 iBatched.SetColL(EObjectStoreFormatSubCode, aObject.Uint(CMTPObjectMetaData::EFormatSubCode)); |
|
471 iBatched.SetColL(EObjectStoreStorageId, aObject.Uint(CMTPObjectMetaData::EStorageId)); |
|
472 iBatched.SetColL(EObjectStoreModes, aObject.Uint(CMTPObjectMetaData::EModes)); |
|
473 iBatched.SetColL(EObjectStorePOUID, id); |
|
474 iBatched.SetColL(EObjectStoreParentHandle, parentHandle); |
|
475 iBatched.SetColL(EObjectStoreDPFlag, 1); |
|
476 iBatched.SetColL(EObjectStoreNonConsumable, aObject.Uint(CMTPObjectMetaData::ENonConsumable)); |
|
477 iBatched.SetColL(EObjectStoreName, aObject.DesC(CMTPObjectMetaData::EName)); |
|
478 iBatched.PutL(); |
|
479 CleanupStack::Pop(&iBatched); |
|
480 IncTranOpsNumL(); |
|
481 } |
|
482 else if(needUpdateOwner) |
|
483 { |
|
484 if(iBatched.SeekL(static_cast<TUint>(handle))) |
|
485 { |
|
486 CleanupStack::PushL(TCleanupItem(CMTPObjectStore::DBUpdateFailRecover, &iBatched)); |
|
487 iBatched.UpdateL(); |
|
488 iBatched.SetColL(EObjectStoreDataProviderId, aObject.Uint(CMTPObjectMetaData::EDataProviderId)); |
|
489 iBatched.SetColL(EObjectStoreFormatCode, aObject.Uint(CMTPObjectMetaData::EFormatCode)); |
|
490 iBatched.SetColL(EObjectStoreFormatSubCode, aObject.Uint(CMTPObjectMetaData::EFormatSubCode)); |
|
491 iBatched.SetColL(EObjectStoreStorageId, aObject.Uint(CMTPObjectMetaData::EStorageId)); |
|
492 iBatched.SetColL(EObjectStoreModes, aObject.Uint(CMTPObjectMetaData::EModes)); |
|
493 iBatched.SetColL(EObjectStoreNonConsumable, aObject.Uint(CMTPObjectMetaData::ENonConsumable)); |
|
494 iBatched.SetColL(EObjectStoreName, aObject.DesC(CMTPObjectMetaData::EName)); |
|
495 iBatched.PutL(); |
|
496 CleanupStack::Pop(&iBatched); |
|
497 IncTranOpsNumL(); |
|
498 } |
|
499 } |
|
500 if ((needToInsert || needUpdateOwner) && IsMediaFormat(aObject.Uint(CMTPObjectMetaData::EFormatCode))) |
|
501 { |
|
502 if (iUpdateDeltaDataTable) |
|
503 { |
|
504 iMtpDeltaDataMgr->UpdateDeltaDataTableL(id, CMtpDeltaDataMgr::EAdded); |
|
505 } |
|
506 } |
|
507 |
|
508 __FLOG(_L8("InsertObjectL - Exit")); |
|
509 } |
|
510 |
|
511 void CMTPObjectStore::IncTranOpsNumL() |
|
512 { |
|
513 iTransactionOps++; |
|
514 if (iTransactionOps % iMaxCommitLimit == 0) |
|
515 { |
|
516 CommitTransactionL(); |
|
517 if (iTransactionOps % iMaxCompactLimit == 0) |
|
518 { |
|
519 User::LeaveIfError(iDatabase.Compact()); |
|
520 } |
|
521 BeginTransactionL(); |
|
522 } |
|
523 } |
|
524 |
|
525 void CMTPObjectStore::BeginTransactionL() |
|
526 { |
|
527 if (!iDatabase.InTransaction()) |
|
528 { |
|
529 User::LeaveIfError(iDatabase.Begin()); |
|
530 } |
|
531 } |
|
532 |
|
533 void CMTPObjectStore::CommitTransactionL() |
|
534 { |
|
535 if (iDatabase.InTransaction()) |
|
536 { |
|
537 User::LeaveIfError(iDatabase.Commit()); |
|
538 } |
|
539 } |
|
540 |
|
541 void CMTPObjectStore::InsertObjectsL(RPointerArray<CMTPObjectMetaData>& aObjects) |
|
542 { |
|
543 TInt count = aObjects.Count(); |
|
544 for (TInt i = 0; i < count; i++) |
|
545 { |
|
546 InsertObjectL(*aObjects[i]); |
|
547 } |
|
548 } |
|
549 |
|
550 void CMTPObjectStore::ModifyObjectL(const CMTPObjectMetaData& aObject) |
|
551 { |
|
552 TUint32 handle = aObject.Uint(CMTPObjectMetaData::EHandle); |
|
553 TFileName suid; |
|
554 suid.CopyLC(aObject.DesC(CMTPObjectMetaData::ESuid)); |
|
555 TUint32 suidHash = DefaultHash::Des16(suid); |
|
556 |
|
557 if (LocateByHandleL(handle)) |
|
558 { |
|
559 //After the PutL called the cursor's position is not well defined. |
|
560 iCachedHandle = 0; |
|
561 iCachedSuidHash = 0; |
|
562 TInt64 id = iBatched.ColInt64(EObjectStorePOUID); |
|
563 TUint32 suidHashOld = iBatched.ColUint32(EObjectStoreSUIDHash); |
|
564 TUint32 parentOld = iBatched.ColUint32(EObjectStoreParentHandle); |
|
565 CleanupStack::PushL(TCleanupItem(CMTPObjectStore::DBUpdateFailRecover, &iBatched)); |
|
566 iBatched.UpdateL(); |
|
567 if(suidHashOld != suidHash) |
|
568 {//change on index column will impact the performace |
|
569 iBatched.SetColL(EObjectStoreSUIDHash, suidHash); |
|
570 } |
|
571 if(parentOld != aObject.Uint(CMTPObjectMetaData::EParentHandle)) |
|
572 {//change on index column will impact the performace |
|
573 iBatched.SetColL(EObjectStoreParentHandle, aObject.Uint(CMTPObjectMetaData::EParentHandle)); |
|
574 } |
|
575 |
|
576 DbColWriteStreamL(iBatched, EObjectStoreSUID, aObject.DesC(CMTPObjectMetaData::ESuid)); |
|
577 iBatched.SetColL(EObjectStoreDataProviderId, aObject.Uint(CMTPObjectMetaData::EDataProviderId)); |
|
578 iBatched.SetColL(EObjectStoreFormatCode, aObject.Uint(CMTPObjectMetaData::EFormatCode)); |
|
579 iBatched.SetColL(EObjectStoreFormatSubCode, aObject.Uint(CMTPObjectMetaData::EFormatSubCode)); |
|
580 iBatched.SetColL(EObjectStoreStorageId, aObject.Uint(CMTPObjectMetaData::EStorageId)); |
|
581 iBatched.SetColL(EObjectStoreModes, aObject.Uint(CMTPObjectMetaData::EModes)); |
|
582 iBatched.SetColL(EObjectStoreDPFlag, 1); |
|
583 iBatched.SetColL(EObjectStoreNonConsumable, aObject.Uint(CMTPObjectMetaData::ENonConsumable)); |
|
584 iBatched.SetColL(EObjectStoreName, aObject.DesC(CMTPObjectMetaData::EName)); |
|
585 iBatched.PutL(); |
|
586 CleanupStack::Pop(&iBatched); |
|
587 IncTranOpsNumL(); |
|
588 if (aObject.Uint(CMTPObjectMetaData::EObjectMetaDataUpdate) && IsMediaFormat(aObject.Uint(CMTPObjectMetaData::EFormatCode))) |
|
589 { |
|
590 if (iUpdateDeltaDataTable) |
|
591 { |
|
592 iMtpDeltaDataMgr->UpdateDeltaDataTableL(id, CMtpDeltaDataMgr::EModified); |
|
593 } |
|
594 } |
|
595 } |
|
596 else |
|
597 { |
|
598 User::Leave(KErrNotFound); |
|
599 } |
|
600 } |
|
601 |
|
602 TBool CMTPObjectStore::ObjectL(const TMTPTypeUint32& aHandle, CMTPObjectMetaData& aBuf) const |
|
603 { |
|
604 TUint32 handleId = aHandle.Value(); |
|
605 aBuf.SetUint(CMTPObjectMetaData::EHandle, handleId); |
|
606 return GetObjectL(handleId, aBuf); |
|
607 } |
|
608 |
|
609 TBool CMTPObjectStore::ObjectExistsL(const TUint32 aHandle) |
|
610 { |
|
611 return LocateByHandleL(aHandle, EFalse); |
|
612 } |
|
613 |
|
614 |
|
615 void CMTPObjectStore::BuildObjectMetaDataL(CMTPObjectMetaData& aBuf, const RDbTable& aTable) const |
|
616 { |
|
617 aBuf.SetUint(CMTPObjectMetaData::EHandle, aTable.ColUint32(EObjectStoreHandleId)); |
|
618 |
|
619 TFileName suid; |
|
620 DbColReadStreamL(aTable, EObjectStoreSUID, suid); |
|
621 aBuf.SetDesCL(CMTPObjectMetaData::ESuid, suid); |
|
622 |
|
623 aBuf.SetUint(CMTPObjectMetaData::EFormatCode, aTable.ColUint16(EObjectStoreFormatCode)); |
|
624 aBuf.SetUint(CMTPObjectMetaData::EFormatSubCode, aTable.ColUint16(EObjectStoreFormatSubCode)); |
|
625 aBuf.SetUint(CMTPObjectMetaData::EDataProviderId, aTable.ColUint8(EObjectStoreDataProviderId)); |
|
626 aBuf.SetUint(CMTPObjectMetaData::EParentHandle, aTable.ColUint32(EObjectStoreParentHandle)); |
|
627 aBuf.SetUint(CMTPObjectMetaData::EStorageId, aTable.ColUint32(EObjectStoreStorageId)); |
|
628 aBuf.SetUint(CMTPObjectMetaData::EModes, aTable.ColUint8(EObjectStoreModes)); |
|
629 aBuf.SetUint(CMTPObjectMetaData::EIdentifier, aTable.ColInt64(EObjectStorePOUID)); |
|
630 aBuf.SetUint(CMTPObjectMetaData::ENonConsumable, aTable.ColUint8(EObjectStoreNonConsumable)); |
|
631 aBuf.SetDesCL(CMTPObjectMetaData::EName, aTable.ColDes(EObjectStoreName)); |
|
632 } |
|
633 |
|
634 TBool CMTPObjectStore::ObjectL(const TDesC& aSuid, CMTPObjectMetaData& aBuf) const |
|
635 { |
|
636 if (LocateBySuidL(aSuid)) |
|
637 { |
|
638 BuildObjectMetaDataL(aBuf, iBatched_SuidHashID); |
|
639 return ETrue; |
|
640 } |
|
641 return EFalse; |
|
642 } |
|
643 |
|
644 const TPtrC CMTPObjectStore::ObjectSuidL(TUint32 aHandle) const |
|
645 { |
|
646 //iBatched owns the memory of Suid ? |
|
647 if (!LocateByHandleL(aHandle)) |
|
648 { |
|
649 User::Leave(KErrNotFound); |
|
650 } |
|
651 DbColReadStreamL(iBatched, EObjectStoreSUID, iSuidBuf); |
|
652 return iSuidBuf; |
|
653 } |
|
654 |
|
655 TMTPTypeUint128 CMTPObjectStore::PuidL(TUint32 aHandle) |
|
656 { |
|
657 if (!LocateByHandleL(aHandle)) |
|
658 { |
|
659 User::Leave(KErrNotFound); |
|
660 } |
|
661 TUint64 highHalfPOUID = static_cast<TUint64> (iBatched.ColInt64(EObjectStorePOUID)); |
|
662 // We actually use the first 64 bits to represent the PUID. this will represent 2^64=16 G xG objects, it is reasonable |
|
663 //to assume the Phone, as a resource-constrained device, never will reach that number, therefore, we choose |
|
664 //only 64 bit to represent the POUID Of the objects on phone. |
|
665 TMTPTypeUint128 result; |
|
666 result.Set(1, highHalfPOUID); //for the ONB |
|
667 return result; |
|
668 } |
|
669 |
|
670 TMTPTypeUint128 CMTPObjectStore::PuidL(const TDesC& aSuid) |
|
671 { |
|
672 if (!LocateBySuidL(aSuid)) |
|
673 { |
|
674 User::Leave(KErrNotFound); |
|
675 } |
|
676 TUint64 highHalfPOUID = static_cast<TUint64> (iBatched_SuidHashID.ColInt64(EObjectStorePOUID)); |
|
677 // We actually use the first 64 bits to represent the PUID. this will represent 2^64=16 G xG objects, it is reasonable |
|
678 //to assume the Phone, as a resource-constrained device, never will reach that number, therefore, we choose |
|
679 //only 64 bit to represent the POUID Of the objects on phone. |
|
680 TMTPTypeUint128 result; |
|
681 result.Set(1, highHalfPOUID); //for the ONB |
|
682 return result; |
|
683 } |
|
684 |
|
685 void CMTPObjectStore::RemoveObjectL(const TMTPTypeUint32& aHandle) |
|
686 { |
|
687 if (LocateByHandleL(aHandle.Value())) |
|
688 { |
|
689 if (iSingletons.DpController().EnumerateState() != CMTPDataProviderController::EEnumerated && |
|
690 IsMediaFormat(iBatched.ColUint16(EObjectStoreFormatCode))) |
|
691 { |
|
692 iMtpDeltaDataMgr->UpdateDeltaDataTableL(iBatched.ColInt64(EObjectStorePOUID), CMtpDeltaDataMgr::EDeleted); |
|
693 } |
|
694 iCachedSuidHash = 0; |
|
695 iCachedHandle = 0; |
|
696 iBatched.DeleteL(); |
|
697 IncTranOpsNumL(); |
|
698 } |
|
699 } |
|
700 |
|
701 void CMTPObjectStore::RemoveObjectL(const TDesC& aSuid) |
|
702 { |
|
703 if(LocateBySuidL(aSuid)) |
|
704 { |
|
705 if (iSingletons.DpController().EnumerateState() != CMTPDataProviderController::EEnumerated && |
|
706 IsMediaFormat(iBatched_SuidHashID.ColUint16(EObjectStoreFormatCode))) |
|
707 { |
|
708 iMtpDeltaDataMgr->UpdateDeltaDataTableL(iBatched_SuidHashID.ColInt64(EObjectStorePOUID), CMtpDeltaDataMgr::EDeleted); |
|
709 } |
|
710 iCachedSuidHash = 0; |
|
711 iCachedHandle = 0; |
|
712 iBatched_SuidHashID.DeleteL(); |
|
713 IncTranOpsNumL(); |
|
714 } |
|
715 } |
|
716 |
|
717 void CMTPObjectStore::RemoveObjectsL(const CDesCArray& aSuids) |
|
718 { |
|
719 TUint i(aSuids.Count()); |
|
720 while (i--) |
|
721 { |
|
722 RemoveObjectL(aSuids[i]); |
|
723 } |
|
724 } |
|
725 |
|
726 void CMTPObjectStore::RemoveObjectsL(TUint aDataProviderId) |
|
727 { |
|
728 iCachedSuidHash = 0; |
|
729 iCachedHandle = 0; |
|
730 TMTPObjectMgrQueryParams params(KMTPStorageAll, 0, 0, aDataProviderId); |
|
731 TDelAction action(*this, MTraverseAction::EAllDP); |
|
732 TraverseL(params, action); |
|
733 } |
|
734 |
|
735 void CMTPObjectStore::RemoveObjectsByStorageIdL(TUint32 aStorageId) |
|
736 { |
|
737 iCachedSuidHash = 0; |
|
738 iCachedHandle = 0; |
|
739 TMTPObjectMgrQueryParams params(aStorageId, 0, 0); |
|
740 TDelAction action(*this); |
|
741 TraverseL(params, action); |
|
742 } |
|
743 |
|
744 void CMTPObjectStore::ReserveObjectHandleL(CMTPObjectMetaData& aObject, TUint64 /*aSpaceRequired*/) |
|
745 { |
|
746 const TUint dp(aObject.Uint(CMTPObjectMetaData::EDataProviderId)); |
|
747 const TUint32 id(iHandleAllocator->NextIdL(dp)); |
|
748 aObject.SetUint(CMTPObjectMetaData::EHandle, id); |
|
749 } |
|
750 |
|
751 void CMTPObjectStore::UnreserveObjectHandleL(const CMTPObjectMetaData& /*aObjectInfo*/) |
|
752 { |
|
753 |
|
754 } |
|
755 |
|
756 /** |
|
757 Clean unloaded data provider contents from object store |
|
758 */ |
|
759 void CMTPObjectStore::CleanL() |
|
760 { |
|
761 __FLOG(_L8("CleanL - Entry")); |
|
762 Swi::RSisRegistrySession sisSession; |
|
763 User::LeaveIfError(sisSession.Connect()); |
|
764 CleanupClosePushL(sisSession); |
|
765 |
|
766 const RArray<TUint>& loadedDPIDs = iPkgIDStore->DPIDL(); |
|
767 RArray<TUint> unInstalledDpIDs; |
|
768 CleanupClosePushL(unInstalledDpIDs); |
|
769 for (TUint idx(0); (idx < loadedDPIDs.Count()); ++idx) |
|
770 { |
|
771 TUid pkgUid = TUid::Uid(iPkgIDStore->PKGIDL(idx)); |
|
772 if (!sisSession.IsInstalledL(pkgUid)) |
|
773 { |
|
774 //DP is uninstalled, remove DP related data from database. |
|
775 TUint thisID = loadedDPIDs[idx]; |
|
776 __FLOG_1(_L("Data provider[%d] is removed from device!"),thisID); |
|
777 unInstalledDpIDs.AppendL(thisID); |
|
778 } |
|
779 } |
|
780 for (TUint index = 0; index < unInstalledDpIDs.Count(); ++index) |
|
781 { |
|
782 RemoveObjectsL(unInstalledDpIDs[index]); |
|
783 iPkgIDStore->RemoveL(unInstalledDpIDs[index]); |
|
784 } |
|
785 CleanupStack::PopAndDestroy(&unInstalledDpIDs); |
|
786 CleanupStack::PopAndDestroy(&sisSession); |
|
787 __FLOG(_L8("CleanL - Exit")); |
|
788 } |
|
789 |
|
790 TUint CMTPObjectStore::ObjectOwnerId(const TMTPTypeUint32& aHandle) const |
|
791 { |
|
792 if (!LocateByHandleL(aHandle.Value())) |
|
793 { |
|
794 return 0xff; |
|
795 } |
|
796 return iBatched.ColUint32(EObjectStoreDataProviderId); |
|
797 } |
|
798 /** |
|
799 Standard c++ constructor |
|
800 */ |
|
801 CMTPObjectStore::CMTPObjectStore() |
|
802 { |
|
803 } |
|
804 |
|
805 /** |
|
806 Second phase constructor. |
|
807 */ |
|
808 void CMTPObjectStore::ConstructL() |
|
809 { |
|
810 __FLOG_OPEN(KMTPSubsystem, KComponent); |
|
811 iMaxCommitLimit = KMaxLimitCommitInEnumeration; |
|
812 iMaxCompactLimit = KMaxLimitCompactInEnumeration; |
|
813 iSingletons.OpenL(); |
|
814 InitializeDbL(); |
|
815 iCompactor = CDbCompactor::NewL(&iDatabase); |
|
816 iMtpDeltaDataMgr = CMtpDeltaDataMgr::NewL(iDatabase); |
|
817 iReferenceMgr = CMTPReferenceMgr::NewL(*this); |
|
818 iDPIDStore = CMTPDPIDStore::NewL(iDatabase); |
|
819 iPkgIDStore = CMTPPkgIDStore::NewL(iDatabase); |
|
820 iBatched.Open(iDatabase, KSQLHandleTableName, RDbRowSet::EUpdatable); |
|
821 iBatched.SetIndex(KSQLHandleId); |
|
822 iBatched_SuidHashID.Open(iDatabase, KSQLHandleTableName, RDbRowSet::EUpdatable); |
|
823 iBatched_SuidHashID.SetIndex(KSQLSuidHash); |
|
824 iHandleAllocator = CMTPHandleAllocator::NewL(*this); |
|
825 iSentinal = CEnumertingCacheItem::NewL(0, 0, 0, 0, 0); |
|
826 BeginTransactionL(); |
|
827 } |
|
828 |
|
829 /** |
|
830 Initialises the database, it creates the table and index if the database does not exist, otherwise, |
|
831 it open the existing table and index |
|
832 */ |
|
833 void CMTPObjectStore::InitializeDbL() |
|
834 { |
|
835 TFileName fullName; |
|
836 GetFullPathName(KMTPNoBackupFolderName, fullName); |
|
837 BaflUtils::EnsurePathExistsL(iSingletons.Fs(), fullName); |
|
838 fullName.Append(KMTPBackSlash); |
|
839 fullName.Append(KMTPHandleObjectDbName); |
|
840 TInt err = KErrNone; |
|
841 if (!BaflUtils::FileExists(iSingletons.Fs(), fullName)) |
|
842 { |
|
843 CreateDbL(fullName); |
|
844 } |
|
845 else |
|
846 { |
|
847 err = OpenDb(fullName); |
|
848 if (iDatabase.IsDamaged()) |
|
849 { |
|
850 err = iDatabase.Recover(); |
|
851 } |
|
852 } |
|
853 |
|
854 if (err != KErrNone) |
|
855 { |
|
856 CloseDb(); |
|
857 CreateDbL(fullName); |
|
858 } |
|
859 } |
|
860 |
|
861 /** |
|
862 Create the database with the specified database name |
|
863 @param aFileName The name of the database to create |
|
864 */ |
|
865 void CMTPObjectStore::CreateDbL(const TDesC& aFileName) |
|
866 { |
|
867 BaflUtils::EnsurePathExistsL(iSingletons.Fs(), aFileName); |
|
868 |
|
869 User::LeaveIfError(iDatabase.Replace(iSingletons.Fs(), aFileName, KMTPFormat)); |
|
870 // Create table and index |
|
871 CreateHandleTableL(); |
|
872 CreateHandleIndexL(); |
|
873 //This is the very very 1st time of MTP server running, therefore, all of the objects in the HandleStore should be added items |
|
874 //roundtrip table will fetch the added items directly from the handlestore, do not popluate the added items to round-trip table |
|
875 //until the enumeration is finished. |
|
876 iUpdateDeltaDataTable = EFalse; |
|
877 } |
|
878 |
|
879 /** |
|
880 Open the database with the specified database name |
|
881 @param aFileName The name of the database to open |
|
882 */ |
|
883 TInt CMTPObjectStore::OpenDb(const TDesC& aFileName) |
|
884 { |
|
885 TInt err = iDatabase.Open(iSingletons.Fs(), aFileName, KMTPFormat); |
|
886 if(KErrNone == err) |
|
887 { |
|
888 TRAP(err, |
|
889 CreateHandleTableL(); |
|
890 CreateHandleIndexL(); |
|
891 ) |
|
892 } |
|
893 iUpdateDeltaDataTable = ETrue; |
|
894 return err; |
|
895 } |
|
896 |
|
897 /** |
|
898 Close the current opened database |
|
899 */ |
|
900 void CMTPObjectStore::CloseDb() |
|
901 { |
|
902 iDatabase.Close(); |
|
903 } |
|
904 |
|
905 /** |
|
906 Create the table for storing the mapping from object handle to other properties (data provider id, storage id, formatcode, etc.) |
|
907 */ |
|
908 void CMTPObjectStore::CreateHandleTableL() |
|
909 { |
|
910 if (!DBUtility::IsTableExistsL(iDatabase, KSQLHandleTableName)) |
|
911 { |
|
912 User::LeaveIfError(iDatabase.Execute(KSQLCreateHandleTableText)); |
|
913 } |
|
914 } |
|
915 |
|
916 /** |
|
917 Create three index on the table: 1. Handle, 2. SuidHash, 3. ParentHandle |
|
918 */ |
|
919 void CMTPObjectStore::CreateHandleIndexL() |
|
920 { |
|
921 if (DBUtility::IsTableExistsL(iDatabase, KSQLHandleTableName)) |
|
922 { |
|
923 if (!DBUtility::IsIndexExistsL(iDatabase, KSQLHandleTableName, KSQLHandleId)) |
|
924 { |
|
925 User::LeaveIfError(iDatabase.Execute(KSQLCreateHandleIndexText)); |
|
926 } |
|
927 |
|
928 if (!DBUtility::IsIndexExistsL(iDatabase, KSQLHandleTableName, KSQLSuidHash)) |
|
929 { |
|
930 User::LeaveIfError(iDatabase.Execute(KSQLCreateSuidIndexText)); |
|
931 } |
|
932 |
|
933 if (!DBUtility::IsIndexExistsL(iDatabase, KSQLHandleTableName, KSQLParentHandle)) |
|
934 { |
|
935 User::LeaveIfError(iDatabase.Execute(KSQLCreateParentHandleText)); |
|
936 } |
|
937 } |
|
938 else |
|
939 { |
|
940 User::Leave(KErrNotFound); |
|
941 } |
|
942 } |
|
943 |
|
944 /** |
|
945 Get the full path of the database |
|
946 @param aFileName The file name of the database to be retrieved |
|
947 */ |
|
948 void CMTPObjectStore::GetFullPathName(const TDesC& aName, TFileName& aFileName) const |
|
949 { |
|
950 iSingletons.Fs().PrivatePath(aFileName); |
|
951 aFileName.Insert(0, KMTPDbDriveLocation); |
|
952 aFileName.Append(aName); |
|
953 } |
|
954 |
|
955 /** |
|
956 Initialize the handle allocator for this DP with the minimum object ID to use. |
|
957 This must not be called while an initiator has an open session or it could cause |
|
958 an object ID to be reused. |
|
959 @param aDataProviderId Data provider ID whose handle allocator must be initialized |
|
960 */ |
|
961 void CMTPObjectStore::RestorePersistentObjectsL(TUint) |
|
962 { |
|
963 |
|
964 } |
|
965 |
|
966 TBool CMTPObjectStore::LocateByHandleL(const TUint aHandle, const TBool aReadTable /*default = ETrue*/) const |
|
967 { |
|
968 TBool result = EFalse; |
|
969 if(IsInvalidHandle(aHandle)) |
|
970 { |
|
971 return result; |
|
972 } |
|
973 |
|
974 if (iCachedHandle == aHandle) |
|
975 { |
|
976 result = ETrue; |
|
977 } |
|
978 else |
|
979 { |
|
980 if (iBatched.SeekL(aHandle)) |
|
981 { |
|
982 iCachedHandle = aHandle; |
|
983 result = ETrue; |
|
984 } |
|
985 else |
|
986 { |
|
987 iCachedHandle = 0; |
|
988 } |
|
989 } |
|
990 if (result && aReadTable) |
|
991 { |
|
992 iBatched.GetL(); |
|
993 } |
|
994 return result; |
|
995 } |
|
996 |
|
997 TBool CMTPObjectStore::LocateBySuidL(const TDesC& aSuid) const |
|
998 { |
|
999 TBool result = EFalse; |
|
1000 TFileName suid; |
|
1001 suid.CopyLC(aSuid); |
|
1002 TUint32 suidHash = DefaultHash::Des16(suid); |
|
1003 if (iCachedSuidHash == suidHash && iCachedSuidHash != 0) //the hash may generate 0 and we use 0 as a sentinel |
|
1004 { |
|
1005 iBatched_SuidHashID.GetL(); |
|
1006 DbColReadStreamL(iBatched_SuidHashID, EObjectStoreSUID, suid); |
|
1007 if (suid.CompareF(aSuid) == 0 ) |
|
1008 { |
|
1009 result = ETrue; |
|
1010 } |
|
1011 } |
|
1012 if (!result) |
|
1013 { |
|
1014 if (iBatched_SuidHashID.SeekL(static_cast<TUint> (suidHash))) |
|
1015 {//found, but there might be multiple entries since SUIDhash might possible conflict. |
|
1016 while (!iBatched_SuidHashID.AtEnd()) |
|
1017 { |
|
1018 iBatched_SuidHashID.GetL(); |
|
1019 DbColReadStreamL(iBatched_SuidHashID, EObjectStoreSUID, suid); |
|
1020 if (suid.CompareF(aSuid) == 0) |
|
1021 { |
|
1022 result = ETrue; |
|
1023 iCachedSuidHash = suidHash; |
|
1024 break; |
|
1025 } |
|
1026 else if (iBatched_SuidHashID.ColUint32(EObjectStoreSUIDHash) == suidHash) |
|
1027 { |
|
1028 iBatched_SuidHashID.NextL(); |
|
1029 } |
|
1030 else |
|
1031 { |
|
1032 iCachedSuidHash = 0; |
|
1033 break;//Not found |
|
1034 } |
|
1035 } |
|
1036 } |
|
1037 else |
|
1038 { |
|
1039 iCachedSuidHash = 0; |
|
1040 } |
|
1041 } |
|
1042 return result; |
|
1043 } |
|
1044 |
|
1045 /** |
|
1046 Get an object for the current query |
|
1047 @param aBuf if found, contains the pointer to the created object info, |
|
1048 @return ETrue if the object is found, otherwise, EFalse |
|
1049 */ |
|
1050 |
|
1051 TBool CMTPObjectStore::GetObjectL(TUint32 aHandle, CMTPObjectMetaData& aObject) const |
|
1052 { |
|
1053 if (LocateByHandleL(aHandle)) |
|
1054 { |
|
1055 BuildObjectMetaDataL(aObject, iBatched); |
|
1056 return ETrue; |
|
1057 } |
|
1058 return EFalse; |
|
1059 } |
|
1060 |
|
1061 /** |
|
1062 Determine if the object is of WMP supported media format |
|
1063 @param aObject the object meta data |
|
1064 @return ETrue if it is of WMP supported media format. EFalse otherwise. |
|
1065 */ |
|
1066 TBool CMTPObjectStore::IsMediaFormat(TUint32 aFormatCode) |
|
1067 { |
|
1068 switch (aFormatCode) |
|
1069 { |
|
1070 //case EMTPFormatCodeUndefined: |
|
1071 //case EMTPFormatCodeAssociation: |
|
1072 case EMTPFormatCodeAIFF: |
|
1073 case EMTPFormatCodeWAV: |
|
1074 case EMTPFormatCodeMP3: |
|
1075 case EMTPFormatCodeAVI: |
|
1076 case EMTPFormatCodeMPEG: |
|
1077 case EMTPFormatCodeASF: |
|
1078 case EMTPFormatCodeEXIFJPEG: |
|
1079 case EMTPFormatCodeTIFFEP: |
|
1080 case EMTPFormatCodeFlashPix: |
|
1081 case EMTPFormatCodeBMP: |
|
1082 case EMTPFormatCodeCIFF: |
|
1083 case EMTPFormatCodeGIF: |
|
1084 case EMTPFormatCodeJFIF: |
|
1085 case EMTPFormatCodeCD: |
|
1086 case EMTPFormatCodePICT: |
|
1087 case EMTPFormatCodePNG: |
|
1088 case EMTPFormatCodeTIFF: |
|
1089 case EMTPFormatCodeTIFFIT: |
|
1090 case EMTPFormatCodeJP2: |
|
1091 case EMTPFormatCodeJPX: |
|
1092 case EMTPFormatCodeUndefinedFirmware: |
|
1093 case EMTPFormatCodeWindowsImageFormat: |
|
1094 case EMTPFormatCodeUndefinedAudio: |
|
1095 case EMTPFormatCodeWMA: |
|
1096 case EMTPFormatCodeOGG: |
|
1097 case EMTPFormatCodeAAC: |
|
1098 case EMTPFormatCodeAudible: |
|
1099 case EMTPFormatCodeWMV: |
|
1100 case EMTPFormatCodeMP4Container: |
|
1101 case EMTPFormatCodeMP2: |
|
1102 case EMTPFormatCode3GPContainer: |
|
1103 case EMTPFormatCodeAbstractMultimediaAlbum: |
|
1104 case EMTPFormatCodeAbstractImageAlbum: |
|
1105 case EMTPFormatCodeAbstractAudioAlbum: |
|
1106 case EMTPFormatCodeAbstractVideoAlbum: |
|
1107 case EMTPFormatCodeAbstractAudioVideoPlaylist: |
|
1108 case EMTPFormatCodeAbstractAudioPlaylist: |
|
1109 case EMTPFormatCodeAbstractVideoPlaylist: |
|
1110 case EMTPFormatCodeWPLPlaylist: |
|
1111 case EMTPFormatCodeM3UPlaylist: |
|
1112 case EMTPFormatCodeMPLPlaylist: |
|
1113 case EMTPFormatCodeASXPlaylist: |
|
1114 case EMTPFormatCodePLSPlaylist: |
|
1115 return ETrue; |
|
1116 |
|
1117 default: |
|
1118 return EFalse; |
|
1119 } |
|
1120 } |
|
1121 |
|
1122 void CMTPObjectStore::CalcFreeHandlesL(TUint aDataProviderId) |
|
1123 { |
|
1124 TMTPTypeObjectHandle handleType(0, aDataProviderId); |
|
1125 TUint32 minHandleForDP = handleType.Value(); |
|
1126 iCachedSuidHash = 0; |
|
1127 iCachedHandle = 0; |
|
1128 TUint32 preHandle = minHandleForDP, curHandle = 0; |
|
1129 if (iBatched.SeekL((TUint) minHandleForDP, RDbTable::ELessThan)) |
|
1130 { |
|
1131 iBatched.NextL(); |
|
1132 while (!iBatched.AtEnd()) |
|
1133 { |
|
1134 iBatched.GetL(); |
|
1135 curHandle = iBatched.ColUint32(EObjectStoreHandleId); |
|
1136 TMTPTypeObjectHandle handleType(curHandle); |
|
1137 if (handleType.DpId() == aDataProviderId) |
|
1138 { |
|
1139 if(++ preHandle < curHandle)//base on the handle is allocated continuously |
|
1140 { |
|
1141 if(!iHandleAllocator->AppendHandleBlockL(aDataProviderId, preHandle, curHandle - preHandle)) |
|
1142 { |
|
1143 break; |
|
1144 } |
|
1145 preHandle = curHandle; |
|
1146 } |
|
1147 iBatched.NextL(); |
|
1148 } |
|
1149 else |
|
1150 { |
|
1151 //Has gone over the current DPid, break; |
|
1152 break; |
|
1153 } |
|
1154 } |
|
1155 } |
|
1156 } |
|
1157 |
|
1158 void CMTPObjectStore::EstablishDBSnapshotL(TUint32 aStorageId) |
|
1159 { |
|
1160 //Currently, i only do this for File DP since it is non-persistent, later, if we take the proposal that |
|
1161 //1. FileDP is the last DP to be enumerated. |
|
1162 //2. FileDP will san the whole file system, and will try to enumerate all of the objects(might on behalf of another DP) if the objects is still not |
|
1163 // in the object store after all other DP finish its enumeration. |
|
1164 //3. Then notify the related DP about the newly added objects by notification API; |
|
1165 //_LIT(KInsert, "CMTPObjectStore::EstablishDBSnapshotL"); |
|
1166 //volatile TTimer t(KInsert); |
|
1167 RDbTable temp; |
|
1168 CleanupClosePushL(temp); |
|
1169 temp.Open(iDatabase, KSQLHandleTableName, RDbRowSet::EUpdatable); |
|
1170 if(!iCacheExist) |
|
1171 { |
|
1172 TInt32 count = temp.CountL(RDbRowSet::EQuick); |
|
1173 iEnumeratingCacheObjList.ReserveL(count); |
|
1174 } |
|
1175 temp.FirstL(); |
|
1176 while (!temp.AtEnd()) |
|
1177 { |
|
1178 temp.GetL(); |
|
1179 if (temp.ColUint8(EObjectStoreDPFlag) == 1 && (KMTPStorageAll == aStorageId || temp.ColUint32(EObjectStoreStorageId) == aStorageId)) |
|
1180 { |
|
1181 TUint32 handleID = temp.ColUint32(EObjectStoreHandleId); |
|
1182 TInt64 pUID = temp.ColInt64(EObjectStorePOUID); |
|
1183 iHandleAllocator->SetIdL(handleID, pUID); |
|
1184 CEnumertingCacheItem* item = CEnumertingCacheItem::NewLC( |
|
1185 temp.ColUint32(EObjectStoreSUIDHash), handleID, |
|
1186 temp.ColUint16(EObjectStoreFormatCode), pUID, temp.ColUint8(EObjectStoreDataProviderId)); |
|
1187 TInt result = iEnumeratingCacheObjList.InsertInOrder(item, TLinearOrder<CEnumertingCacheItem>(CEnumertingCacheItem::Compare)); |
|
1188 if (KErrAlreadyExists == result) //hash collision |
|
1189 { |
|
1190 TInt found = iEnumeratingCacheObjList.FindInOrder(item, TLinearOrder<CEnumertingCacheItem>(CEnumertingCacheItem::Compare)); |
|
1191 CEnumertingCacheItem* colliItem = iEnumeratingCacheObjList[found]; |
|
1192 TFileName suid; |
|
1193 if (colliItem->iSuid == NULL) |
|
1194 { |
|
1195 if (!LocateByHandleL(colliItem->iObjHandleId)) |
|
1196 { |
|
1197 DbColReadStreamL(iBatched, EObjectStoreSUID, suid); |
|
1198 |
|
1199 colliItem->iSuid = suid.AllocL(); |
|
1200 |
|
1201 colliItem->iSuidPtr.Set(*colliItem->iSuid); |
|
1202 } |
|
1203 } |
|
1204 DbColReadStreamL(temp, EObjectStoreSUID, suid); |
|
1205 |
|
1206 item->iSuid = suid.AllocL(); |
|
1207 |
|
1208 item->iSuidPtr.Set(*item->iSuid); |
|
1209 result = iEnumeratingCacheObjList.InsertInOrder(item, TLinearOrder<CEnumertingCacheItem>(CEnumertingCacheItem::Compare)); |
|
1210 } |
|
1211 if(result != KErrAlreadyExists) |
|
1212 { |
|
1213 User::LeaveIfError(result); |
|
1214 } |
|
1215 CleanupStack::Pop(item); |
|
1216 } |
|
1217 temp.NextL(); |
|
1218 } |
|
1219 CleanupStack::PopAndDestroy(&temp); |
|
1220 iCacheExist = ETrue; |
|
1221 } |
|
1222 |
|
1223 void CMTPObjectStore::CleanDBSnapshotL() |
|
1224 { |
|
1225 //For those items left in the iEnumeratingCacheObjList, remove the object entry if the DPID of the handle is not persistent. and populate the |
|
1226 //roundtrip table if needed. |
|
1227 //and then close the iEnumeratingCacheObjList to release the memory. |
|
1228 //_LIT(KInsert, "CMTPObjectStore::CleanDBSnapshot"); |
|
1229 //volatile TTimer t(KInsert); |
|
1230 if(iCacheExist) |
|
1231 { |
|
1232 iCacheExist = EFalse; |
|
1233 } |
|
1234 else |
|
1235 return; |
|
1236 |
|
1237 for (TInt i = iEnumeratingCacheObjList.Count() - 1; i >= 0; i--) |
|
1238 { |
|
1239 TInt rc = iNonPersistentDPList.FindInOrder(iEnumeratingCacheObjList[i]->iDpID); |
|
1240 if (rc != KErrNotFound) |
|
1241 {//This is a non persistent DP. |
|
1242 RemoveObjectL(iEnumeratingCacheObjList[i]->iObjHandleId); |
|
1243 } |
|
1244 } |
|
1245 iNonPersistentDPList.Close(); |
|
1246 iEnumeratingCacheObjList.ResetAndDestroy(); |
|
1247 iUpdateDeltaDataTable = ETrue; |
|
1248 iMaxCommitLimit = KMaxLimitCommitAfterEnumeration; |
|
1249 iMaxCompactLimit = KMaxLimitCompactAfterEnumeration; |
|
1250 CommitTransactionL(); |
|
1251 User::LeaveIfError(iDatabase.Compact()); |
|
1252 BeginTransactionL(); |
|
1253 } |
|
1254 |
|
1255 CMTPObjectStore::CEnumertingCacheItem::CEnumertingCacheItem(TUint32 aSuidHash, TUint32 aHandle, TUint32 aFormat, TUint64 aId, TUint8 aDpID) |
|
1256 { |
|
1257 iObjSuiIdHash = aSuidHash; |
|
1258 iObjHandleId = aHandle; |
|
1259 iFormatcode = aFormat; |
|
1260 iPOUID = aId; |
|
1261 iDpID = aDpID; |
|
1262 } |
|
1263 |
|
1264 TInt CMTPObjectStore::CEnumertingCacheItem::Compare(const CEnumertingCacheItem& aFirst, const CEnumertingCacheItem& aSecond) |
|
1265 { |
|
1266 if (aFirst.iObjSuiIdHash > aSecond.iObjSuiIdHash) |
|
1267 { |
|
1268 return 1; |
|
1269 } |
|
1270 else if (aFirst.iObjSuiIdHash < aSecond.iObjSuiIdHash) |
|
1271 { |
|
1272 return -1; |
|
1273 } |
|
1274 if ((aFirst.iSuidPtr.Length() != 0) && (aSecond.iSuidPtr.Length() != 0)) |
|
1275 { |
|
1276 return aFirst.iSuidPtr.CompareF(aSecond.iSuidPtr); |
|
1277 } |
|
1278 return 0; |
|
1279 } |
|
1280 |
|
1281 TBool CMTPObjectStore::IsInvalidHandle( TUint32 aHandle ) const |
|
1282 { |
|
1283 return ( (KMTPHandleAll == aHandle) || (KMTPHandleNone == aHandle) ); |
|
1284 } |
|
1285 |
|
1286 void CMTPObjectStore::DbColWriteStreamL(RDbTable& aTable, TDbColNo aCol, const TDesC16& aDes) |
|
1287 { |
|
1288 RDbColWriteStream suid; |
|
1289 suid.OpenLC(aTable, aCol); |
|
1290 suid.WriteL(aDes); |
|
1291 suid.Close(); |
|
1292 CleanupStack::PopAndDestroy(); // suid |
|
1293 } |
|
1294 |
|
1295 void CMTPObjectStore::DbColReadStreamL(const RDbTable& aTable, TDbColNo aCol, TDes16& aDes) const |
|
1296 { |
|
1297 RDbColReadStream suid; |
|
1298 suid.OpenLC(aTable, aCol); |
|
1299 suid.ReadL(aDes, aTable.ColLength(aCol)); |
|
1300 suid.Close(); |
|
1301 CleanupStack::PopAndDestroy(); // suid |
|
1302 } |