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: File server interface class representing an open file. |
|
15 * Allows to access a specific remote file. |
|
16 * |
|
17 */ |
|
18 |
|
19 |
|
20 // INCLUDE FILES |
|
21 #include "rsfwfsfilecb.h" |
|
22 #include "rsfwfsmountcb.h" |
|
23 |
|
24 // ----------------------------------------------------------------------------- |
|
25 // CRsfwFsFileCB::CRsfwFsFileCB |
|
26 // C++ default constructor can NOT contain any code, that |
|
27 // might leave. |
|
28 // ----------------------------------------------------------------------------- |
|
29 // |
|
30 CRsfwFsFileCB::CRsfwFsFileCB() |
|
31 { |
|
32 iLastFlushFailed = ETrue; |
|
33 iPartialWriteSupported = ETrue; |
|
34 } |
|
35 |
|
36 // Destructor |
|
37 CRsfwFsFileCB::~CRsfwFsFileCB() |
|
38 { |
|
39 // close the cache file first so that RFE can move/delete it if upload fails |
|
40 iContFile.Close(); |
|
41 TUint flags = 0; |
|
42 if (iFileName) |
|
43 { |
|
44 if (!iLastFlushFailed) |
|
45 { |
|
46 // Now the container file has been changed, |
|
47 // tell Remote File Engine to update it on the servers |
|
48 // RSessionL() should not leave here as the remote session surely is created by now... |
|
49 if (iAtt & KEntryAttModified) |
|
50 { |
|
51 flags |= ECloseModified; |
|
52 |
|
53 // File was modified use, flush to write data to the server |
|
54 // We write the whole file always, if flush was never called we cannot |
|
55 // know whether partial write is supported. |
|
56 TRAP_IGNORE(static_cast<CRsfwFsMountCB&> |
|
57 (Mount()).RSessionL()->Flush(iThisFid, 0, iCachedSize, iCachedSize)); |
|
58 } |
|
59 else |
|
60 { |
|
61 flags |= ECloseNotModified; |
|
62 } |
|
63 |
|
64 } |
|
65 else |
|
66 { |
|
67 // flush was called and failed |
|
68 // do not try to flush again if the application closes the file |
|
69 // instead indicate this to the close state machine |
|
70 flags |= ECloseLastFlushFailed; |
|
71 } |
|
72 } |
|
73 |
|
74 // close will release the write lock if possible |
|
75 // and also allows user to save the file locally if flush failed |
|
76 TRAP_IGNORE(static_cast<CRsfwFsMountCB&> |
|
77 (Mount()).RSessionL()->CloseFile(iThisFid, flags)); |
|
78 |
|
79 } |
|
80 |
|
81 |
|
82 // ----------------------------------------------------------------------------- |
|
83 // CRsfwFsFileCB::RenameL |
|
84 // Renames the file with the full file name provided. Because the full name of |
|
85 // the file includes the path, the function can also be used to move the file. |
|
86 // |
|
87 // It can be assumed that no other sub-session has access to the file: |
|
88 // i.e. the file has not been opened in EFileShareAny share mode. |
|
89 // It can also be assumed that the file has been opened for writing. |
|
90 // ----------------------------------------------------------------------------- |
|
91 // |
|
92 void CRsfwFsFileCB::RenameL( |
|
93 const TDesC& aNewName) |
|
94 { |
|
95 static_cast<CRsfwFsMountCB&>(Mount()).RenameFidL(iParentFid, *iFileName, aNewName); |
|
96 delete iFileName; |
|
97 iFileName = NULL; |
|
98 iFileName = aNewName.AllocL(); |
|
99 } |
|
100 |
|
101 // ----------------------------------------------------------------------------- |
|
102 // CRsfwFsFileCB::ReadL |
|
103 // Reads a specified number of bytes from the open file starting at |
|
104 // the specified position, and writes the result into a descriptor. |
|
105 // |
|
106 // It can be assumed that aPos is inside the file and aLength > 0. |
|
107 // The file should only be read up to its end regardless of |
|
108 // the value of aPos + aLength. The number of bytes read should be stored |
|
109 // in aLength on return. |
|
110 // |
|
111 // Implemented by sending FETCH request to Remote File Engine for the |
|
112 // specified data and subsequently reading the data from the local cache file. |
|
113 // Reading the local cache file sets aLength. |
|
114 // Note that we want to keept the cache file continuos. If the requested data |
|
115 // starts behind the end of the current cache file, the function sends FETCHDATA |
|
116 // and Remote File Engine puts this data into a temp cache file valid only |
|
117 // for the duration of this operation if the caching mode is something else than |
|
118 // Whole File Caching |
|
119 // (other items were commented in a header). |
|
120 // ----------------------------------------------------------------------------- |
|
121 // |
|
122 void CRsfwFsFileCB::ReadL( |
|
123 TInt aPos, |
|
124 TInt& aLength, |
|
125 const TAny* /*aDes*/, |
|
126 const RMessagePtr2& aMessage) |
|
127 |
|
128 { |
|
129 |
|
130 if (iCachedSize == 0) |
|
131 { |
|
132 // iCachedSize possibly not up-to-date... |
|
133 iContFile.Size(iCachedSize); |
|
134 } |
|
135 |
|
136 HBufC8* data = HBufC8::NewMaxLC(aLength); |
|
137 TPtr8 buf(data->Des()); |
|
138 |
|
139 if (aPos > iCachedSize) |
|
140 { |
|
141 // Depending on the caching mode this type of request may bypass the |
|
142 // normal cache file. |
|
143 TBool useTempCache = EFalse; |
|
144 HBufC* tmpCacheFile = HBufC::NewLC(KMaxPath); |
|
145 TPtr tmpCache(tmpCacheFile->Des()); |
|
146 User::LeaveIfError(static_cast<CRsfwFsMountCB&> |
|
147 (Mount()).RSessionL()->FetchData(iThisFid, |
|
148 aPos, |
|
149 aPos + aLength - 1, |
|
150 tmpCache, |
|
151 useTempCache)); |
|
152 if (useTempCache) |
|
153 { |
|
154 // use "temp" in the same directory instead of the cache file |
|
155 RFile tempFile; |
|
156 TParse parser; |
|
157 parser.Set(tmpCache, NULL, NULL); |
|
158 HBufC* tempPath = HBufC::NewLC(KMaxPath); |
|
159 TPtr tempptr = tempPath->Des(); |
|
160 tempptr.Append(parser.DriveAndPath()); |
|
161 tempptr.Append(KTempFileName); |
|
162 User::LeaveIfError(tempFile.Open(*(RFs* )Dll::Tls(), |
|
163 tempptr, EFileRead)); |
|
164 CleanupStack::PopAndDestroy(tempPath); |
|
165 CleanupClosePushL(tempFile); |
|
166 User::LeaveIfError(tempFile.Read(buf, aLength)); |
|
167 CleanupStack::PopAndDestroy(&tempFile); |
|
168 } |
|
169 else |
|
170 { |
|
171 // read from the normal container file (Whole File Caching mode). |
|
172 iContFile.Size(iCachedSize); |
|
173 User::LeaveIfError(iContFile.Read(aPos, buf, aLength)); |
|
174 } |
|
175 CleanupStack::PopAndDestroy(tmpCacheFile); // tempcacheFile |
|
176 } |
|
177 else if ((aPos + aLength) > iCachedSize) |
|
178 { |
|
179 User::LeaveIfError(static_cast<CRsfwFsMountCB&> |
|
180 (Mount()).RSessionL()->Fetch(iThisFid, |
|
181 aPos, |
|
182 aPos + aLength - 1, |
|
183 iCachedSize)); |
|
184 |
|
185 User::LeaveIfError(iContFile.Read(aPos, buf, aLength)); |
|
186 } |
|
187 else |
|
188 { |
|
189 User::LeaveIfError(iContFile.Read(aPos, buf, aLength)); |
|
190 } |
|
191 |
|
192 aMessage.WriteL(0, buf, 0); |
|
193 CleanupStack::PopAndDestroy(data); |
|
194 if (iCachedSize == iSize) |
|
195 { |
|
196 // clear the remote attribute if the whole file has now been fetched |
|
197 iAtt &= ~KEntryAttRemote; |
|
198 } |
|
199 } |
|
200 |
|
201 // ----------------------------------------------------------------------------- |
|
202 // CRsfwFsFileCB::WriteL |
|
203 // Writes data to the open file. iModified and iSize are set by the file server |
|
204 // after this function has completed successfully. |
|
205 // |
|
206 // It can be assumed that aPos is within the file range and aLength > 0. |
|
207 // When aPos + aLength is greater than the file size then the file should |
|
208 // be enlarged using SetSizeL(). The number of bytes written should be |
|
209 // returned through the argument aLength. |
|
210 // |
|
211 // Implemented by writing to the local cache file. First requests Remote File |
|
212 // Engine whether there is enough space in the cache to write the file (this |
|
213 // also calls SysUtil::DiskSpaceBelowCritical()). FE attempts to free space |
|
214 // from the cache if necessary Implementation notice: writes a large file in |
|
215 // chunks of 64K. |
|
216 // |
|
217 // (other items were commented in a header). |
|
218 // ----------------------------------------------------------------------------- |
|
219 // |
|
220 void CRsfwFsFileCB::WriteL( |
|
221 TInt aPos, |
|
222 TInt& aLength, |
|
223 const TAny* /*aDes*/, |
|
224 const RMessagePtr2& aMessage) |
|
225 { |
|
226 |
|
227 if (iCachedSize == 0) |
|
228 { |
|
229 // iCachedSize possibly not up-to-date... |
|
230 iContFile.Size(iCachedSize); |
|
231 } |
|
232 |
|
233 // if flush was cancelled, but we come again to write, again set iLastFlushFailed to EFalse |
|
234 iLastFlushFailed = EFalse; |
|
235 |
|
236 // We must first fetch the file to the local cache |
|
237 // unless aPos = 0 and aLength => iSize |
|
238 // Note that if files are written to they cannot be partially cached |
|
239 // as the whole file will be sent to the server and overwrites the old file. |
|
240 // That is why we must ensure that the whole file is cached as soon as we |
|
241 // get the first write. |
|
242 // in subsequent writes iCachedSize will equal iSize |
|
243 // This may eventually change if we start to use some kind of "delta-PUT". |
|
244 if (!((aPos == 0) && (aLength >= iSize)) && iCachedSize < iSize && !iFetchedBeforeWriting) |
|
245 { |
|
246 User::LeaveIfError(static_cast<CRsfwFsMountCB&> |
|
247 (Mount()).RSessionL()->Fetch(iThisFid, iCachedSize, iSize-1, iCachedSize)); |
|
248 iFetchedBeforeWriting = ETrue; |
|
249 } |
|
250 |
|
251 // make sure that a potential cache addition still fits into the cache |
|
252 TInt sizeToBeWritten = 0; |
|
253 |
|
254 if (iSize > iCachedSize) |
|
255 { |
|
256 // when current Write is executed as a part of Copy operation |
|
257 // then iSize has been set to final size, even before any writing started |
|
258 sizeToBeWritten = iSize - iCachedSize; |
|
259 } |
|
260 else if (aPos + aLength > iCachedSize) |
|
261 { |
|
262 sizeToBeWritten = aPos + aLength - iCachedSize + iWrittenSize; |
|
263 } |
|
264 |
|
265 TBool okToWrite; |
|
266 User::LeaveIfError(static_cast<CRsfwFsMountCB&> |
|
267 (Mount()).RSessionL()->OkToWrite(iThisFid, |
|
268 sizeToBeWritten, |
|
269 okToWrite)); |
|
270 |
|
271 if (!okToWrite) |
|
272 { |
|
273 User::Leave(KErrDiskFull); |
|
274 } |
|
275 |
|
276 TInt anOffset = 0; |
|
277 HBufC8* data = HBufC8::NewMaxLC(aLength); |
|
278 TPtr8 buf(data->Des()); |
|
279 |
|
280 aMessage.ReadL(0, buf, anOffset); |
|
281 |
|
282 User::LeaveIfError(iContFile.Write(aPos, *data, aLength)); |
|
283 User::LeaveIfError(iContFile.Flush()); |
|
284 CleanupStack::PopAndDestroy(data); |
|
285 |
|
286 // update iCachedSize and iWrittenSize if the container file size has grown |
|
287 if (aPos + aLength > iCachedSize) |
|
288 { |
|
289 iCachedSize = aPos + aLength; |
|
290 iWrittenSize = sizeToBeWritten; |
|
291 } |
|
292 |
|
293 // for flush() calls after this call: |
|
294 // set iFlushedSize to aPos, so that changes will be flushed |
|
295 if (iFlushedSize > aPos) |
|
296 { |
|
297 iFlushedSize = aPos; |
|
298 } |
|
299 |
|
300 } |
|
301 |
|
302 // ----------------------------------------------------------------------------- |
|
303 // CRsfwFsFileCB::SetSizeL |
|
304 // Emply implementation, upper class already set iSize |
|
305 // (other items were commented in a header). |
|
306 // ----------------------------------------------------------------------------- |
|
307 // |
|
308 void CRsfwFsFileCB::SetSizeL( |
|
309 TInt aSize) |
|
310 { |
|
311 iReportedSize = aSize; |
|
312 // we cannot set the actual size of the remote file, but also we do not |
|
313 // return KErrNotSupported as that would cause problems with CFileMan |
|
314 // and File Manager, which use SetSize() as an optimization to set the |
|
315 // target file size in copy. |
|
316 // Propably calling setsize() on remote files when for example just writing |
|
317 // to an existing file would cause weird results. |
|
318 } |
|
319 |
|
320 // ----------------------------------------------------------------------------- |
|
321 // CRsfwFsFileCB::SetEntryL |
|
322 // Sets the attribute mask, iAtt, and the modified time of the file, iModified. |
|
323 // If aMask|aVal does not equal zero, then aMask should be OR'ed with iAtt, |
|
324 // whilst the inverse of aVal should be AND'ed with iAtt. |
|
325 // If the modified flag is set in aMask then iModified should be set to aTime. |
|
326 // |
|
327 // Implemented by calling CRsfwFsMountCB::SetEntryL(). |
|
328 // (other items were commented in a header). |
|
329 // ----------------------------------------------------------------------------- |
|
330 // |
|
331 void CRsfwFsFileCB::SetEntryL( |
|
332 const TTime& aTime, |
|
333 TUint aMask, |
|
334 TUint aVal) |
|
335 { |
|
336 static_cast<CRsfwFsMountCB&>(Mount()).SetEntryL(*iFileName, |
|
337 aTime, |
|
338 aMask, |
|
339 aVal); |
|
340 } |
|
341 |
|
342 // ----------------------------------------------------------------------------- |
|
343 // CRsfwFsFileCB::FlushAllL |
|
344 // Flushes, to disk, all cached file data (e.g. attributes, modification time, |
|
345 // file size). The modified bit in the file attributes mask should be cleared if |
|
346 // the flush was successful. |
|
347 // |
|
348 // File Server calls this before reading directory entries, getting an entry |
|
349 // details for a directory entry etc. The idea is to make sure that all the |
|
350 // information to be retrieved is up to date. We don't need to implement this, |
|
351 // as our framework does not have buffers that could cause this problem. |
|
352 // |
|
353 // (other items were commented in a header). |
|
354 // ----------------------------------------------------------------------------- |
|
355 // |
|
356 void CRsfwFsFileCB::FlushAllL() |
|
357 { |
|
358 } |
|
359 |
|
360 // ----------------------------------------------------------------------------- |
|
361 // CRsfwFsFileCB::FlushDataL |
|
362 // Flushes, to disk, the cached information necessary for the integrity |
|
363 // of recently written data, such as the file size. |
|
364 // |
|
365 // Called by File Server as a result of RFile::Flush() (if the file has been |
|
366 // modified). In our framework the file should be written to the server. |
|
367 // We should also clear KEntryAttModified here. |
|
368 // |
|
369 // (other items were commented in a header). |
|
370 // |
|
371 // ----------------------------------------------------------------------------- |
|
372 // |
|
373 void CRsfwFsFileCB::FlushDataL() |
|
374 { |
|
375 TInt err = KErrNone; |
|
376 |
|
377 // close the container file to make sure all the local changes are cached |
|
378 iContFile.Close(); |
|
379 |
|
380 // if flush was cancelled, but we come again to write, |
|
381 // again set lastflushfailed to EFale |
|
382 iLastFlushFailed = EFalse; |
|
383 |
|
384 // may attempt to write part of the file or whole file |
|
385 // also we may or may not know for sure whether the |
|
386 // server supports partial write |
|
387 starttoflush: |
|
388 if (!iPartialWriteSupported) |
|
389 { |
|
390 // If we know that partial write is not supported |
|
391 // AND the client has reported the full size of |
|
392 // the file, do not really flush until all the data |
|
393 // has been written to the cache file. |
|
394 // * |
|
395 // If we do not know the total size flush whatever is cached |
|
396 if ((iCachedSize == iReportedSize) || iReportedSize == 0) |
|
397 { |
|
398 err = static_cast<CRsfwFsMountCB&> |
|
399 (Mount()).RSessionL()->Flush(iThisFid, |
|
400 0, |
|
401 iCachedSize, |
|
402 iCachedSize); |
|
403 } |
|
404 // else do not do anything yet, only when the whole file is in cache |
|
405 } |
|
406 else |
|
407 { |
|
408 // we "still" assume that partial write is supported |
|
409 err = static_cast<CRsfwFsMountCB&> |
|
410 (Mount()).RSessionL()->Flush(iThisFid, |
|
411 iFlushedSize, |
|
412 iCachedSize, |
|
413 iReportedSize); |
|
414 if (err == KErrNotSupported) |
|
415 { |
|
416 err = KErrNone; // reset the error |
|
417 // flushing the file not supported |
|
418 // probably because the access protol plugin does not support partial write |
|
419 iPartialWriteSupported = EFalse; |
|
420 // apply the flush logic again |
|
421 // this time with the knowledge that the server does not support partial |
|
422 // write |
|
423 goto starttoflush; |
|
424 } |
|
425 else |
|
426 { |
|
427 iAtt &= ~KEntryAttModified; // clear KEntryAttModified if flush worked |
|
428 } |
|
429 |
|
430 } |
|
431 |
|
432 // re-open the container file |
|
433 User::LeaveIfError(iContFile.Open(*(RFs* )Dll::Tls(), |
|
434 iCachePath, |
|
435 EFileWrite | EFileShareAny)); |
|
436 |
|
437 |
|
438 // handling the results |
|
439 if (err == KErrNone) |
|
440 { |
|
441 // the operation was successful |
|
442 iFlushedSize = iCachedSize; |
|
443 } |
|
444 else if (err != KErrNone) |
|
445 { |
|
446 iLastFlushFailed = ETrue; |
|
447 User::Leave(err); |
|
448 } |
|
449 |
|
450 } |
|
451 |
|
452 // ----------------------------------------------------------------------------- |
|
453 // CRsfwFsFileCB::SetContainerFileL |
|
454 // Opens the container file. |
|
455 // Called in CRsfwFsMountCB when the file is opened. |
|
456 // Implementation notice: If this file is only opened for reading, it would |
|
457 // seem sensible to open EFileRead|EFileShareAny here, but when Remote |
|
458 // File Engine then tries to open EFileWrite|EFileShareAny it fails unless |
|
459 // EFileWrite is specified here also... |
|
460 // |
|
461 // (other items were commented in a header). |
|
462 // ----------------------------------------------------------------------------- |
|
463 // |
|
464 void CRsfwFsFileCB::SetContainerFileL( |
|
465 const TDesC& aPath) |
|
466 { |
|
467 iCachePath = aPath; |
|
468 User::LeaveIfError(iContFile.Open(*(RFs* )Dll::Tls(), |
|
469 aPath, |
|
470 EFileWrite | EFileShareAny)); |
|
471 } |
|
472 |
|
473 // End of File |
|