1 /* |
|
2 * Copyright (c) 2003-2006 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: Operation independent remote file handling functions |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include <apgcli.h> |
|
20 #include <bautils.h> |
|
21 |
|
22 #include "rsfwfileentry.h" |
|
23 #include "rsfwfiletable.h" |
|
24 #include "rsfwvolumetable.h" |
|
25 #include "rsfwvolume.h" |
|
26 #include "rsfwrfestatemachine.h" |
|
27 #include "rsfwinterface.h" |
|
28 #include "rsfwcontrol.h" |
|
29 #include "rsfwremoteaccess.h" |
|
30 #include "rsfwfileengine.h" |
|
31 #include "rsfwrfeserver.h" |
|
32 #include "rsfwlockmanager.h" |
|
33 #include "mdebug.h" |
|
34 #include "rsfwdirent.h" |
|
35 #include "rsfwdirentattr.h" |
|
36 #include "rsfwinterface.h" |
|
37 |
|
38 // ---------------------------------------------------------------------------- |
|
39 // CRsfwFileEngine::NewL |
|
40 // ---------------------------------------------------------------------------- |
|
41 // |
|
42 CRsfwFileEngine* CRsfwFileEngine::NewL(CRsfwVolume* aVolume) |
|
43 { |
|
44 CRsfwFileEngine* self = CRsfwFileEngine::NewLC(aVolume); |
|
45 CleanupStack::Pop(self); |
|
46 return self; |
|
47 } |
|
48 |
|
49 // ---------------------------------------------------------------------------- |
|
50 // CRsfwFileEngine::NewLC |
|
51 // ---------------------------------------------------------------------------- |
|
52 // |
|
53 CRsfwFileEngine* CRsfwFileEngine::NewLC(CRsfwVolume* aVolume) |
|
54 { |
|
55 DEBUGSTRING(("CRsfwFileEngine::NewLC")); |
|
56 CRsfwFileEngine* self = new (ELeave) CRsfwFileEngine(); |
|
57 DEBUGSTRING(("CRsfwFileEngine: in NewLC 0x%x", self)); |
|
58 CleanupStack::PushL(self); |
|
59 self->ConstructL(aVolume); |
|
60 return self; |
|
61 } |
|
62 |
|
63 // ---------------------------------------------------------------------------- |
|
64 // CRsfwFileEngine::ConstructL |
|
65 // ---------------------------------------------------------------------------- |
|
66 // |
|
67 void CRsfwFileEngine::ConstructL(CRsfwVolume* aVolume) |
|
68 { |
|
69 iRemoteAccess = NULL; |
|
70 iRootFid = NULL; |
|
71 iRootFep = NULL; |
|
72 iVolume = aVolume; |
|
73 iFs = CRsfwRfeServer::Env()->iFs; |
|
74 iConnectionState = KMountNotConnected; |
|
75 __ASSERT_ALWAYS(iVolume != NULL, User::Panic(KRfeServer, EConstructingServerStructs)); |
|
76 iInactivityTimeout = |
|
77 iVolume->iMountInfo.iMountConfig.iInactivityTimeout * 1000000; |
|
78 PrepareCacheL(); |
|
79 // Create file table |
|
80 iFileTable = CRsfwFileTable::NewL(aVolume, iCacheRoot); |
|
81 __ASSERT_ALWAYS(iVolume->iVolumeTable != NULL, User::Panic(KRfeServer, |
|
82 EConstructingServerStructs)); |
|
83 SetupRootL(iVolume->iVolumeTable->iPermanence); |
|
84 } |
|
85 |
|
86 // ---------------------------------------------------------------------------- |
|
87 // CRsfwFileEngine::~CRsfwFileEngine |
|
88 // ---------------------------------------------------------------------------- |
|
89 // |
|
90 CRsfwFileEngine::~CRsfwFileEngine() |
|
91 { |
|
92 DEBUGSTRING(("CRsfwFileEngine destructor")); |
|
93 delete iFileTable; |
|
94 delete iRemoteAccess; |
|
95 delete iLockManager; |
|
96 StopInactivityTimer(); |
|
97 delete iInactivityTimer; |
|
98 } |
|
99 |
|
100 // ---------------------------------------------------------------------------- |
|
101 // CRsfwFileEngine::DispatchL |
|
102 // we should only come here with some synchronous requests |
|
103 // ---------------------------------------------------------------------------- |
|
104 // |
|
105 void CRsfwFileEngine::DispatchL(TRfeInArgs& aIn, TRfeOutArgs& aOut) |
|
106 { |
|
107 |
|
108 switch(aIn.iOpCode) |
|
109 { |
|
110 case EFsIoctl: |
|
111 DEBUGSTRING(("IOCTL")); |
|
112 DoIoctlL(static_cast<TRfeIoctlInArgs&>(aIn), |
|
113 aOut); |
|
114 break; |
|
115 |
|
116 case EFsRoot: |
|
117 DEBUGSTRING(("ROOT")); |
|
118 DoRootL(static_cast<TRfeRootInArgs&>(aIn), |
|
119 static_cast<TRfeRootOutArgs&>(aOut)); |
|
120 break; |
|
121 |
|
122 case ESetAttr: |
|
123 DEBUGSTRING(("SETATTR")); |
|
124 DoSetAttrL(static_cast<TRfeSetAttrInArgs&>(aIn), |
|
125 aOut); |
|
126 break; |
|
127 |
|
128 default: |
|
129 DEBUGSTRING(("WHAT??? - %d", aIn.iOpCode)); |
|
130 User::Leave(KErrArgument); |
|
131 break; |
|
132 } |
|
133 } |
|
134 |
|
135 // ---------------------------------------------------------------------------- |
|
136 // CRsfwFileEngine::FullNameLC |
|
137 // ---------------------------------------------------------------------------- |
|
138 // |
|
139 HBufC* CRsfwFileEngine::FullNameLC(CRsfwFileEntry& aFe) |
|
140 { |
|
141 HBufC* fn = aFe.FullNameLC(); |
|
142 return fn; |
|
143 } |
|
144 |
|
145 // ---------------------------------------------------------------------------- |
|
146 // CRsfwFileEngine::FullNameL |
|
147 // ---------------------------------------------------------------------------- |
|
148 // |
|
149 HBufC* CRsfwFileEngine::FullNameL(CRsfwFileEntry& aFe) |
|
150 { |
|
151 HBufC* fn = FullNameLC(aFe); |
|
152 CleanupStack::Pop(fn); |
|
153 return fn; |
|
154 } |
|
155 |
|
156 // ---------------------------------------------------------------------------- |
|
157 // CRsfwFileEngine::SetupAttributes |
|
158 // ---------------------------------------------------------------------------- |
|
159 // |
|
160 void CRsfwFileEngine::SetupAttributes(CRsfwFileEntry& aFe) |
|
161 { |
|
162 DEBUGSTRING(("CRsfwFileEngine::SetupAttributes")); |
|
163 // Construct the attributes for a newly created file or directory, |
|
164 // or a file that that was locally modified and just written to the server, |
|
165 // based on local knowledge of time and file size. |
|
166 // We assume that either the file is cached or it is an empty file. |
|
167 // We do not touch the local or protection attributes. |
|
168 |
|
169 TUint att; |
|
170 |
|
171 // Assume that the file type has already been setup |
|
172 if (aFe.Type() == KNodeTypeDir) |
|
173 { |
|
174 att = KEntryAttDir; |
|
175 } |
|
176 else |
|
177 { |
|
178 att = 0; |
|
179 } |
|
180 |
|
181 TTime time; |
|
182 if (aFe.IsCached()) |
|
183 { |
|
184 TDesC* cacheNamep = aFe.CacheFileName(); |
|
185 RFile f; |
|
186 if (f.Open(iFs, *cacheNamep, EFileShareAny) == KErrNone) |
|
187 { |
|
188 // attribute bits |
|
189 TUint a; |
|
190 f.Att(a); |
|
191 |
|
192 att |= a & KEntryAttReadOnly; |
|
193 |
|
194 if (aFe.Type() == KNodeTypeDir) |
|
195 { |
|
196 aFe.SetSize(0); |
|
197 } |
|
198 else |
|
199 { |
|
200 if (aFe.IsFullyCached()) |
|
201 { |
|
202 // size |
|
203 TInt siz; |
|
204 f.Size(siz); |
|
205 DEBUGSTRING(("File is fully cached, setting size to %d", siz)); |
|
206 aFe.SetSize(siz); |
|
207 aFe.SetCachedSize(siz); |
|
208 } |
|
209 else |
|
210 { |
|
211 DEBUGSTRING(("File is not fully cached, not touching the size")); |
|
212 // file is not fully cached |
|
213 // the size cannot be set from the local cache container |
|
214 } |
|
215 } |
|
216 // modification time |
|
217 f.Modified(time); |
|
218 |
|
219 f.Close(); |
|
220 aFe.iUseCachedData = ETrue; |
|
221 } |
|
222 else |
|
223 { |
|
224 // No cache |
|
225 aFe.SetSize(0); |
|
226 time.HomeTime(); |
|
227 } |
|
228 |
|
229 } |
|
230 else |
|
231 { |
|
232 // No cache |
|
233 aFe.SetSize(0); |
|
234 time.HomeTime(); |
|
235 } |
|
236 |
|
237 aFe.SetAtt(att); |
|
238 |
|
239 aFe.SetModified(time); |
|
240 aFe.SetAttribValidationTime(); |
|
241 } |
|
242 |
|
243 // ---------------------------------------------------------------------------- |
|
244 // CRsfwFileEngine::MakeDirectoryEntry |
|
245 // ---------------------------------------------------------------------------- |
|
246 // |
|
247 void CRsfwFileEngine::MakeDirectoryEntry(CRsfwFileEntry& aFe, TDirEnt& aDirEnt) |
|
248 { |
|
249 DEBUGSTRING(("CRsfwFileEngine::MakeDirectoryEntry")); |
|
250 DEBUGSTRING16(("name %S, att %d, size %d", aFe.Name(), aFe.Att(), aFe.Size()));; |
|
251 aDirEnt.Clear(); |
|
252 aDirEnt.iName.Copy(*aFe.Name()); |
|
253 aDirEnt.iAttr.iAtt = aFe.Att(); |
|
254 aDirEnt.iAttr.iSize = aFe.Size(); |
|
255 aDirEnt.iAttr.iModified = aFe.Modified(); |
|
256 aDirEnt.iAttr.iUid3 = aFe.iUid; |
|
257 } |
|
258 |
|
259 // ---------------------------------------------------------------------------- |
|
260 // CRsfwFileEngine::UpdateDirectoryContainerL |
|
261 // ---------------------------------------------------------------------------- |
|
262 // |
|
263 void CRsfwFileEngine::UpdateDirectoryContainerL(CRsfwFileEntry& aFe) |
|
264 { |
|
265 // Construct the directory container based on |
|
266 // file table information |
|
267 DEBUGSTRING16(("Update directory container of %d (%S)", aFe.Fid().iNodeId, aFe.Name())); |
|
268 |
|
269 TDesC* cacheNamep = aFe.CacheFileName(); |
|
270 if (!cacheNamep) |
|
271 { |
|
272 // There was no prior cache. |
|
273 DEBUGSTRING(("Cache missing!")); |
|
274 User::Leave(KErrGeneral); |
|
275 } |
|
276 |
|
277 RFile f; |
|
278 CleanupClosePushL(f); |
|
279 User::LeaveIfError(f.Replace(iFs, |
|
280 *cacheNamep, |
|
281 EFileShareAny | EFileWrite)); |
|
282 RFileWriteStream fStream(f); |
|
283 CleanupClosePushL(fStream); |
|
284 |
|
285 RPointerArray<CRsfwFileEntry>* kidsp = aFe.Kids(); |
|
286 TInt i; |
|
287 if (!(iVolume->iVolumeTable->EnsureCacheCanBeAddedL( |
|
288 sizeof(TEntry) * kidsp->Count()))) |
|
289 { // pessimistic estimate |
|
290 User::Leave(KErrDiskFull); |
|
291 } |
|
292 for (i = 0; i < kidsp->Count(); i++) |
|
293 { |
|
294 CRsfwFileEntry* kidFep = (*kidsp)[i]; |
|
295 TDirEnt dirEnt; |
|
296 MakeDirectoryEntry(*kidFep, dirEnt); |
|
297 dirEnt.ExternalizeL(fStream); |
|
298 } |
|
299 CleanupStack::PopAndDestroy(2, &f); // f |
|
300 |
|
301 aFe.ResetLocallyDirty(); |
|
302 } |
|
303 |
|
304 // ---------------------------------------------------------------------------- |
|
305 // CRsfwFileEngine::DataChanged |
|
306 // ---------------------------------------------------------------------------- |
|
307 // |
|
308 TInt CRsfwFileEngine::DataChanged(const CRsfwDirEntAttr& aOldAttr, |
|
309 const CRsfwDirEntAttr& aNewAttr) |
|
310 { |
|
311 // Based on attributes or metadata in general, |
|
312 // tell whether the actual data, if cached, |
|
313 // should be updated |
|
314 if (aOldAttr.Att() == KEntryAttDir) |
|
315 { |
|
316 // use Last Modified (a weak entity tag) |
|
317 if (aOldAttr.Modified() == aNewAttr.Modified()) |
|
318 { |
|
319 return EFalse; |
|
320 } |
|
321 else |
|
322 { |
|
323 return ETrue; |
|
324 } |
|
325 } |
|
326 else |
|
327 { |
|
328 // use ETags if available |
|
329 // a strong entity tag |
|
330 if (aOldAttr.ETag() && aNewAttr.ETag()) |
|
331 { |
|
332 if (*aOldAttr.ETag() == *aNewAttr.ETag()) |
|
333 { |
|
334 return EFalse; |
|
335 } |
|
336 else |
|
337 { |
|
338 return ETrue; |
|
339 } |
|
340 } |
|
341 |
|
342 // use Last Modified (a weak entity tag) |
|
343 // we assume it's file and compare also iSize... |
|
344 if ((aOldAttr.Modified() == aNewAttr.Modified()) && |
|
345 (aOldAttr.Size() == aNewAttr.Size())) |
|
346 { |
|
347 return EFalse; |
|
348 } |
|
349 else |
|
350 { |
|
351 return ETrue; |
|
352 } |
|
353 } |
|
354 } |
|
355 |
|
356 // ---------------------------------------------------------------------------- |
|
357 // CRsfwFileEngine::UseCachedData |
|
358 // ---------------------------------------------------------------------------- |
|
359 // |
|
360 TBool CRsfwFileEngine::UseCachedData(CRsfwFileEntry& aFe) |
|
361 { |
|
362 if (!Disconnected()) |
|
363 { |
|
364 return aFe.UseCachedData(); |
|
365 } |
|
366 else |
|
367 { |
|
368 return ETrue; |
|
369 } |
|
370 } |
|
371 |
|
372 // ---------------------------------------------------------------------------- |
|
373 // CRsfwFileEngine::UseCachedAttributes |
|
374 // ---------------------------------------------------------------------------- |
|
375 // |
|
376 TBool CRsfwFileEngine::UseCachedAttributes(CRsfwFileEntry& aFe) |
|
377 { |
|
378 if (!Disconnected()) |
|
379 { |
|
380 if (aFe.Type() == KNodeTypeDir) |
|
381 { |
|
382 return iFileTable->Volume()->iVolumeTable-> |
|
383 IsCachedAttrStillValid(aFe.iAttribValidation); |
|
384 } |
|
385 else |
|
386 { // file |
|
387 return iFileTable->Volume()->iVolumeTable-> |
|
388 IsCachedDataStillValid(aFe.iAttribValidation); |
|
389 |
|
390 } |
|
391 } |
|
392 else |
|
393 { |
|
394 return ETrue; |
|
395 } |
|
396 } |
|
397 |
|
398 // ---------------------------------------------------------------------------- |
|
399 // CRsfwFileEngine::GetAttributesL |
|
400 // ---------------------------------------------------------------------------- |
|
401 // |
|
402 void CRsfwFileEngine::GetAttributesL(CRsfwFileEntry& aFe, |
|
403 CRsfwDirEntAttr*& aAttr, |
|
404 TUint aNodeType, |
|
405 CRsfwRfeStateMachine* aCaller) |
|
406 { |
|
407 // Gets attributes for File Entry aFe. |
|
408 // Uses either cached attributes (if they are still deemed to be valid), or |
|
409 // fetches the attributes from the server*/ |
|
410 DEBUGSTRING(("GetAttributesL")); |
|
411 if ((aFe.Type() == aNodeType) && UseCachedAttributes(aFe)) |
|
412 { |
|
413 // Nothing to do |
|
414 |
|
415 if (aFe.IsOpenedForWriting()) |
|
416 { |
|
417 // update attributes when we are writing to the file |
|
418 DEBUGSTRING(("volatile attributes")); |
|
419 SetupAttributes(aFe); |
|
420 } |
|
421 else |
|
422 { |
|
423 DEBUGSTRING(("using cached attributes")); |
|
424 } |
|
425 aCaller->HandleRemoteAccessResponse(0, KErrNone); // "file exists" |
|
426 } |
|
427 else |
|
428 { |
|
429 // Refresh attributes |
|
430 UpdateAttributesL(aFe, aAttr, aNodeType, aCaller); |
|
431 } |
|
432 } |
|
433 |
|
434 // ---------------------------------------------------------------------------- |
|
435 // CRsfwFileEngine::UpdateAttributesL |
|
436 // ---------------------------------------------------------------------------- |
|
437 // |
|
438 void CRsfwFileEngine::UpdateAttributesL(CRsfwFileEntry& aFe, |
|
439 CRsfwDirEntAttr*& aAttr, |
|
440 TUint aNodeType, |
|
441 MRsfwRemoteAccessResponseHandler* aCaller) |
|
442 { |
|
443 // UpdateAttributes doesn't attempt to use cached attributes |
|
444 HBufC* path = FullNameLC(aFe); |
|
445 TPtr p = path->Des(); |
|
446 DEBUGSTRING16(("UpdateAttributesL of '%S'", &p)); |
|
447 |
|
448 |
|
449 UpdateAttributesL(*path, aAttr, aNodeType, aCaller); |
|
450 |
|
451 CleanupStack::PopAndDestroy(path); // path |
|
452 } |
|
453 |
|
454 // ---------------------------------------------------------------------------- |
|
455 // CRsfwFileEngine::UpdateAttributesL |
|
456 // ---------------------------------------------------------------------------- |
|
457 // |
|
458 void CRsfwFileEngine::UpdateAttributesL(TDesC& aPath, |
|
459 TDesC& aName, |
|
460 CRsfwDirEntAttr*& aAttr, |
|
461 TUint aNodeType, |
|
462 MRsfwRemoteAccessResponseHandler* aCaller) |
|
463 { |
|
464 HBufC* pn = HBufC::NewLC(KMaxPath); |
|
465 TPtr pnPtr = pn->Des(); |
|
466 |
|
467 if (aPath.Length()) |
|
468 { |
|
469 pnPtr.Copy(aPath); |
|
470 pnPtr.Append('/'); |
|
471 } |
|
472 pnPtr.Append(aName); |
|
473 |
|
474 DEBUGSTRING16(("UpdateKidAttributes of '%S'", &pnPtr)); |
|
475 |
|
476 UpdateAttributesL(pnPtr, aAttr, aNodeType, aCaller); |
|
477 |
|
478 CleanupStack::PopAndDestroy(pn); |
|
479 } |
|
480 |
|
481 // ---------------------------------------------------------------------------- |
|
482 // CRsfwFileEngine::UpdateAttributesL |
|
483 // ---------------------------------------------------------------------------- |
|
484 // |
|
485 void CRsfwFileEngine::UpdateAttributesL(TDesC& aFullPath, |
|
486 CRsfwDirEntAttr*& aAttr, |
|
487 TUint aNodeType, |
|
488 MRsfwRemoteAccessResponseHandler* aCaller) |
|
489 { |
|
490 |
|
491 // If we have "recently" found out that this file/dir does NOT exist |
|
492 // we cache even this negative result. Time limit is cache expiry for |
|
493 // directory attributes |
|
494 if ((aFullPath.Length() > 0) && // do not compare root folder (always exists) |
|
495 (iLastFailedLookup == aFullPath) && |
|
496 (iFileTable->Volume()->iVolumeTable-> |
|
497 IsCachedAttrStillValid(iLookupTime))) |
|
498 { |
|
499 if (aNodeType == KNodeTypeDir) |
|
500 { |
|
501 aCaller->HandleRemoteAccessResponse(0, KErrPathNotFound); |
|
502 } |
|
503 else if (aNodeType == KNodeTypeFile) |
|
504 { |
|
505 aCaller->HandleRemoteAccessResponse(0, KErrNotFound); |
|
506 } |
|
507 return; |
|
508 |
|
509 } |
|
510 |
|
511 if (!Disconnected()) |
|
512 { |
|
513 if (aNodeType == KNodeTypeDir) |
|
514 { |
|
515 RemoteAccessL()->GetDirectoryAttributesL(aFullPath, aAttr, aCaller); |
|
516 } |
|
517 else if (aNodeType == KNodeTypeFile) |
|
518 { |
|
519 RemoteAccessL()->GetFileAttributesL(aFullPath, aAttr, aCaller); |
|
520 } |
|
521 } |
|
522 else |
|
523 { |
|
524 User::Leave(KErrNotFound); |
|
525 } |
|
526 |
|
527 } |
|
528 |
|
529 // ---------------------------------------------------------------------------- |
|
530 // CRsfwFileEngine::CreateContainerFileL |
|
531 // ---------------------------------------------------------------------------- |
|
532 // |
|
533 void CRsfwFileEngine::CreateContainerFileL(CRsfwFileEntry& aFe) |
|
534 { |
|
535 // Create a container file for the Fid. |
|
536 // If the cache file already exists, it will be deleted |
|
537 |
|
538 RFile f; |
|
539 HBufC* cachePath = HBufC::NewMaxLC(KMaxPath); |
|
540 TPtr pathPtr = cachePath->Des(); |
|
541 BuildContainerPathL(aFe, pathPtr); |
|
542 |
|
543 TInt err = f.Replace(iFs, *cachePath, EFileShareAny | EFileWrite); |
|
544 f.Close(); |
|
545 if (err != KErrNone) |
|
546 { |
|
547 DEBUGSTRING(("Error when creating container file! err=%d", err)); |
|
548 User::Leave(KErrGeneral); |
|
549 } |
|
550 aFe.SetCacheFileName(cachePath); |
|
551 CleanupStack::PopAndDestroy(cachePath); |
|
552 } |
|
553 |
|
554 // ---------------------------------------------------------------------------- |
|
555 // CRsfwFileEngine::FetchAndCacheL |
|
556 // ---------------------------------------------------------------------------- |
|
557 // |
|
558 TUint CRsfwFileEngine::FetchAndCacheL(CRsfwFileEntry& aFe, |
|
559 TInt aFirstByte, |
|
560 TInt* aLength, |
|
561 RPointerArray<CRsfwDirEnt>* aDirEntsp, |
|
562 CRsfwRfeStateMachine* aCaller) |
|
563 { |
|
564 // Fetch a file from the remote store and decrypt it if necessary. |
|
565 // The assumption is that the file has not yet been fetched |
|
566 // or has been cached up to the byte indicated by (aFe.iCachedSize - 1) |
|
567 // and filling the cache will continue linearly |
|
568 // i.e. aFirstByte = 0 || aFirstByte = aFe.iCachedSize |
|
569 // Access modules can fetch more than requested, so aLastByte might change. |
|
570 |
|
571 DEBUGSTRING(("Fetch fid %d, bytes %d - %d", |
|
572 aFe.Fid().iNodeId, |
|
573 aFirstByte, |
|
574 aFirstByte + *aLength)); |
|
575 |
|
576 TUint transactionId = 0; |
|
577 RFile f; |
|
578 HBufC* fullName = NULL; |
|
579 HBufC* cacheName = HBufC::NewMaxLC(KMaxPath); |
|
580 TPtr cachePtr = cacheName->Des(); |
|
581 TInt err; |
|
582 |
|
583 TInt usedCache = iVolume->iVolumeTable->TotalCachedSize(); |
|
584 |
|
585 // This much will be added to the cache by this fetch |
|
586 if (!iVolume->iVolumeTable->EnsureCacheCanBeAddedL(*aLength)) |
|
587 { |
|
588 User::Leave(KErrDiskFull); |
|
589 } |
|
590 |
|
591 if (!Disconnected()) |
|
592 { |
|
593 if (aFe.CacheFileName()) |
|
594 { |
|
595 // modify an existing cachefile ... |
|
596 cachePtr = *(aFe.CacheFileName()); |
|
597 |
|
598 if (aFe.Type() == KNodeTypeFile) |
|
599 { |
|
600 // If the cache file exists, |
|
601 // we will just continue filling it... |
|
602 err = f.Open(iFs, *cacheName, EFileShareAny | EFileWrite); |
|
603 if (err) |
|
604 { |
|
605 User::LeaveIfError(f.Replace(iFs, |
|
606 *cacheName, |
|
607 EFileShareAny | EFileWrite)); |
|
608 } |
|
609 } |
|
610 else |
|
611 { |
|
612 User::LeaveIfError(f.Replace(iFs, |
|
613 *cacheName, |
|
614 EFileShareAny | EFileWrite)); |
|
615 } |
|
616 } |
|
617 else |
|
618 { |
|
619 // create a new cache file |
|
620 CreateContainerFileL(aFe, cachePtr, f); |
|
621 } |
|
622 |
|
623 CleanupClosePushL(f); |
|
624 fullName = FullNameLC(aFe); |
|
625 if (aFe.Type() == KNodeTypeDir) |
|
626 { |
|
627 transactionId = GetDirectoryL(aFe, |
|
628 *fullName, |
|
629 f, |
|
630 aDirEntsp, |
|
631 aCaller); |
|
632 } |
|
633 else if (aFe.Type() == KNodeTypeFile) |
|
634 { |
|
635 f.Close(); |
|
636 transactionId = RemoteAccessL()->GetFileL(*fullName, |
|
637 *cacheName, |
|
638 aFirstByte, |
|
639 aLength, |
|
640 0, |
|
641 aCaller); |
|
642 } |
|
643 |
|
644 // fullName, f (duplicate close in the case of files) |
|
645 CleanupStack::PopAndDestroy(2, &f); |
|
646 } |
|
647 CleanupStack::PopAndDestroy(cacheName); |
|
648 return transactionId; |
|
649 } |
|
650 |
|
651 // ---------------------------------------------------------------------------- |
|
652 // CRsfwFileEngine::RequestConnectionStateL |
|
653 // ---------------------------------------------------------------------------- |
|
654 // |
|
655 TUint CRsfwFileEngine::RequestConnectionStateL(TUint aConnectionState, |
|
656 CRsfwRfeStateMachine* aCaller) |
|
657 { |
|
658 DEBUGSTRING16(("CRsfwFileEngine::RequestConnectionStateL %d", aConnectionState)); |
|
659 DEBUGSTRING16(("current connection state is %d", iConnectionState)); |
|
660 TUint transactionId = 0; |
|
661 if (aConnectionState != iConnectionState) |
|
662 { |
|
663 switch (aConnectionState) |
|
664 { |
|
665 case KMountNotConnected: |
|
666 DisconnectL(); |
|
667 break; |
|
668 case KMountStronglyConnected: |
|
669 transactionId = ConnectL(ETrue, aCaller); |
|
670 break; |
|
671 |
|
672 default: |
|
673 break; |
|
674 } |
|
675 } |
|
676 // else does not do anything (if iConnectionState == aConnectionState) |
|
677 return transactionId; |
|
678 } |
|
679 |
|
680 // ---------------------------------------------------------------------------- |
|
681 // CRsfwFileEngine::EnteredConnectionStateL |
|
682 // ---------------------------------------------------------------------------- |
|
683 // |
|
684 void CRsfwFileEngine::EnteredConnectionStateL(TUint aConnectionState, |
|
685 TBool aRequested) |
|
686 { |
|
687 DEBUGSTRING16(("CRsfwFileEngine::EnteredConnectionStateL %d", aConnectionState)); |
|
688 DEBUGSTRING16(("current connection state is %d", iConnectionState)); |
|
689 if (aConnectionState != iConnectionState) |
|
690 { |
|
691 iConnectionState = aConnectionState; |
|
692 iVolume->ConnectionStateChanged(iConnectionState); |
|
693 |
|
694 switch (aConnectionState) |
|
695 { |
|
696 case KMountNotConnected: |
|
697 if (!aRequested) |
|
698 { |
|
699 iRemoteAccess->Cancel(0); |
|
700 } |
|
701 break; |
|
702 |
|
703 case KMountStronglyConnected: |
|
704 if (aRequested) |
|
705 { |
|
706 if (iLockManager) |
|
707 { |
|
708 iLockManager->PopulateExternalLockTokenCacheL(iRootFep); |
|
709 } |
|
710 } |
|
711 break; |
|
712 |
|
713 default: |
|
714 break; |
|
715 } |
|
716 } |
|
717 } |
|
718 |
|
719 // ---------------------------------------------------------------------------- |
|
720 // CRsfwFileEngine::ConnectionState |
|
721 // ---------------------------------------------------------------------------- |
|
722 // |
|
723 TUint CRsfwFileEngine::ConnectionState() |
|
724 { |
|
725 return iConnectionState; |
|
726 } |
|
727 |
|
728 // ---------------------------------------------------------------------------- |
|
729 // CRsfwFileEngine::LockManager |
|
730 // ---------------------------------------------------------------------------- |
|
731 // |
|
732 CRsfwLockManager* CRsfwFileEngine::LockManager() |
|
733 { |
|
734 return iLockManager; |
|
735 } |
|
736 |
|
737 // ---------------------------------------------------------------------------- |
|
738 // CRsfwFileEngine::SetPermanenceL |
|
739 // ---------------------------------------------------------------------------- |
|
740 // |
|
741 void CRsfwFileEngine::SetPermanenceL(TBool aPermanence) |
|
742 { |
|
743 iFileTable->SetPermanenceL(aPermanence); |
|
744 } |
|
745 |
|
746 // ---------------------------------------------------------------------------- |
|
747 // CRsfwFileEngine::Disconnected |
|
748 // ---------------------------------------------------------------------------- |
|
749 // |
|
750 TBool CRsfwFileEngine::Disconnected() |
|
751 { |
|
752 return (iConnectionState == KMountNotConnected); |
|
753 } |
|
754 |
|
755 // ---------------------------------------------------------------------------- |
|
756 // CRsfwFileEngine::WriteDisconnected |
|
757 // ---------------------------------------------------------------------------- |
|
758 // |
|
759 TBool CRsfwFileEngine::WriteDisconnected() |
|
760 { |
|
761 // This also encompasses disconnected mode |
|
762 return (iConnectionState != KMountStronglyConnected); |
|
763 } |
|
764 |
|
765 // ---------------------------------------------------------------------------- |
|
766 // CRsfwFileEngine::AddToCacheL |
|
767 // ---------------------------------------------------------------------------- |
|
768 // |
|
769 TInt CRsfwFileEngine::AddToCacheL(CRsfwFileEntry& aFe, |
|
770 RPointerArray<CRsfwDirEnt>* aDirEnts, |
|
771 CRsfwFileEngine *aFileEngine, |
|
772 TUint cachedSize) |
|
773 { |
|
774 // returns the size of the cached data |
|
775 RFs fs = CRsfwRfeServer::Env()->iFs; |
|
776 TInt err; |
|
777 TInt kidsCount = 0; |
|
778 TInt containerSize = cachedSize; |
|
779 // holds true for files, will be overwritten for directories |
|
780 |
|
781 if (aFe.Type() == KNodeTypeDir) |
|
782 { |
|
783 // *********** originally from CRsfwFileEngine::GetDirectoryL() |
|
784 // ********************************************************** |
|
785 // Unmark and mark kids only when getdirectory returns KErrNone |
|
786 // otherwise (i.e. KErrUpdateNotRequired) let's just keep |
|
787 // the cached kids... |
|
788 aFe.UnmarkKids(); |
|
789 |
|
790 RApaLsSession lsSession; |
|
791 User::LeaveIfError(lsSession.Connect()); |
|
792 CleanupClosePushL(lsSession); |
|
793 |
|
794 RFileWriteStream fStream; |
|
795 // Dump to the local cache |
|
796 User::LeaveIfError( |
|
797 fStream.Open(fs, |
|
798 *(aFe.CacheFileName()), |
|
799 EFileWrite | EFileShareAny)); |
|
800 CleanupClosePushL(fStream); |
|
801 |
|
802 containerSize = fStream.Sink()->SizeL(); |
|
803 TInt i; |
|
804 TLex lex; |
|
805 for (i = 0; i < aDirEnts->Count(); i++) |
|
806 { |
|
807 CRsfwDirEnt* d = (*aDirEnts)[i]; |
|
808 TUid appUid; |
|
809 // For each TDirEnt we just read... |
|
810 // ... if the server returned content-type |
|
811 if (d->Attr()->MimeType() && d->Attr()->MimeType()->Length()) |
|
812 { |
|
813 err = lsSession.AppForDataType(*(d->Attr()->MimeType()), |
|
814 appUid); |
|
815 if (err == KErrNone) |
|
816 { |
|
817 d->Attr()->SetUid(appUid); |
|
818 } |
|
819 } |
|
820 |
|
821 d->Attr()->SetAttFlags(KEntryAttRemote); |
|
822 CRsfwFileEntry* kidFep = aFe.FindKidByName(*d->Name()); |
|
823 if (kidFep) |
|
824 { |
|
825 // We already know this kid |
|
826 // However we must check whether the kid has been modified |
|
827 CRsfwDirEntAttr* oldAttr = CRsfwDirEntAttr::NewLC(); |
|
828 kidFep->GetAttributesL(*oldAttr); |
|
829 if (DataChanged(*oldAttr, *d->Attr())) |
|
830 { |
|
831 kidFep->RemoveCacheFile(); |
|
832 } |
|
833 CleanupStack::PopAndDestroy(oldAttr); |
|
834 if (kidFep->IsFullyCached()) |
|
835 { |
|
836 // Mark the kid as cached |
|
837 d->Attr()->ResetAttFlags(KEntryAttRemote); |
|
838 } |
|
839 // as this entry is "used", move it to the back of metadata LRU list |
|
840 iVolume->iVolumeTable->MoveToTheBackOfMetadataLRUPriorityListL(kidFep); |
|
841 } |
|
842 |
|
843 // As a side effect, |
|
844 // insert this kid into the file table and |
|
845 // set its attributes |
|
846 if (!kidFep) |
|
847 { |
|
848 if (!iVolume->iVolumeTable->EnsureMetadataCanBeAddedL(&aFe)) |
|
849 { |
|
850 User::Leave(KErrNoMemory); |
|
851 } |
|
852 kidFep = CRsfwFileEntry::NewL(*d->Name(), &aFe); |
|
853 // Attach the new kid |
|
854 aFileEngine->iFileTable->AddL(kidFep); |
|
855 aFe.AddKid(*kidFep); |
|
856 } |
|
857 |
|
858 kidFep->Mark(); |
|
859 |
|
860 // set attributes if getting directory listing also supports getting file attributes |
|
861 if (DirectoryListingContainsFileMetadata()) |
|
862 { |
|
863 kidFep->SetAttributesL(*d->Attr(), ETrue); |
|
864 } |
|
865 else |
|
866 { |
|
867 kidFep->SetAttributesL(*d->Attr(), EFalse); |
|
868 } |
|
869 |
|
870 TDirEnt dirEnt; |
|
871 MakeDirectoryEntry(*kidFep, dirEnt); |
|
872 dirEnt.ExternalizeL(fStream); |
|
873 kidsCount++; |
|
874 } |
|
875 |
|
876 aFe.DropUnmarkedKidsL(); |
|
877 |
|
878 containerSize = fStream.Sink()->SizeL(); |
|
879 // assumes that this fetch will write the whole directory, |
|
880 |
|
881 // i.e. there is no partial fetching for the directories |
|
882 if(!iFileTable->Volume()->iVolumeTable-> |
|
883 EnsureCacheCanBeAddedL(containerSize)) |
|
884 { |
|
885 User::Leave(KErrDiskFull); |
|
886 } |
|
887 fStream.CommitL(); |
|
888 |
|
889 CleanupStack::PopAndDestroy(2, &lsSession); // fStream, lsSession |
|
890 |
|
891 // if the directory appeared to be childless add it to metadata LRU list |
|
892 if ( aDirEnts->Count() == 0 ) |
|
893 { |
|
894 iVolume->iVolumeTable->AddToMetadataLRUPriorityListL(&aFe, ECachePriorityNormal); |
|
895 } |
|
896 |
|
897 }// if directory |
|
898 |
|
899 // assumes the files are cached in continuos chunks, |
|
900 // i.e. always cached up to the last byte fetched |
|
901 aFe.SetCachedSize(containerSize); |
|
902 |
|
903 aFe.SetCached(ETrue); |
|
904 |
|
905 // We have to update locally dirty bit for the parent container |
|
906 if (aFe.Parent()) |
|
907 { |
|
908 aFe.Parent()->SetLocallyDirty(); |
|
909 } |
|
910 // But the object itself cannot be remotely dirty any more |
|
911 aFe.ResetRemotelyDirty(); |
|
912 |
|
913 // *** from CRsfwFileEngine::DoFetch *** |
|
914 if (aFe.Type() == KNodeTypeDir) |
|
915 { |
|
916 // the reason why kidsCount may be different than aFe.Kids.Count is that for big directories |
|
917 // some kids could have been removed when adding the others to memory. this is due to memory management cap. |
|
918 // however this should not happen so often |
|
919 aFe.KidsCount() == kidsCount ? aFe.iUseCachedData = ETrue : aFe.iUseCachedData = EFalse; |
|
920 } |
|
921 else |
|
922 { |
|
923 aFe.iUseCachedData = ETrue; |
|
924 } |
|
925 |
|
926 return containerSize; |
|
927 } |
|
928 |
|
929 // ---------------------------------------------------------------------------- |
|
930 // CRsfwFileEngine::RemoteAccessL |
|
931 // ---------------------------------------------------------------------------- |
|
932 // |
|
933 CRsfwRemoteAccess* CRsfwFileEngine::RemoteAccessL() |
|
934 { |
|
935 DEBUGSTRING(("CRsfwFileEngine::RemoteAccessL")); |
|
936 if (!iRemoteAccess) |
|
937 { |
|
938 User::Leave(KErrNotReady); |
|
939 } |
|
940 |
|
941 // Prevent the inactivity timer from triggering |
|
942 // in the middle of a remote access operation |
|
943 StopInactivityTimer(); |
|
944 |
|
945 return iRemoteAccess; |
|
946 } |
|
947 |
|
948 // ---------------------------------------------------------------------------- |
|
949 // CRsfwFileEngine::OperationCompleted |
|
950 // ---------------------------------------------------------------------------- |
|
951 // |
|
952 void CRsfwFileEngine::OperationCompleted() |
|
953 { |
|
954 DEBUGSTRING(("File engine operation completed")); |
|
955 if (iVolume->iVolumeTable->iPermanence) |
|
956 { |
|
957 iFileTable->SaveMetaDataDelta(); |
|
958 } |
|
959 |
|
960 if (iLockManager && (iLockManager->LockedCount() == 0)) |
|
961 { |
|
962 // Start timer only if we don't have files open for writing |
|
963 StartInactivityTimer(); |
|
964 } |
|
965 |
|
966 iVolume->OperationCompleted(); |
|
967 } |
|
968 |
|
969 // ---------------------------------------------------------------------------- |
|
970 // CRsfwFileEngine::CancelTransaction |
|
971 // ---------------------------------------------------------------------------- |
|
972 // |
|
973 void CRsfwFileEngine::CancelTransaction(TUint iTransactionId) |
|
974 { |
|
975 DEBUGSTRING(("CRsfwFileEngine::CancelTransactionL")); |
|
976 if (iRemoteAccess) |
|
977 { |
|
978 iRemoteAccess->Cancel(iTransactionId); |
|
979 } |
|
980 |
|
981 } |
|
982 |
|
983 // ---------------------------------------------------------------------------- |
|
984 // CRsfwFileEngine::CancelTransaction |
|
985 // ---------------------------------------------------------------------------- |
|
986 // |
|
987 void CRsfwFileEngine::CancelTransactionL(TDesC& aPathName) |
|
988 { |
|
989 DEBUGSTRING(("CRsfwFileEngine::CancelTransactionL")); |
|
990 TPtrC testPtr; |
|
991 testPtr.Set(aPathName.Right(aPathName.Length() - 3)); |
|
992 HBufC* cancelPath = HBufC::NewLC(KMaxPath); |
|
993 TPtr cancelPathPtr = cancelPath->Des(); |
|
994 // change '\\' to '/' so the path matches |
|
995 TLex parser(testPtr); |
|
996 TChar theChar; |
|
997 |
|
998 for (int i = 0; i < testPtr.Length(); i++) |
|
999 { |
|
1000 theChar = parser.Get(); |
|
1001 if (theChar == 0) |
|
1002 { |
|
1003 break; |
|
1004 } |
|
1005 // assumes that the input string always has "\\" and not just "\" |
|
1006 // this is true as the input is a file path |
|
1007 if (theChar != '\\') |
|
1008 { |
|
1009 cancelPathPtr.Append(theChar); |
|
1010 } |
|
1011 else |
|
1012 { |
|
1013 cancelPathPtr.Append('/'); |
|
1014 } |
|
1015 } |
|
1016 |
|
1017 if (iRemoteAccess) |
|
1018 { |
|
1019 iRemoteAccess->Cancel(*cancelPath); |
|
1020 } |
|
1021 |
|
1022 CleanupStack::PopAndDestroy(cancelPath); |
|
1023 |
|
1024 } |
|
1025 |
|
1026 |
|
1027 |
|
1028 |
|
1029 // ---------------------------------------------------------------------------- |
|
1030 // CRsfwFileEngine::SetFailedLookup |
|
1031 // Caches the last failed lookup result |
|
1032 // ---------------------------------------------------------------------------- |
|
1033 // |
|
1034 void CRsfwFileEngine::SetFailedLookup(TDesC& aPath, TDesC& aKidName) |
|
1035 { |
|
1036 iLastFailedLookup = aPath; |
|
1037 iLastFailedLookup.Append('/'); |
|
1038 iLastFailedLookup.Append(aKidName); |
|
1039 iLookupTime.HomeTime(); |
|
1040 DEBUGSTRING16(("SetFailedLookup: %S", &iLastFailedLookup)); |
|
1041 } |
|
1042 |
|
1043 // ---------------------------------------------------------------------------- |
|
1044 // CRsfwFileEngine::ResetFailedLookup |
|
1045 // Clears the last failed lookup result |
|
1046 // ---------------------------------------------------------------------------- |
|
1047 // |
|
1048 void CRsfwFileEngine::ResetFailedLookup() |
|
1049 { |
|
1050 DEBUGSTRING16(("ResetFailedLookup: %S", &iLastFailedLookup)); |
|
1051 iLastFailedLookup.Zero(); |
|
1052 } |
|
1053 |
|
1054 // ---------------------------------------------------------------------------- |
|
1055 // CRsfwFileEngine::Volume |
|
1056 // ---------------------------------------------------------------------------- |
|
1057 // |
|
1058 CRsfwVolume* CRsfwFileEngine::Volume() |
|
1059 { |
|
1060 return iVolume; |
|
1061 } |
|
1062 |
|
1063 // ---------------------------------------------------------------------------- |
|
1064 // CRsfwFileEngine::PrepareCacheL |
|
1065 // ---------------------------------------------------------------------------- |
|
1066 // |
|
1067 void CRsfwFileEngine::PrepareCacheL() |
|
1068 { |
|
1069 // make sure the file cache (of this volume) exists |
|
1070 iCacheRoot.Copy(CRsfwRfeServer::Env()->iCacheRoot); |
|
1071 iCacheRoot.Append('C'); |
|
1072 iCacheRoot.AppendNum(iVolume->iMountInfo.iMountStatus.iVolumeId); |
|
1073 iCacheRoot.Append('\\'); |
|
1074 |
|
1075 if (! BaflUtils::FileExists(iFs, iCacheRoot)) |
|
1076 { |
|
1077 // There was no prior cache directory |
|
1078 TInt err = iFs.MkDirAll(iCacheRoot); |
|
1079 DEBUGSTRING(("Cache directory created with err=%d", err)); |
|
1080 User::LeaveIfError(err); |
|
1081 } |
|
1082 } |
|
1083 |
|
1084 // ---------------------------------------------------------------------------- |
|
1085 // CRsfwFileEngine::GetDirectoryL |
|
1086 // ---------------------------------------------------------------------------- |
|
1087 // |
|
1088 TUint CRsfwFileEngine::GetDirectoryL(CRsfwFileEntry& /*aFe*/, |
|
1089 TDesC& aFullName, |
|
1090 RFile& /*aF*/, |
|
1091 RPointerArray<CRsfwDirEnt>* aDirEntsp, |
|
1092 MRsfwRemoteAccessResponseHandler* aCaller) |
|
1093 { |
|
1094 return RemoteAccessL()->GetDirectoryL(aFullName, *aDirEntsp, aCaller); |
|
1095 } |
|
1096 |
|
1097 // ---------------------------------------------------------------------------- |
|
1098 // CRsfwFileEngine::BuildContainerPathL |
|
1099 // ---------------------------------------------------------------------------- |
|
1100 // |
|
1101 void CRsfwFileEngine::BuildContainerPathL(CRsfwFileEntry& aFe, TDes& aPath) |
|
1102 { |
|
1103 if (aPath.MaxLength() < (aPath.Length() + iCacheRoot.Length())) |
|
1104 { |
|
1105 aPath.Copy(iCacheRoot); |
|
1106 } |
|
1107 else |
|
1108 { |
|
1109 User::Leave(KErrOverflow); |
|
1110 } |
|
1111 |
|
1112 ApplyMultiDirCacheL(aPath); |
|
1113 // This filename tagging based on container type is just for convenience |
|
1114 if (aFe.Type() == KNodeTypeFile) |
|
1115 { |
|
1116 aPath.Append('F'); |
|
1117 } |
|
1118 else |
|
1119 { |
|
1120 aPath.Append('D'); |
|
1121 } |
|
1122 aPath.AppendNum((TInt)aFe.Fid().iNodeId); |
|
1123 } |
|
1124 |
|
1125 // ---------------------------------------------------------------------------- |
|
1126 // CRsfwFileEngine::ApplyMultiDirCachePathL |
|
1127 // Due to Symbian performance problems with huge directories, items will not |
|
1128 // be stored in one directory in the cache. |
|
1129 // Now instead one dir like: |
|
1130 // C:\system\data\rsfw_cache\C16 |
|
1131 // there will be dirs like: |
|
1132 // C:\system\data\rsfw_cache\C16\M0 |
|
1133 // C:\system\data\rsfw_cache\C16\M1 |
|
1134 // ... and so on |
|
1135 // ---------------------------------------------------------------------------- |
|
1136 // |
|
1137 void CRsfwFileEngine::ApplyMultiDirCacheL(TDes& aPath) |
|
1138 { |
|
1139 // maximum number of items in a single dir in the cache |
|
1140 const TInt KRsfwMaxItemsInDir = 100; |
|
1141 TInt i; |
|
1142 // this loop will surely break (or leave) at some point |
|
1143 for ( i = 0; ; i++ ) |
|
1144 { |
|
1145 // create path like "C:\system\data\rsfw_cache\C16\M0" |
|
1146 HBufC* trypath = HBufC::NewMaxL(KMaxPath); |
|
1147 TPtr pathPtr = trypath->Des(); |
|
1148 pathPtr.Copy(aPath); |
|
1149 pathPtr.Append('M'); |
|
1150 pathPtr.AppendNum(i); |
|
1151 pathPtr.Append('\\'); |
|
1152 |
|
1153 // check whether dir exists and if so, how many items it contains |
|
1154 CDir* dir = NULL; |
|
1155 // note that KEntryAttDir att means files & directories |
|
1156 TInt err = iFs.GetDir(*trypath, KEntryAttDir, ESortNone, dir); |
|
1157 if ( err == KErrNone ) |
|
1158 { |
|
1159 // count the items |
|
1160 TInt count = dir->Count(); |
|
1161 delete dir; |
|
1162 dir = NULL; |
|
1163 |
|
1164 //limit is not exceeded -> return the path |
|
1165 if ( count < KRsfwMaxItemsInDir ) |
|
1166 { |
|
1167 aPath.Copy(pathPtr); |
|
1168 delete trypath; |
|
1169 break; |
|
1170 } |
|
1171 // limit exceeded -> let's try the next dir |
|
1172 else |
|
1173 { |
|
1174 delete trypath; |
|
1175 continue; |
|
1176 } |
|
1177 } |
|
1178 else if ( err == KErrPathNotFound ) |
|
1179 { |
|
1180 // create dir and return the path to empty dir |
|
1181 err = iFs.MkDir(*trypath); |
|
1182 if (!err) |
|
1183 { |
|
1184 aPath.Copy(pathPtr); |
|
1185 delete trypath; |
|
1186 } |
|
1187 else |
|
1188 { |
|
1189 delete trypath; |
|
1190 DEBUGSTRING(("Error when creating cache dir! err=%d", err)); |
|
1191 User::Leave(KErrGeneral); |
|
1192 } |
|
1193 |
|
1194 break; |
|
1195 } |
|
1196 else |
|
1197 { |
|
1198 delete trypath; |
|
1199 DEBUGSTRING(("Cache directory cannot be created! err=%d", err)); |
|
1200 User::Leave(KErrGeneral); |
|
1201 } |
|
1202 } |
|
1203 } |
|
1204 |
|
1205 // ---------------------------------------------------------------------------- |
|
1206 // CRsfwFileEngine::CreateContainerFileL |
|
1207 // ---------------------------------------------------------------------------- |
|
1208 // |
|
1209 void CRsfwFileEngine::CreateContainerFileL(CRsfwFileEntry& aFe, |
|
1210 TDes& aPath, |
|
1211 RFile& aF) |
|
1212 { |
|
1213 // Create a container file for the Fid. |
|
1214 // If the cache file already exists, it will be deleted |
|
1215 |
|
1216 BuildContainerPathL(aFe, aPath); |
|
1217 |
|
1218 TInt err = aF.Replace(iFs, aPath, EFileShareAny | EFileWrite); |
|
1219 if (err != KErrNone) |
|
1220 { |
|
1221 User::Leave(KErrGeneral); |
|
1222 } |
|
1223 aF.Close(); |
|
1224 |
|
1225 aFe.SetCacheFileName(&aPath); |
|
1226 } |
|
1227 |
|
1228 // ---------------------------------------------------------------------------- |
|
1229 // CRsfwFileEngine::DoIoctlL |
|
1230 // ---------------------------------------------------------------------------- |
|
1231 // |
|
1232 void CRsfwFileEngine::DoIoctlL(TRfeIoctlInArgs& aIn, TRfeOutArgs& /* aOut */) |
|
1233 { |
|
1234 TFid fidp = aIn.iFid; |
|
1235 TInt cmd = aIn.iCmd; |
|
1236 |
|
1237 TInt err = KErrNone; |
|
1238 |
|
1239 DEBUGSTRING(("ioctl fid %d - command=%d, data=%d", |
|
1240 fidp.iNodeId, |
|
1241 cmd, |
|
1242 aIn.iData32[0])); |
|
1243 |
|
1244 CRsfwFileEntry* fep = iFileTable->Lookup(fidp); |
|
1245 if (fep) |
|
1246 { |
|
1247 switch (cmd) |
|
1248 { |
|
1249 case ERemoteFsIoctlRefresh: |
|
1250 |
|
1251 |
|
1252 if (fep->Type() == KNodeTypeFile) |
|
1253 { |
|
1254 |
|
1255 fep->SetCacheFileName(NULL); |
|
1256 fep->SetCached(EFalse); |
|
1257 |
|
1258 // There is a change in the parent's container |
|
1259 fep->Parent()->SetLocallyDirty(); |
|
1260 } |
|
1261 break; |
|
1262 |
|
1263 case ERemoteFsHighCachePriority: |
|
1264 default: |
|
1265 err = KErrArgument; |
|
1266 break; |
|
1267 } |
|
1268 } |
|
1269 else |
|
1270 { |
|
1271 err = KErrNotFound; |
|
1272 } |
|
1273 |
|
1274 if (err != KErrNone) |
|
1275 { |
|
1276 User::Leave(err); |
|
1277 } |
|
1278 |
|
1279 return; |
|
1280 } |
|
1281 |
|
1282 // ---------------------------------------------------------------------------- |
|
1283 // CRsfwFileEngine::DoRootL |
|
1284 // ---------------------------------------------------------------------------- |
|
1285 // |
|
1286 void CRsfwFileEngine::DoRootL(TRfeRootInArgs& /* aIn */, TRfeRootOutArgs& aOut) |
|
1287 { |
|
1288 SetupRootL(iVolume->iVolumeTable->iPermanence); |
|
1289 aOut.iFid.iVolumeId = iRootFid->iVolumeId; |
|
1290 aOut.iFid.iNodeId = iRootFid->iNodeId; |
|
1291 return; |
|
1292 } |
|
1293 |
|
1294 // ---------------------------------------------------------------------------- |
|
1295 // CRsfwFileEngine::DoSetAttrL |
|
1296 // ---------------------------------------------------------------------------- |
|
1297 // |
|
1298 void CRsfwFileEngine::DoSetAttrL(TRfeSetAttrInArgs& aIn, TRfeOutArgs& /* aOut */) |
|
1299 // We cannot really set anything but this is the way to implement this |
|
1300 // note that if this is implemented, it should really be a state machine |
|
1301 { |
|
1302 TInt err = KErrNone; |
|
1303 TFid fidp = aIn.iFid; |
|
1304 #ifdef _DEBUG |
|
1305 TDirEntAttr* attrp = &(aIn.iAttr); |
|
1306 #endif |
|
1307 |
|
1308 DEBUGSTRING(("setting attributes of fid %d, attr=0x%x, size=%d, time=", |
|
1309 fidp.iNodeId, |
|
1310 attrp->iAtt, |
|
1311 attrp->iSize)); |
|
1312 DEBUGTIME((attrp->iModified)); |
|
1313 |
|
1314 // Get the file or directory to setattr |
|
1315 CRsfwFileEntry* fep = iFileTable->Lookup(fidp); |
|
1316 if (fep) |
|
1317 { |
|
1318 err = KErrNotSupported; |
|
1319 } |
|
1320 else |
|
1321 { |
|
1322 err = KErrNotFound; |
|
1323 } |
|
1324 |
|
1325 User::Leave(err); |
|
1326 return; |
|
1327 } |
|
1328 |
|
1329 // ---------------------------------------------------------------------------- |
|
1330 // CRsfwFileEngine::SetupRootL |
|
1331 // ---------------------------------------------------------------------------- |
|
1332 // |
|
1333 void CRsfwFileEngine::SetupRootL(TBool aPermanence) |
|
1334 { |
|
1335 _LIT(KRootPath, "."); // dummy |
|
1336 |
|
1337 if (!iRootFid) |
|
1338 { |
|
1339 CRsfwFileEntry* root = NULL; |
|
1340 TInt err; |
|
1341 if (aPermanence) |
|
1342 { |
|
1343 TRAP(err, root = iFileTable->LoadMetaDataL()); |
|
1344 } |
|
1345 if (err == KErrCorrupt) |
|
1346 { |
|
1347 DEBUGSTRING(("Metadata corrupted! Recreating cache file...")); |
|
1348 // corrupted cache file, recreate filetable and cache file |
|
1349 delete iFileTable; |
|
1350 iFileTable = NULL; |
|
1351 CleanupCorruptedCacheL(); |
|
1352 PrepareCacheL(); |
|
1353 iFileTable = CRsfwFileTable::NewL(iVolume, iCacheRoot); |
|
1354 } |
|
1355 if (!aPermanence || (err != KErrNone)) |
|
1356 { |
|
1357 root = CRsfwFileEntry::NewL(KRootPath, NULL); |
|
1358 // Insert root into the file table |
|
1359 iFileTable->AddL(root); |
|
1360 root->SetType(KNodeTypeDir); |
|
1361 } |
|
1362 if (aPermanence) |
|
1363 { |
|
1364 iFileTable->SaveMetaDataDelta(); |
|
1365 } |
|
1366 iRootFep = root; |
|
1367 iRootFid = &(root->Fid()); |
|
1368 } |
|
1369 } |
|
1370 |
|
1371 // ---------------------------------------------------------------------------- |
|
1372 // CRsfwFileEngine::CleanupCorruptedCacheL |
|
1373 // ---------------------------------------------------------------------------- |
|
1374 // |
|
1375 void CRsfwFileEngine::CleanupCorruptedCacheL() |
|
1376 { |
|
1377 // delete everything from the cache |
|
1378 TFileName cachepath; |
|
1379 cachepath.Copy(iCacheRoot); |
|
1380 CFileMan* fileMan = CFileMan::NewL(iFs); |
|
1381 fileMan->Delete(cachepath, CFileMan::ERecurse); |
|
1382 delete fileMan; |
|
1383 } |
|
1384 |
|
1385 // ---------------------------------------------------------------------------- |
|
1386 // CRsfwFileEngine::ConnectL |
|
1387 // ---------------------------------------------------------------------------- |
|
1388 // |
|
1389 TUint CRsfwFileEngine::ConnectL(TBool aRestart, CRsfwRfeStateMachine* aCaller) |
|
1390 { |
|
1391 // Assume parameter format: |
|
1392 // protocol://username:password@server:port/rootdir or |
|
1393 // The ":password", ":port", and "[/]rootdir" can be omitted. |
|
1394 // If the length of password parameter is bigger than 1, |
|
1395 // it overrides the one in uri, if any. |
|
1396 // Characters can be quoted with %<hexdigit><hexdigit> format |
|
1397 TUint transactionId = 0; |
|
1398 |
|
1399 if (iRemoteAccess) |
|
1400 { |
|
1401 // We already have a remote accessor |
|
1402 if (aRestart) |
|
1403 { |
|
1404 // Restarting |
|
1405 delete iLockManager; |
|
1406 iLockManager = NULL; |
|
1407 delete iRemoteAccess; |
|
1408 iRemoteAccess = NULL; |
|
1409 } |
|
1410 else |
|
1411 { |
|
1412 User::Leave(KErrAlreadyExists); |
|
1413 } |
|
1414 } |
|
1415 |
|
1416 DEBUGSTRING16(("ConnectL(): '%S'", |
|
1417 &iVolume->iMountInfo.iMountConfig.iUri)); |
|
1418 |
|
1419 TUriParser uriParser; |
|
1420 User::LeaveIfError(uriParser.Parse(iVolume->iMountInfo.iMountConfig.iUri)); |
|
1421 |
|
1422 TPtrC userName; |
|
1423 TPtrC password; |
|
1424 TPtrC friendlyName; |
|
1425 |
|
1426 if (uriParser.IsPresent(EUriUserinfo)) |
|
1427 { |
|
1428 TPtrC userInfo(uriParser.Extract(EUriUserinfo)); |
|
1429 // Split the user info into user name and password (seprated by ':') |
|
1430 TInt pos = userInfo.Locate(':'); |
|
1431 if (pos != KErrNotFound) |
|
1432 { |
|
1433 password.Set(userInfo.Mid(pos + 1)); |
|
1434 userName.Set(userInfo.Left(pos)); |
|
1435 } |
|
1436 else |
|
1437 { |
|
1438 userName.Set(userInfo); |
|
1439 } |
|
1440 } |
|
1441 |
|
1442 HBufC* userNameBuf = NULL; |
|
1443 if (!userName.Length() && |
|
1444 iVolume->iMountInfo.iMountConfig.iUserName.Length()) |
|
1445 { |
|
1446 // separate user name overwrites the username embedded in the URI |
|
1447 userName.Set(iVolume->iMountInfo.iMountConfig.iUserName); |
|
1448 } |
|
1449 |
|
1450 HBufC* passwordBuf = NULL; |
|
1451 if (!password.Length() && |
|
1452 (iVolume->iMountInfo.iMountConfig.iPassword.Length() > 1)) |
|
1453 { |
|
1454 // separate password overwrites the password embedded in the URI |
|
1455 password.Set(iVolume->iMountInfo.iMountConfig.iPassword); |
|
1456 } |
|
1457 |
|
1458 friendlyName.Set(iVolume->iMountInfo.iMountConfig.iName); |
|
1459 |
|
1460 TPtrC scheme(uriParser.Extract(EUriScheme)); |
|
1461 HBufC8* protocol = HBufC8::NewLC(scheme.Length()); |
|
1462 TPtr8 protocolPtr = protocol->Des(); |
|
1463 protocolPtr.Copy(scheme); |
|
1464 iRemoteAccess = CRsfwRemoteAccess::NewL(protocolPtr); |
|
1465 CleanupStack::PopAndDestroy(protocol); |
|
1466 |
|
1467 // user name and password are conveyed separately from the URI |
|
1468 CUri* uri = CUri::NewLC(uriParser); |
|
1469 uri->RemoveComponentL(EUriUserinfo); |
|
1470 |
|
1471 // leaves if error |
|
1472 iRemoteAccess->SetupL(this); |
|
1473 transactionId = iRemoteAccess-> |
|
1474 OpenL(uri->Uri(), |
|
1475 friendlyName, |
|
1476 userName, |
|
1477 password, |
|
1478 iVolume->iMountInfo.iMountConfig.iAuxData, |
|
1479 aCaller); |
|
1480 |
|
1481 CleanupStack::PopAndDestroy(uri); |
|
1482 if (passwordBuf) |
|
1483 { |
|
1484 CleanupStack::PopAndDestroy(passwordBuf); |
|
1485 } |
|
1486 if (userNameBuf) |
|
1487 { |
|
1488 CleanupStack::PopAndDestroy(userNameBuf); |
|
1489 } |
|
1490 |
|
1491 // lock manager can be created before we know whether connecting was |
|
1492 // succesful - however it must be deleted upon unsuccesful connect |
|
1493 if (!iLockManager) |
|
1494 { |
|
1495 iLockManager = CRsfwLockManager::NewL(iRemoteAccess); |
|
1496 } |
|
1497 |
|
1498 if ((iInactivityTimeout > 0) && !iInactivityTimer) |
|
1499 { |
|
1500 iInactivityTimer = CPeriodic::NewL(CActive::EPriorityLow); |
|
1501 } |
|
1502 return transactionId; |
|
1503 } |
|
1504 |
|
1505 // ---------------------------------------------------------------------------- |
|
1506 // CRsfwFileEngine::DisconnectL |
|
1507 // ---------------------------------------------------------------------------- |
|
1508 // |
|
1509 void CRsfwFileEngine::DisconnectL() |
|
1510 { |
|
1511 DEBUGSTRING(("CRsfwFileEngine::DisconnectL")); |
|
1512 if (iRemoteAccess) |
|
1513 { |
|
1514 iRemoteAccess->Cancel(0); |
|
1515 delete iRemoteAccess; |
|
1516 iRemoteAccess = NULL; |
|
1517 } |
|
1518 |
|
1519 if (iLockManager) |
|
1520 { |
|
1521 delete iLockManager; |
|
1522 iLockManager = NULL; |
|
1523 } |
|
1524 |
|
1525 |
|
1526 // Set open file count to zero |
|
1527 // If there are open files, after disconnecting we do not necessarily |
|
1528 // get close events. |
|
1529 // Note that this variable is not "dirty bit" (file has currently |
|
1530 // uncommitted modifications), so it is safe to set it to zero |
|
1531 TInt openfiles = iFileTable->OpenFileCount(); |
|
1532 iFileTable->UpdateOpenFileCount(-openfiles); |
|
1533 |
|
1534 EnteredConnectionStateL(KMountNotConnected, ETrue); |
|
1535 |
|
1536 // publish connection status when disconnecting |
|
1537 iVolume->iVolumeTable->PublishConnectionStatus(iVolume); |
|
1538 |
|
1539 } |
|
1540 |
|
1541 // ---------------------------------------------------------------------------- |
|
1542 // CRsfwFileEngine::StartInactivityTimer |
|
1543 // ---------------------------------------------------------------------------- |
|
1544 // |
|
1545 void CRsfwFileEngine::StartInactivityTimer() |
|
1546 { |
|
1547 if (iInactivityTimer) |
|
1548 { |
|
1549 DEBUGSTRING(("inactivity timer started (%d us)", |
|
1550 iInactivityTimeout)); |
|
1551 iInactivityTimer->Cancel(); |
|
1552 TCallBack callBack(CRsfwFileEngine::InactivityTimerExpired, this); |
|
1553 iInactivityTimer->Start(iInactivityTimeout, |
|
1554 iInactivityTimeout, |
|
1555 callBack); |
|
1556 } |
|
1557 } |
|
1558 |
|
1559 // ---------------------------------------------------------------------------- |
|
1560 // CRsfwFileEngine::StopInactivityTimer |
|
1561 // ---------------------------------------------------------------------------- |
|
1562 // |
|
1563 void CRsfwFileEngine::StopInactivityTimer() |
|
1564 { |
|
1565 DEBUGSTRING(("CRsfwFileEngine::StopInactivityTimer")); |
|
1566 if (iInactivityTimer) |
|
1567 { |
|
1568 DEBUGSTRING(("inactivity timer stopped")); |
|
1569 iInactivityTimer->Cancel(); |
|
1570 } |
|
1571 } |
|
1572 |
|
1573 // ---------------------------------------------------------------------------- |
|
1574 // CRsfwFileEngine::InactivityTimerExpired |
|
1575 // ---------------------------------------------------------------------------- |
|
1576 // |
|
1577 TInt CRsfwFileEngine::InactivityTimerExpired(TAny* aArg) |
|
1578 { |
|
1579 DEBUGSTRING(("CRsfwFileEngine::InactivityTimerExpired")); |
|
1580 CRsfwFileEngine* fileEngine = static_cast<CRsfwFileEngine*>(aArg); |
|
1581 if (fileEngine->iFileTable->OpenFileCount() == 0) |
|
1582 { |
|
1583 fileEngine->StopInactivityTimer(); |
|
1584 TRAP_IGNORE(fileEngine->DisconnectL()); |
|
1585 // "Simulate" operation completion (which may result in RFE shutdown) |
|
1586 fileEngine->OperationCompleted(); |
|
1587 } |
|
1588 else |
|
1589 { |
|
1590 // if there are open files on this volume, just restart the inactivity timer |
|
1591 fileEngine->StartInactivityTimer(); |
|
1592 } |
|
1593 |
|
1594 return 0; |
|
1595 } |
|
1596 |
|
1597 // ---------------------------------------------------------------------------- |
|
1598 // CRsfwFileEngine::HandleRemoteAccessEventL |
|
1599 // ---------------------------------------------------------------------------- |
|
1600 // |
|
1601 void CRsfwFileEngine::HandleRemoteAccessEventL(TInt aEventType, |
|
1602 TInt aEvent, |
|
1603 TAny* /* aArg */) |
|
1604 { |
|
1605 DEBUGSTRING(("Handle remote access event: %d/%d in connection state %d", |
|
1606 aEventType, |
|
1607 aEvent, |
|
1608 iConnectionState)); |
|
1609 switch (aEventType) |
|
1610 { |
|
1611 case ERsfwRemoteAccessObserverEventConnection: |
|
1612 switch (aEvent) |
|
1613 { |
|
1614 case ERsfwRemoteAccessObserverEventConnectionDisconnected: |
|
1615 EnteredConnectionStateL(KMountNotConnected, EFalse); |
|
1616 break; |
|
1617 |
|
1618 case ERsfwRemoteAccessObserverEventConnectionWeaklyConnected: |
|
1619 #if 0 |
|
1620 // This event does not appear |
|
1621 EnteredConnectionStateL(KMountWeaklyConnected, EFalse); |
|
1622 #endif |
|
1623 break; |
|
1624 |
|
1625 case ERsfwRemoteAccessObserverEventConnectionStronglyConnected: |
|
1626 #if 0 |
|
1627 // This event does not appear |
|
1628 EnteredConnectionStateL(KMountStronglyConnected, EFalse); |
|
1629 #endif |
|
1630 break; |
|
1631 |
|
1632 default: |
|
1633 break; |
|
1634 } |
|
1635 break; |
|
1636 |
|
1637 default: |
|
1638 break; |
|
1639 } |
|
1640 } |
|
1641 |
|
1642 // ---------------------------------------------------------------------------- |
|
1643 // CRsfwFileEngine::PurgeFromCacheL |
|
1644 // ---------------------------------------------------------------------------- |
|
1645 // |
|
1646 TInt CRsfwFileEngine::PurgeFromCache(const TDesC& aPath) |
|
1647 { |
|
1648 // get the fid of the entry for which the cached data is removed |
|
1649 CRsfwFileEntry* targetFid = FetchFep(aPath); |
|
1650 if (!targetFid) |
|
1651 { |
|
1652 return KErrPathNotFound; |
|
1653 } |
|
1654 // only directories can be refreshed currently |
|
1655 if (targetFid->Type() != KNodeTypeDir) |
|
1656 { |
|
1657 return KErrArgument; |
|
1658 } |
|
1659 targetFid->SetCached(EFalse); |
|
1660 return KErrNone; |
|
1661 } |
|
1662 |
|
1663 CRsfwFileEntry* CRsfwFileEngine::FetchFep(const TDesC& aPath) |
|
1664 { |
|
1665 DEBUGSTRING16(("CRsfwFileEngine::FetchFep for file %S", &aPath)); |
|
1666 if (aPath.Length() <= 1) |
|
1667 { |
|
1668 DEBUGSTRING(("returning rootFep")); |
|
1669 return iRootFep; |
|
1670 } |
|
1671 else |
|
1672 { |
|
1673 TInt delimiterPos = aPath.LocateReverse(KPathDelimiter); |
|
1674 if (delimiterPos == (aPath.Length() - 1)) |
|
1675 { |
|
1676 // The path ends with a slash, |
|
1677 //i.e. this is a directory - continue parsing |
|
1678 TPtrC nextdelimiter; |
|
1679 nextdelimiter.Set(aPath.Left(delimiterPos)); |
|
1680 delimiterPos = nextdelimiter.LocateReverse(KPathDelimiter); |
|
1681 } |
|
1682 TPtrC entry(aPath.Right(aPath.Length() - (delimiterPos + 1))); |
|
1683 TPtrC path(aPath.Left(delimiterPos + 1)); |
|
1684 |
|
1685 // strip a trailing backslash if found |
|
1686 delimiterPos = entry.LocateReverse(KPathDelimiter); |
|
1687 if (delimiterPos == (entry.Length() - 1)) |
|
1688 { |
|
1689 TPtrC stripped(entry.Left(entry.Length() - 1)); |
|
1690 return (FetchFep(path)->FindKidByName(stripped)); |
|
1691 } |
|
1692 else |
|
1693 { |
|
1694 return (FetchFep(path)->FindKidByName(entry)); |
|
1695 } |
|
1696 |
|
1697 } |
|
1698 |
|
1699 } |
|
1700 |
|
1701 HBufC8* CRsfwFileEngine::GetContentType(TDesC& aName) |
|
1702 { |
|
1703 TInt err; |
|
1704 RApaLsSession lsSession; |
|
1705 err = lsSession.Connect(); |
|
1706 if (err) |
|
1707 { |
|
1708 return NULL; |
|
1709 } |
|
1710 |
|
1711 RFs fsSession; |
|
1712 err = fsSession.Connect(); |
|
1713 if (err) |
|
1714 { |
|
1715 lsSession.Close(); |
|
1716 return NULL; |
|
1717 } |
|
1718 fsSession.ShareProtected(); |
|
1719 TDataRecognitionResult dataType; |
|
1720 RFile theFile; |
|
1721 // the mode must mach the mode that is used in the file system plugin |
|
1722 // (EFileWrite|EFileShareAny) |
|
1723 err = theFile.Open(fsSession, aName, EFileWrite|EFileShareAny); |
|
1724 if (err) |
|
1725 { |
|
1726 lsSession.Close(); |
|
1727 fsSession.Close(); |
|
1728 return NULL; |
|
1729 } |
|
1730 err = lsSession.RecognizeData(theFile, dataType); |
|
1731 lsSession.Close(); |
|
1732 theFile.Close(); |
|
1733 fsSession.Close(); |
|
1734 if (err) |
|
1735 { |
|
1736 return NULL; |
|
1737 } |
|
1738 |
|
1739 return dataType.iDataType.Des8().Alloc(); |
|
1740 } |
|
1741 |
|
1742 // The purpose of these functions is to give capability info |
|
1743 // for the access protocol plugin used. |
|
1744 |
|
1745 // Currently this information is hard coded and takes into account webdav and upnp |
|
1746 // access modules. New function should be added to the access plugin api to get |
|
1747 // this information from the protocol module |
|
1748 |
|
1749 // whether getting the directory listing also gives reliable file metadata |
|
1750 TBool CRsfwFileEngine::DirectoryListingContainsFileMetadata() |
|
1751 { |
|
1752 _LIT(KUPnP, "upnp"); |
|
1753 if (iVolume->MountInfo()->iMountConfig.iUri.Left(4) == KUPnP) |
|
1754 { |
|
1755 return EFalse; |
|
1756 } |
|
1757 else |
|
1758 { |
|
1759 return ETrue; |
|
1760 } |
|
1761 |
|
1762 } |
|
1763 |
|