|
1 // Copyright (c) 2008-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 "FileBuf64.h" |
|
16 |
|
17 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
18 /////////////////////////// PROFILER //////////////////////////////////////////////////////////////////// |
|
19 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
20 |
|
21 #ifdef _SQLPROFILER |
|
22 |
|
23 extern TBool TheOsCallTimeDetailedProfileEnabled;//If true, the OS porting layer call details are enabled and for each call an entry will be added to the log file (epocwind.out). |
|
24 |
|
25 #define PROFILE_READ(pos,amount) \ |
|
26 do \ |
|
27 { \ |
|
28 if(TheOsCallTimeDetailedProfileEnabled) \ |
|
29 { \ |
|
30 ++iFileReadCount; iFileReadAmount += (amount); \ |
|
31 RDebug::Print(_L(" -- FRead this=%X, Cnt=%d, Pos=%ld, Amt=%d, Ttl=%ld\r\n"), (TUint32)this, iFileReadCount, pos, amount, iFileReadAmount); \ |
|
32 } \ |
|
33 } while(0) |
|
34 |
|
35 #define PROFILE_WRITE(pos,amount) \ |
|
36 do \ |
|
37 { \ |
|
38 if(TheOsCallTimeDetailedProfileEnabled) \ |
|
39 { \ |
|
40 ++iFileWriteCount, iFileWriteAmount += (amount); \ |
|
41 RDebug::Print(_L(" -- FWrite this=%X, Cnt=%d, Pos=%ld, Amt=%d, Ttl=%ld\r\n"), (TUint32)this, iFileWriteCount, pos, amount, iFileWriteAmount); \ |
|
42 } \ |
|
43 } while(0) |
|
44 |
|
45 #define PROFILE_SIZE() \ |
|
46 do \ |
|
47 { \ |
|
48 if(TheOsCallTimeDetailedProfileEnabled) \ |
|
49 { \ |
|
50 ++iFileSizeCount; \ |
|
51 RDebug::Print(_L(" -- FSize this=%X, Cnt=%d\r\n"), (TUint32)this, iFileSizeCount); \ |
|
52 } \ |
|
53 } while(0) |
|
54 |
|
55 #define PROFILE_SETSIZE() \ |
|
56 do \ |
|
57 { \ |
|
58 if(TheOsCallTimeDetailedProfileEnabled) \ |
|
59 { \ |
|
60 ++iFileSetSizeCount; \ |
|
61 RDebug::Print(_L(" -- FSetSize this=%X, Cnt=%d\r\n"), (TUint32)this, iFileSetSizeCount); \ |
|
62 } \ |
|
63 } while(0) |
|
64 |
|
65 #define PROFILE_FLUSH() \ |
|
66 do \ |
|
67 { \ |
|
68 if(TheOsCallTimeDetailedProfileEnabled) \ |
|
69 { \ |
|
70 ++iFileFlushCount; \ |
|
71 RDebug::Print(_L(" -- FFlush this=%X, Cnt=%d\r\n"), (TUint32)this, iFileFlushCount); \ |
|
72 } \ |
|
73 } while(0) |
|
74 |
|
75 //Resets the profiler counters |
|
76 void RFileBuf64::ProfilerReset() |
|
77 { |
|
78 iFileReadCount = 0; iFileReadAmount = 0; iFileWriteCount = 0; iFileWriteAmount = 0; iFileSizeCount = 0; iFileSetSizeCount = 0; iFileFlushCount = 0; |
|
79 } |
|
80 |
|
81 #else |
|
82 |
|
83 #define PROFILE_READ(pos,amount) void(0) |
|
84 #define PROFILE_WRITE(pos,amount) void(0) |
|
85 |
|
86 #define PROFILE_SIZE() void(0) |
|
87 #define PROFILE_SETSIZE() void(0) |
|
88 #define PROFILE_FLUSH() void(0) |
|
89 |
|
90 #endif//_SQLPROFILER |
|
91 |
|
92 /** |
|
93 This constant is used for initializing the RFileBuf64::iFileSize data member and means that |
|
94 the iFileSize is not yet initialized with the real file size value. |
|
95 (RFileBuf64::iFileSize caches the file size value) |
|
96 @internalComponent |
|
97 */ |
|
98 static const TInt KFileSizeNotSet = -1; |
|
99 |
|
100 /** |
|
101 This constant is used as a default initializer for the RFileBuf64::iNextReadFilePos data member, |
|
102 indicating that the "guessed" file read offset is invalid and should not be used. |
|
103 @internalComponent |
|
104 */ |
|
105 static const TInt KNextReadFilePosNotSet = -1; |
|
106 |
|
107 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
108 /////////////////////////// ASSERTS & INVARIANT ////////////////////////////////////////////////////////// |
|
109 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
110 |
|
111 #ifdef _DEBUG |
|
112 |
|
113 #define __FILEBUF64_INVARIANT() Invariant() |
|
114 |
|
115 /** |
|
116 String literal used in _DEBUG mode for indicating that the reported panic happened inside the RFileBuf64 implementation. |
|
117 |
|
118 @see TFileBufPanic64 |
|
119 @internalComponent |
|
120 */ |
|
121 _LIT(KPanicCategory, "FBuf64"); |
|
122 |
|
123 /** |
|
124 Set of numeric constants used together with the KPanicCategory string literal in _DEBUG mode for providing more detailed |
|
125 information about the reason of the panic. |
|
126 |
|
127 @see KPanicCategory |
|
128 @internalComponent |
|
129 */ |
|
130 enum TFileBufPanic64 |
|
131 { |
|
132 EFBufPanicCapacity = 1, //1 |
|
133 EFBufPanicNullBuf, |
|
134 EFBufPanicBufLen, |
|
135 EFBufPanicFilePos, |
|
136 EFBufPanicFileSize, //5 |
|
137 EFBufPanicFileHandle, |
|
138 EFBufPanicFsHandle, |
|
139 EFBufPanicMsgHandle, |
|
140 EFBufPanicMsgIndex, |
|
141 EFBufPanicFileNameLen, //10 |
|
142 EFBufPanicNullThis, |
|
143 EFBufPanicDirty, |
|
144 EFBufPanicNextReadFilePos, |
|
145 EFBufPanicNextReadFilePosHits, |
|
146 EFBufPanicFileBlockSize, //15 |
|
147 }; |
|
148 |
|
149 /** |
|
150 Helper function used in the implementation of the __FBUF64_ASSERT() macro. |
|
151 In case if the expression in __FBUF64_ASSERT() macro evaluates to false, |
|
152 PanicFileBuf64() will use the supplied aLine and aPanicCode arguments together with the KPanicCategory string literal |
|
153 to prepare and print out a line (including the time of the panic) to the default log. The calling thread will be panic'ed |
|
154 after that. |
|
155 |
|
156 @see TFileBufPanic64 |
|
157 @see KPanicCategory |
|
158 @internalComponent |
|
159 */ |
|
160 static void PanicFileBuf64(TInt aLine, TFileBufPanic64 aPanicCode) |
|
161 { |
|
162 TTime time; |
|
163 time.HomeTime(); |
|
164 TDateTime dt = time.DateTime(); |
|
165 TBuf<16> tbuf; |
|
166 tbuf.Format(_L("%02d:%02d:%02d.%06d"), dt.Hour(), dt.Minute(), dt.Second(), dt.MicroSecond()); |
|
167 |
|
168 TBuf<64> buf; |
|
169 _LIT(KFormat,"**%S:RFileBuf64 panic %d, at line(%d)"); |
|
170 buf.Format(KFormat, &tbuf, aPanicCode, aLine); |
|
171 RDebug::Print(buf); |
|
172 User::Panic(KPanicCategory, aPanicCode); |
|
173 } |
|
174 |
|
175 /** |
|
176 This macro should be used when there is a need to panic the client/server if "expr" condition is not satisfied. |
|
177 Works in only in debug mode. In release mode evaluates to nothing. |
|
178 |
|
179 @see TFileBufPanic64 |
|
180 @see KPanicCategory |
|
181 @see PanicFileBuf64() |
|
182 @internalComponent |
|
183 */ |
|
184 #define __FBUF64_ASSERT(expr, panicCode) (void)(!(expr) ? ::PanicFileBuf64(__LINE__, panicCode) : void(0)) |
|
185 |
|
186 #else //_DEBUG |
|
187 |
|
188 #define __FILEBUF64_INVARIANT() void(0) |
|
189 |
|
190 #define __FBUF64_ASSERT(expr, panicCode) void(0) |
|
191 |
|
192 #endif//_DEBUG |
|
193 |
|
194 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
195 /////////////////////////// MFileInitializer64 ///////////////////////////////////////////////////////////// |
|
196 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
197 |
|
198 /** |
|
199 MFileInitializer64 interface provides only one abstract method - Init() that is used during the initialization of |
|
200 the RFileBuf64 objects. |
|
201 Here is what is the problem MFileInitializer64 tries to solve. |
|
202 RFileBuf64 has 4 different "resource acquisition" methods - Create(), Open(), Temp() and AdoptFromClient(). |
|
203 They perform different actions and have different input arguments. |
|
204 This is the variable part of the RFileBuf64 initialization. |
|
205 Apart from that, RFileBuf64 has a "fixed" initialization part that does not change whatever the variable part is. |
|
206 If MFileInitializer64 interface is not used then the following chunk of code has to be duplicated 4 times: |
|
207 @code |
|
208 TInt err = do_fixed_init(); |
|
209 if(err == KErrNone) |
|
210 { |
|
211 err = do_variable_init(); |
|
212 if(err != KErrNone) |
|
213 { |
|
214 revert_fixed_init(); |
|
215 } |
|
216 } |
|
217 return err; |
|
218 @endcode |
|
219 In order to avoid the code duplication, the fixed part of the initialization is moved to RFileBuf64::DoInit(), which |
|
220 is given a reference to a MFileInitializer64 derived class that performas the variable part of the initialization. |
|
221 4 different MFileInitializer64 derived classes are provided for the 4 different "resource acquisition" methods. |
|
222 All they store the variable part of the RFileBuf64 initialization parameters and implement MFileInitializer64::Init(). |
|
223 |
|
224 @see RFileBuf64::DoInit() |
|
225 @internalComponent |
|
226 */ |
|
227 struct MFileInitializer64 |
|
228 { |
|
229 virtual TInt Init(RFile64& aFile) = 0; |
|
230 }; |
|
231 |
|
232 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
233 /////////////////////////// RFileBuf64 ///////////////////////////////////////////////////////////////////// |
|
234 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
235 |
|
236 /** |
|
237 Initializes RFileBuf64 data members with their default values. |
|
238 |
|
239 @param aSize Max file buffer size (capacity) in bytes. |
|
240 |
|
241 @panic FBuf64 1 In _DEBUG mode - aSize is 0 or negative. |
|
242 */ |
|
243 RFileBuf64::RFileBuf64(TInt aSize) : |
|
244 iCapacity(aSize), |
|
245 iReadAheadSize(RFileBuf64::KDefaultReadAheadSize) |
|
246 { |
|
247 __FBUF64_ASSERT(aSize > 0, EFBufPanicCapacity); |
|
248 } |
|
249 |
|
250 /** |
|
251 Initializes the RFileBuf64 object and creates and opens a new file that will be accessed through RFileBuf64 public interface. |
|
252 If the file already exists, an error is returned. |
|
253 If the resulting path does not exist, then the operation cannot proceed and the function returns an error code. |
|
254 |
|
255 @param aFs The file server session. |
|
256 @param aFileName The name of the file. Any path components (i.e. drive letter |
|
257 or directory), which are not specified, are taken from |
|
258 the session path. |
|
259 @param aFileMode The mode in which the file is opened. See TFileMode for details. |
|
260 |
|
261 @return KErrNone if successful, otherwise one of the other system-wide error codes. |
|
262 |
|
263 @see TFileMode |
|
264 @see RFile64::Create() |
|
265 @see MFileInitializer64 |
|
266 |
|
267 @panic FBuf64 7 In _DEBUG mode - Invalid aFs object (null file session handle). |
|
268 @panic FBuf64 10 In _DEBUG mode - Invalid file name length (zero file name length). |
|
269 */ |
|
270 TInt RFileBuf64::Create(RFs& aFs, const TDesC& aFileName, TUint aFileMode) |
|
271 { |
|
272 __FBUF64_ASSERT(aFs.Handle() != 0, EFBufPanicFsHandle); |
|
273 __FBUF64_ASSERT(aFileName.Length() > 0, EFBufPanicFileNameLen); |
|
274 |
|
275 struct TFileCreateInitializer64 : public MFileInitializer64 |
|
276 { |
|
277 inline TFileCreateInitializer64(RFs& aFs, const TDesC& aFileName, TUint aFileMode) : |
|
278 iFs(aFs), |
|
279 iFileName(aFileName), |
|
280 iFileMode(aFileMode) |
|
281 { |
|
282 } |
|
283 virtual TInt Init(RFile64& aFile) |
|
284 { |
|
285 return aFile.Create(iFs, iFileName, iFileMode); |
|
286 } |
|
287 RFs& iFs; |
|
288 const TDesC& iFileName; |
|
289 TUint iFileMode; |
|
290 } initializer(aFs, aFileName, aFileMode); |
|
291 |
|
292 return DoInit(initializer); |
|
293 } |
|
294 |
|
295 /** |
|
296 Initializes the RFileBuf64 object and opens an existing file that will be accessed through RFileBuf64 public interface. |
|
297 If the file does not already exist, an error is returned. |
|
298 |
|
299 @param aFs The file server session. |
|
300 @param aFileName The name of the file. Any path components (i.e. drive letter |
|
301 or directory), which are not specified, are taken from |
|
302 the session path. |
|
303 @param aFileMode The mode in which the file is opened. See TFileMode for details. |
|
304 |
|
305 @return KErrNone if successful, otherwise one of the other system-wide error codes. |
|
306 |
|
307 @see TFileMode |
|
308 @see RFile64::Open() |
|
309 @see MFileInitializer64 |
|
310 |
|
311 @panic FBuf64 7 In _DEBUG mode - Invalid aFs object (null file session handle). |
|
312 @panic FBuf64 10 In _DEBUG mode - Invalid file name length (zero file name length). |
|
313 */ |
|
314 TInt RFileBuf64::Open(RFs& aFs, const TDesC& aFileName, TUint aFileMode) |
|
315 { |
|
316 __FBUF64_ASSERT(aFs.Handle() != 0, EFBufPanicFsHandle); |
|
317 __FBUF64_ASSERT(aFileName.Length() > 0, EFBufPanicFileNameLen); |
|
318 |
|
319 struct TFileOpenInitializer64 : public MFileInitializer64 |
|
320 { |
|
321 inline TFileOpenInitializer64(RFs& aFs, const TDesC& aFileName, TUint aFileMode) : |
|
322 iFs(aFs), |
|
323 iFileName(aFileName), |
|
324 iFileMode(aFileMode) |
|
325 { |
|
326 } |
|
327 virtual TInt Init(RFile64& aFile) |
|
328 { |
|
329 return aFile.Open(iFs, iFileName, iFileMode); |
|
330 } |
|
331 RFs& iFs; |
|
332 const TDesC& iFileName; |
|
333 TUint iFileMode; |
|
334 } initializer(aFs, aFileName, aFileMode); |
|
335 |
|
336 return DoInit(initializer); |
|
337 } |
|
338 |
|
339 /** |
|
340 Initializes the RFileBuf64 object and creates and opens a temporary file with unique name that will be accessed through |
|
341 RFileBuf64 public interface. |
|
342 |
|
343 @param aFs The file server session. |
|
344 @param aPath The directory in which the file is created. |
|
345 @param aFileName On return, contains the full path and file name of the file. |
|
346 The filename is guaranteed to be unique within the directory |
|
347 specified by aPath. |
|
348 @param aFileMode The mode in which the file is opened. The access mode is |
|
349 automatically set to EFileWrite. See TFileMode for details. |
|
350 |
|
351 @return KErrNone if successful, otherwise one of the other system-wide error codes. |
|
352 |
|
353 @see TFileMode |
|
354 @see RFile64::Temp() |
|
355 @see MFileInitializer64 |
|
356 |
|
357 @panic FBuf64 7 In _DEBUG mode - Invalid aFs object (null file session handle). |
|
358 */ |
|
359 TInt RFileBuf64::Temp(RFs& aFs, const TDesC& aPath, TFileName& aFileName, TUint aFileMode) |
|
360 { |
|
361 __FBUF64_ASSERT(aFs.Handle() != 0, EFBufPanicFsHandle); |
|
362 |
|
363 struct TFileTempInitializer64 : public MFileInitializer64 |
|
364 { |
|
365 inline TFileTempInitializer64(RFs& aFs, const TDesC& aPath, TFileName& aFileName, TUint aFileMode) : |
|
366 iFs(aFs), |
|
367 iPath(aPath), |
|
368 iFileName(aFileName), |
|
369 iFileMode(aFileMode) |
|
370 { |
|
371 } |
|
372 virtual TInt Init(RFile64& aFile) |
|
373 { |
|
374 return aFile.Temp(iFs, iPath, iFileName, iFileMode); |
|
375 } |
|
376 RFs& iFs; |
|
377 const TDesC& iPath; |
|
378 TFileName& iFileName; |
|
379 TUint iFileMode; |
|
380 } initializer(aFs, aPath, aFileName, aFileMode); |
|
381 |
|
382 return DoInit(initializer); |
|
383 } |
|
384 |
|
385 /** |
|
386 Initializes the RFileBuf64 object and creates and adopts an already open file from a client that will be accessed through |
|
387 RFileBuf64 public interface. |
|
388 The client's RFs and RFile or RFile64 handles are contained in message slots within aMsg. |
|
389 Assumes that the client's RFs and RFile or RFile64 handles have been sent to the server using TransferToServer(). |
|
390 |
|
391 @param aMsg The message received from the client |
|
392 @param aFsIndex The index that identifies the message slot |
|
393 of a file server session (RFs) handle |
|
394 @param aFileIndex The index that identifies the message slot |
|
395 of the sub-session (RFile or RFile64) handle of the already opened file |
|
396 |
|
397 @return KErrNone if successful, otherwise one of the other system-wide error codes. |
|
398 |
|
399 @see TFileMode |
|
400 @see RFile64::AdoptFromClient() |
|
401 @see MFileInitializer64 |
|
402 @see KMaxMessageArguments |
|
403 |
|
404 @panic FBuf64 8 In _DEBUG mode - Invalid aMsg object (null message handle). |
|
405 @panic FBuf64 9 In _DEBUG mode - Invalid file session handle message slot index or invalid file handle message slot index. |
|
406 (Probably negative index or index bigger or equal to KMaxMessageArguments) |
|
407 */ |
|
408 TInt RFileBuf64::AdoptFromClient(const RMessage2& aMsg, TInt aFsIndex, TInt aFileIndex) |
|
409 { |
|
410 __FBUF64_ASSERT(aMsg.Handle() != 0, EFBufPanicMsgHandle); |
|
411 __FBUF64_ASSERT(aFsIndex >= 0 && aFsIndex < KMaxMessageArguments, EFBufPanicMsgIndex); |
|
412 __FBUF64_ASSERT(aFileIndex >= 0 && aFileIndex < KMaxMessageArguments, EFBufPanicMsgIndex); |
|
413 |
|
414 struct TFileAdoptInitializer64 : public MFileInitializer64 |
|
415 { |
|
416 inline TFileAdoptInitializer64(const RMessage2& aMsg, TInt aFsIndex, TInt aFileIndex) : |
|
417 iMsg(aMsg), |
|
418 iFsIndex(aFsIndex), |
|
419 iFileIndex(aFileIndex) |
|
420 { |
|
421 } |
|
422 virtual TInt Init(RFile64& aFile) |
|
423 { |
|
424 return aFile.AdoptFromClient(iMsg, iFsIndex, iFileIndex); |
|
425 } |
|
426 const RMessage2& iMsg; |
|
427 TInt iFsIndex; |
|
428 TInt iFileIndex; |
|
429 } initializer(aMsg, aFsIndex, aFileIndex); |
|
430 |
|
431 return DoInit(initializer); |
|
432 } |
|
433 |
|
434 /** |
|
435 Writes to the file the pending data (if the buffer contains pending data), closes the file and releases |
|
436 the RFileBuf64 resources. |
|
437 RFileBuf64::Flush() should be called before RFileBuf64::Close() to ensure that if there are pending data, they will |
|
438 be written to the file and if the operation fails, the caller will be notified with an appropriate return error. |
|
439 |
|
440 @see RFileBuf64::Flush() |
|
441 */ |
|
442 void RFileBuf64::Close() |
|
443 { |
|
444 if(iBase != 0 && iFile.SubSessionHandle() != 0) |
|
445 { |
|
446 (void)DoFileWrite2(); |
|
447 } |
|
448 iFile.Close(); |
|
449 User::Free(iBase); |
|
450 iBase = 0; |
|
451 } |
|
452 |
|
453 /** |
|
454 Calculates and sets optimal read-ahead buffer size. |
|
455 |
|
456 @param aBlockSize The size of a file block in bytes |
|
457 @param aReadRecBufSize The recommended buffer size for optimised reading performance |
|
458 |
|
459 @return The new read-ahead value |
|
460 |
|
461 @see TVolumeIOParamInfo |
|
462 */ |
|
463 TInt RFileBuf64::SetReadAheadSize(TInt aBlockSize, TInt aReadRecBufSize) |
|
464 { |
|
465 __FILEBUF64_INVARIANT(); |
|
466 if((aReadRecBufSize & (aReadRecBufSize - 1)) == 0 && aReadRecBufSize > RFileBuf64::KDefaultReadAheadSize) |
|
467 { |
|
468 iReadAheadSize = aReadRecBufSize > iCapacity ? iCapacity : aReadRecBufSize; |
|
469 } |
|
470 else if((aBlockSize & (aBlockSize - 1)) == 0 && aBlockSize > RFileBuf64::KDefaultReadAheadSize) |
|
471 { |
|
472 iReadAheadSize = aBlockSize > iCapacity ? iCapacity : aBlockSize; |
|
473 } |
|
474 __FILEBUF64_INVARIANT(); |
|
475 return iReadAheadSize; |
|
476 } |
|
477 |
|
478 /** |
|
479 Reads from the file at the specified position (aFilePos). |
|
480 If the data to be read is in the buffer, then the data will be taken from the buffer. |
|
481 |
|
482 @param aFilePos Position of first byte to be read. This is an offset from |
|
483 the start of the file. |
|
484 If aPos is beyond the end of the file, the function returns |
|
485 a zero length descriptor. |
|
486 @param aDes Descriptor into which binary data is read. Any existing contents |
|
487 are overwritten. On return, its length is set to the number of |
|
488 bytes read. |
|
489 |
|
490 @return KErrNone if successful, otherwise one of the other system-wide error codes. |
|
491 |
|
492 @panic FBuf64 4 In _DEBUG mode - negative aFilePos value. |
|
493 See RFileBuf64::Invariant() for other possible panics that may occur when this method is called. |
|
494 |
|
495 @see RFileBuf64::Invariant() |
|
496 */ |
|
497 TInt RFileBuf64::Read(TInt64 aFilePos, TDes8& aDes) |
|
498 { |
|
499 __FBUF64_ASSERT(aFilePos >= 0, EFBufPanicFilePos); |
|
500 __FILEBUF64_INVARIANT(); |
|
501 aDes.SetLength(0); |
|
502 //1. The output buffer max len is 0 |
|
503 if(aDes.MaxLength() == 0) |
|
504 { |
|
505 __FILEBUF64_INVARIANT(); |
|
506 return KErrNone; |
|
507 } |
|
508 //2. Initialize the "iFileSize" if it is not initialized yet |
|
509 TInt err = DoFileSize(); |
|
510 if(err != KErrNone) |
|
511 { |
|
512 __FILEBUF64_INVARIANT(); |
|
513 return err; |
|
514 } |
|
515 //3. Too big "read" request - read directly from the file |
|
516 TInt len = aDes.MaxLength(); |
|
517 if(len > iCapacity) |
|
518 { |
|
519 if((aFilePos + len) > iFilePos && !(aFilePos >= (iFilePos + iLength))) |
|
520 {//Write the pending data if the iDirty flag is set, otherwise preserve the buffer content. |
|
521 err = DoFileWrite1(aFilePos); |
|
522 } |
|
523 if(err == KErrNone) |
|
524 { |
|
525 err = iFile.Read(aFilePos, aDes); |
|
526 PROFILE_READ(aFilePos, aDes.Size()); |
|
527 } |
|
528 __FILEBUF64_INVARIANT(); |
|
529 return err; |
|
530 } |
|
531 //4. The requested data size is smaller than the buffer capacity |
|
532 TUint8* outptr = const_cast <TUint8*> (aDes.Ptr()); |
|
533 while(len > 0 && err == KErrNone && aFilePos < iFileSize) |
|
534 { |
|
535 //1. If part of all of the data is in the buffer - copy the data to the target location |
|
536 if(aFilePos >= iFilePos && aFilePos < (iFilePos + iLength)) |
|
537 { |
|
538 TInt l = Min(len, (iFilePos + iLength - aFilePos)); |
|
539 outptr = Mem::Copy(outptr, iBase + (aFilePos - iFilePos), l); |
|
540 len -= l; |
|
541 aFilePos += l; |
|
542 } |
|
543 //2. Perform a read-ahead operation |
|
544 else |
|
545 { |
|
546 //Write the pending data if the iDirty flag is set, otherwise preserve the buffer content. |
|
547 err = DoFileWrite1(aFilePos); |
|
548 if(err != KErrNone) |
|
549 { |
|
550 break; |
|
551 } |
|
552 if(iNextReadFilePos != aFilePos) |
|
553 {//Direct "file read" operation |
|
554 iNextReadFilePosHits = 0; |
|
555 TPtr8 ptr2(outptr, len); |
|
556 err = iFile.Read(aFilePos, ptr2); |
|
557 PROFILE_READ(aFilePos, ptr2.Size()); |
|
558 if(err == KErrNone) |
|
559 { |
|
560 iNextReadFilePos = aFilePos + len; |
|
561 len -= ptr2.Length(); |
|
562 } |
|
563 break; |
|
564 } |
|
565 //The guessed from the previous "file read" operation file pos is correct. Start reading-ahead. |
|
566 const TInt KMaxReadFilePosHits = 8;//The max read-ahead buffer size can be up to 2^8 times the iReadAheadSize |
|
567 if(iNextReadFilePosHits < KMaxReadFilePosHits) |
|
568 { |
|
569 ++iNextReadFilePosHits; |
|
570 } |
|
571 TInt maxReadAhead = iReadAheadSize * (1 << iNextReadFilePosHits); |
|
572 TInt align = (aFilePos + len + maxReadAhead) & (iReadAheadSize - 1); |
|
573 TInt readahead = maxReadAhead - align; |
|
574 if(readahead < 0) |
|
575 { |
|
576 // if read-ahead doesn't cross block boundary do it all |
|
577 readahead = maxReadAhead; |
|
578 } |
|
579 TPtr8 ptr(iBase, Min(iCapacity, (len + readahead))); |
|
580 err = iFile.Read(aFilePos, ptr); |
|
581 PROFILE_READ(aFilePos, ptr.Size()); |
|
582 if(err == KErrNone) |
|
583 { |
|
584 iFilePos = aFilePos; |
|
585 iLength = ptr.Length(); |
|
586 iNextReadFilePos = iFilePos + iLength; |
|
587 if(iLength == 0) |
|
588 { |
|
589 break; |
|
590 } |
|
591 } |
|
592 else |
|
593 { |
|
594 DoDiscard(); |
|
595 } |
|
596 } |
|
597 } |
|
598 aDes.SetLength(aDes.MaxLength() - len); |
|
599 __FILEBUF64_INVARIANT(); |
|
600 return err; |
|
601 } |
|
602 |
|
603 /** |
|
604 Writes to the file at the specified offset (aFilePos) within the file. |
|
605 If certain conditions are met, the data will be stored in the buffer - no call to the file server. |
|
606 |
|
607 @param aFilePos The offset from the start of the file at which the first byte is written. |
|
608 If a position beyond the end of the file is specified, then |
|
609 the write operation begins at the end of the file. |
|
610 If the position has been locked, then the write fails. |
|
611 |
|
612 @param aData The descriptor from which binary data is written. The function writes |
|
613 the entire contents of aData to the file. |
|
614 |
|
615 @return KErrNone if successful, otherwise one of the other system-wide error codes. |
|
616 |
|
617 @panic FBuf64 4 In _DEBUG mode - negative aFilePos value. |
|
618 See RFileBuf64::Invariant() for other possible panics that may occur when this method is called. |
|
619 |
|
620 @see RFileBuf64::Invariant() |
|
621 */ |
|
622 TInt RFileBuf64::Write(TInt64 aFilePos, const TDesC8& aData) |
|
623 { |
|
624 __FBUF64_ASSERT(aFilePos >= 0, EFBufPanicFilePos); |
|
625 __FILEBUF64_INVARIANT(); |
|
626 if(aData.Length() == 0) |
|
627 { |
|
628 __FILEBUF64_INVARIANT(); |
|
629 return KErrNone; |
|
630 } |
|
631 TInt err = DoFileSize(); |
|
632 if(err != KErrNone) |
|
633 { |
|
634 __FILEBUF64_INVARIANT(); |
|
635 return err; |
|
636 } |
|
637 DoDiscardBufferedReadData(); |
|
638 const TUint8* data = aData.Ptr(); |
|
639 for(TInt len = aData.Length(); len > 0 && err == KErrNone;) |
|
640 { |
|
641 //1. The new write pos is before the buffered file pos |
|
642 if(aFilePos < iFilePos) |
|
643 { |
|
644 //If the new data sticks to/overlapps the old data and there is room in the buffer to move the old data |
|
645 //toward the end, then the new data can be copied at the beginning of the buffer. |
|
646 if((aFilePos + len) >= iFilePos && (iFilePos - aFilePos) <= (iCapacity - iLength)) |
|
647 { |
|
648 (void)Mem::Copy(iBase + (iFilePos - aFilePos), iBase, iLength); //Make room - move the existing data toward the end |
|
649 (void)Mem::Copy(iBase, data, len); //of the buffer. Stick the new data to the old data |
|
650 iLength += (iFilePos - aFilePos); |
|
651 iFilePos = aFilePos; //The new file pos is associated with the buffer |
|
652 iFileSize = Max(iFileSize, (iFilePos + iLength)); |
|
653 len = 0; //No more new data |
|
654 iDirty = ETrue; |
|
655 } |
|
656 else |
|
657 //The "aFilePos" is too far before the "iFilePos". Write the buffer and associate the new pos with the buffer |
|
658 { |
|
659 err = DoFileWrite2(aFilePos); |
|
660 } |
|
661 } |
|
662 //2. The new write pos is after the associated file pos + the data length. |
|
663 else if(aFilePos > (iFilePos + iLength)) |
|
664 { |
|
665 if(aFilePos > iFileSize) //Beyond the end of the file |
|
666 { |
|
667 if((iFilePos + iLength) == iFileSize && (aFilePos - iFilePos) < iCapacity) |
|
668 { //but within the buffer => extend the file with zeros. |
|
669 Mem::FillZ(iBase + iLength, aFilePos - iFilePos - iLength); |
|
670 iLength = aFilePos - iFilePos; |
|
671 iFileSize = Max(iFileSize, (iFilePos + iLength)); |
|
672 iDirty = ETrue; |
|
673 } |
|
674 else |
|
675 //Beyond the end of the file and not in the buffer - set file size. |
|
676 { |
|
677 err = DoSetFileSize(aFilePos); |
|
678 } |
|
679 } |
|
680 else |
|
681 //Within the file, not in the buffer - write the buffer and associate the new file pos with the buffer |
|
682 { |
|
683 err = DoFileWrite2(aFilePos); |
|
684 } |
|
685 } |
|
686 //3. The new write pos is in the buffer, but the data length is too big |
|
687 // (For SQLite is OK, otherwise the whole block must be written to the file) |
|
688 //4. The new write pos is in the buffer, the data entirely fits in the buffer |
|
689 else |
|
690 { |
|
691 if(iCapacity == iLength) //The buffer is full. Write the buffer and associate the new file pos |
|
692 { |
|
693 err = DoFileWrite2(aFilePos); |
|
694 } |
|
695 if(err == KErrNone) |
|
696 { |
|
697 TInt amount = Min(len, (iCapacity - (aFilePos - iFilePos))); |
|
698 const TUint8* end = Mem::Copy(iBase + (aFilePos - iFilePos), data, amount); |
|
699 iLength = Max(iLength, (end - iBase)); |
|
700 iFileSize = Max(iFileSize, (iFilePos + iLength)); |
|
701 len -= amount; |
|
702 data += amount; |
|
703 aFilePos += amount; |
|
704 iDirty = ETrue; |
|
705 } |
|
706 } |
|
707 } |
|
708 __FILEBUF64_INVARIANT(); |
|
709 return err; |
|
710 } |
|
711 |
|
712 /** |
|
713 Gets the current file size. |
|
714 |
|
715 @param aFileSize On return, the size of the file in bytes. |
|
716 |
|
717 @return KErrNone if successful, otherwise one of the other system-wide error codes. |
|
718 |
|
719 See RFileBuf64::Invariant() for possible panics that may occur when this method is called. |
|
720 |
|
721 @see RFileBuf64::Invariant() |
|
722 */ |
|
723 TInt RFileBuf64::Size(TInt64& aFileSize) |
|
724 { |
|
725 __FILEBUF64_INVARIANT(); |
|
726 TInt err = DoFileSize(); |
|
727 if(err == KErrNone) |
|
728 { |
|
729 aFileSize = iFileSize; |
|
730 } |
|
731 __FILEBUF64_INVARIANT(); |
|
732 return err; |
|
733 } |
|
734 |
|
735 /** |
|
736 Sets the file size. |
|
737 |
|
738 If the size of the file is reduced, data may be lost from the end of the file. |
|
739 |
|
740 Note: |
|
741 |
|
742 1. The current file position remains unchanged unless SetSize() reduces the size |
|
743 of the file in such a way that the current file position is now beyond |
|
744 the end of the file. In this case, the current file position is set to |
|
745 the end of file. |
|
746 |
|
747 2. If the file was not opened for writing, an error is returned. |
|
748 |
|
749 @param aFileSize The new size of the file, in bytes. This value must not be negative, otherwise the function raises a panic. |
|
750 |
|
751 @return KErrNone if successful, otherwise one of the other system-wide error codes. |
|
752 |
|
753 @panic FBuf64 5 In _DEBUG mode - negative aFileSize value. |
|
754 See RFileBuf64::Invariant() for other possible panics that may occur when this method is called. |
|
755 |
|
756 @see RFileBuf64::Invariant() |
|
757 */ |
|
758 TInt RFileBuf64::SetSize(TInt64 aFileSize) |
|
759 { |
|
760 __FBUF64_ASSERT(aFileSize >= 0, EFBufPanicFileSize); |
|
761 __FILEBUF64_INVARIANT(); |
|
762 return DoSetFileSize(aFileSize); |
|
763 } |
|
764 |
|
765 /** |
|
766 Writes the pending data and then flushes the file. |
|
767 |
|
768 Although RFileBuf64::Close() also flushes internal buffers, it is better |
|
769 to call RFileBuf64::Flush() before the file is closed. This is because Close() returns no |
|
770 error information, so there is no way of telling whether the final data was |
|
771 written to the file successfully or not. |
|
772 |
|
773 @return KErrNone if successful, otherwise one of the other system-wide error codes. |
|
774 |
|
775 See RFileBuf64::Invariant() for possible panics that may occur when this method is called. |
|
776 |
|
777 @see RFileBuf64::Invariant() |
|
778 */ |
|
779 TInt RFileBuf64::Flush() |
|
780 { |
|
781 __FILEBUF64_INVARIANT(); |
|
782 return DoFileFlush(); |
|
783 } |
|
784 |
|
785 /** |
|
786 Gets information about the drive on which this file resides. |
|
787 |
|
788 @param aDriveNumber On return, the drive number. |
|
789 |
|
790 @param aDriveInfo On return, contains information describing the drive |
|
791 and the medium mounted on it. The value of TDriveInfo::iType |
|
792 shows whether the drive contains media. |
|
793 |
|
794 @return KErrNone if successful, otherwise one of the other system-wide error codes. |
|
795 |
|
796 See RFileBuf64::Invariant() for possible panics that may occur when this method is called. |
|
797 |
|
798 @see RFileBuf64::Invariant() |
|
799 */ |
|
800 TInt RFileBuf64::Drive(TInt& aDriveNumber, TDriveInfo& aDriveInfo) const |
|
801 { |
|
802 __FILEBUF64_INVARIANT(); |
|
803 return iFile.Drive(aDriveNumber, aDriveInfo); |
|
804 } |
|
805 |
|
806 /** |
|
807 Performs the fixed part of the RFileBuf64 initialization and then calls MFileInitializer64::Init() to perform |
|
808 the variable part of the initialization. |
|
809 |
|
810 @param aFileInitializer A reference to an initializer object that implements MFileInitializer64::Init() |
|
811 |
|
812 @return KErrNone if successful, otherwise one of the other system-wide error codes. |
|
813 */ |
|
814 TInt RFileBuf64::DoInit(MFileInitializer64& aFileInitializer) |
|
815 { |
|
816 DoDiscard(); |
|
817 iReadAheadSize = RFileBuf64::KDefaultReadAheadSize; |
|
818 TInt err = KErrNoMemory; |
|
819 iBase = static_cast <TUint8*> (User::Alloc(iCapacity)); |
|
820 if(!iBase) |
|
821 { |
|
822 return KErrNoMemory; |
|
823 } |
|
824 err = aFileInitializer.Init(iFile); |
|
825 if(err != KErrNone) |
|
826 { |
|
827 User::Free(iBase); |
|
828 iBase = 0; |
|
829 } |
|
830 return err; |
|
831 } |
|
832 |
|
833 /** |
|
834 Discards the content of the RFileBuf64 object returning it to the state as if it has just been created. |
|
835 */ |
|
836 void RFileBuf64::DoDiscard() |
|
837 { |
|
838 iLength = 0; |
|
839 iFilePos = 0; |
|
840 iFileSize = KFileSizeNotSet; |
|
841 iDirty = EFalse; |
|
842 iNextReadFilePos = KNextReadFilePosNotSet; |
|
843 iNextReadFilePosHits = 0; |
|
844 } |
|
845 |
|
846 /** |
|
847 Gets the current file size. |
|
848 If iFileSize value is valid, then no call to the file server will be made. |
|
849 Otherwise the file server will be called and the file size - stored (cached) in iFileSize data member for later use. |
|
850 |
|
851 @return KErrNone if successful, otherwise one of the other system-wide error codes. |
|
852 |
|
853 See RFileBuf64::Invariant() for possible panics that may occur when this method is called. |
|
854 |
|
855 @see RFileBuf64::Invariant() |
|
856 */ |
|
857 TInt RFileBuf64::DoFileSize() |
|
858 { |
|
859 __FILEBUF64_INVARIANT(); |
|
860 if(iFileSize != KFileSizeNotSet) |
|
861 { |
|
862 __FILEBUF64_INVARIANT(); |
|
863 return KErrNone; |
|
864 } |
|
865 PROFILE_SIZE(); |
|
866 TInt err = iFile.Size(iFileSize); |
|
867 if(err != KErrNone) |
|
868 { |
|
869 DoDiscard(); |
|
870 } |
|
871 __FILEBUF64_INVARIANT(); |
|
872 return err; |
|
873 } |
|
874 |
|
875 /** |
|
876 Sets the file size. |
|
877 If the buffer contains pending data, the data will be written to the file |
|
878 before the "set file size" operation, if certain conditions are met. |
|
879 |
|
880 @param aFileSize The new size of the file, in bytes. This value must not be negative, otherwise the function raises a panic. |
|
881 |
|
882 @return KErrNone if successful, otherwise one of the other system-wide error codes. |
|
883 |
|
884 @panic FBuf64 5 In _DEBUG mode - negative aFileSize value. |
|
885 See RFileBuf64::Invariant() for other possible panics that may occur when this method is called. |
|
886 |
|
887 @see RFileBuf64::Invariant() |
|
888 */ |
|
889 TInt RFileBuf64::DoSetFileSize(TInt64 aFileSize) |
|
890 { |
|
891 __FBUF64_ASSERT(aFileSize >= 0, EFBufPanicFileSize); |
|
892 __FILEBUF64_INVARIANT(); |
|
893 if(aFileSize < iFilePos) |
|
894 { |
|
895 iDirty = EFalse; |
|
896 iLength = 0; |
|
897 } |
|
898 //If the new file size is "in" the buffer then change the "iLength" |
|
899 else if(aFileSize < (iFilePos + iLength)) |
|
900 { |
|
901 iLength = aFileSize - iFilePos; |
|
902 } |
|
903 PROFILE_SETSIZE(); |
|
904 TInt err = iFile.SetSize(aFileSize); |
|
905 if(err != KErrNone) |
|
906 { |
|
907 DoDiscard(); |
|
908 } |
|
909 else |
|
910 { |
|
911 iFileSize = aFileSize; |
|
912 } |
|
913 __FILEBUF64_INVARIANT(); |
|
914 return err; |
|
915 } |
|
916 |
|
917 /** |
|
918 Writes the pending data and flushes the file. |
|
919 |
|
920 @return KErrNone if successful, otherwise one of the other system-wide error codes. |
|
921 |
|
922 See RFileBuf64::Invariant() for possible panics that may occur when this method is called. |
|
923 |
|
924 @see RFileBuf64::Invariant() |
|
925 */ |
|
926 TInt RFileBuf64::DoFileFlush() |
|
927 { |
|
928 __FILEBUF64_INVARIANT(); |
|
929 TInt err = DoFileWrite2();//Write the buffer if the iDirty flag is set. Do not preserve the buffer content and file pos. |
|
930 if(err != KErrNone) |
|
931 { |
|
932 __FILEBUF64_INVARIANT(); |
|
933 return err; |
|
934 } |
|
935 PROFILE_FLUSH(); |
|
936 err = iFile.Flush(); |
|
937 if(err != KErrNone) |
|
938 { |
|
939 DoDiscard(); |
|
940 } |
|
941 iLength = 0; |
|
942 __FILEBUF64_INVARIANT(); |
|
943 return err; |
|
944 } |
|
945 |
|
946 /** |
|
947 Writes the buffered data to the file if the iLength value is > 0. |
|
948 If the file write operation extends the file, the iFileSize data member will be initialized with the new file size. |
|
949 No changes occur in the other data member values. |
|
950 |
|
951 @return KErrNone if successful, otherwise one of the other system-wide error codes. |
|
952 |
|
953 See RFileBuf64::Invariant() for other possible panics that may occur when this method is called. |
|
954 |
|
955 @see RFileBuf64::DoFileWrite1() |
|
956 @see RFileBuf64::DoFileWrite2() |
|
957 @see RFileBuf64::Invariant() |
|
958 */ |
|
959 TInt RFileBuf64::DoFileWrite() |
|
960 { |
|
961 __FILEBUF64_INVARIANT(); |
|
962 if(iLength == 0) |
|
963 { |
|
964 __FILEBUF64_INVARIANT(); |
|
965 return KErrNone; |
|
966 } |
|
967 PROFILE_WRITE(iFilePos, iLength); |
|
968 TPtrC8 data(iBase, iLength); |
|
969 TInt err = iFile.Write(iFilePos, data); |
|
970 if(err == KErrNone) |
|
971 { |
|
972 iFileSize = Max(iFileSize, (iFilePos + iLength)); |
|
973 } |
|
974 else |
|
975 { |
|
976 DoDiscard(); |
|
977 } |
|
978 __FILEBUF64_INVARIANT(); |
|
979 return err; |
|
980 } |
|
981 |
|
982 /** |
|
983 Writes the buffered data to the file if the iDirty flag is set. |
|
984 If the iDirty flag is set and the file write operation was successful, the iFilePos will be initialized with |
|
985 the aNewFilePos value, the iLength will be set to 0. |
|
986 This method is called from RFileBuf64::Read(), where: |
|
987 - if the buffer contains cached writes (iDirty flag is set), the buffer has to be flushed and iFilePos initialized |
|
988 with aNewFilePos - the offset in the file where the next file read operation should start from; |
|
989 - if the buffer contains cached reads, then nothing happens, the buffer content will be kept; |
|
990 The function resets the iDirty flag. |
|
991 |
|
992 @param aNewFilePos If the buffer is successfully written to the file the iFilePos data member will be initialized with |
|
993 the aNewFilePos value. |
|
994 |
|
995 @return KErrNone if successful, otherwise one of the other system-wide error codes. |
|
996 |
|
997 See RFileBuf64::Invariant() for other possible panics that may occur when this method is called. |
|
998 |
|
999 @panic FBuf64 4 In _DEBUG mode - negative aNewFilePos value. |
|
1000 |
|
1001 @see RFileBuf64::Read() |
|
1002 @see RFileBuf64::DoFileWrite() |
|
1003 @see RFileBuf64::DoFileWrite2() |
|
1004 @see RFileBuf64::Invariant() |
|
1005 */ |
|
1006 TInt RFileBuf64::DoFileWrite1(TInt64 aNewFilePos) |
|
1007 { |
|
1008 __FBUF64_ASSERT(aNewFilePos >= 0, EFBufPanicFilePos); |
|
1009 __FILEBUF64_INVARIANT(); |
|
1010 TInt err = KErrNone; |
|
1011 if(iDirty) |
|
1012 { |
|
1013 err = DoFileWrite(); |
|
1014 if(err == KErrNone) |
|
1015 { |
|
1016 iFilePos = aNewFilePos; |
|
1017 iLength = 0; |
|
1018 } |
|
1019 } |
|
1020 iDirty = EFalse; |
|
1021 __FILEBUF64_INVARIANT(); |
|
1022 return err; |
|
1023 } |
|
1024 |
|
1025 /* |
|
1026 Writes the buffered data to the file if the iDirty flag is set. |
|
1027 If the file write operation was successful or if the iDirty flag was not set, the iFilePos will be initialized with |
|
1028 the aNewFilePos value, the iLength will be set to 0. |
|
1029 This method is called from RFileBuf64::Write() an other RFileBuf64 methods (but not from RFileBuf64::Read()), where: |
|
1030 - if the buffer contains cached writes (iDirty flag is set), the buffer has to be flushed and iFilePos initialized |
|
1031 with aNewFilePos - the offset in the file for which the write data will be cached in the buffer; |
|
1032 - if the buffer contains cached reads, then the buffer content will be destroyed, iFilePos initialized with aNewFilePos |
|
1033 and iLength set to 0; |
|
1034 The function resets the iDirty flag. |
|
1035 The difference between RFileBuf64::DoFileWrite1() and RFileBuf64::DoFileWrite2() is: |
|
1036 - RFileBuf64::DoFileWrite1() perserves the buffer content if iDirty is not set; |
|
1037 - RFileBuf64::DoFileWrite2() always destroys the buffer content and initializes iFilePos; |
|
1038 |
|
1039 @param aNewFilePos If the buffer is successfully written to the file the iFilePos data member will be initialized with |
|
1040 the aNewFilePos value. |
|
1041 |
|
1042 @return KErrNone if successful, otherwise one of the other system-wide error codes. |
|
1043 |
|
1044 See RFileBuf64::Invariant() for other possible panics that may occur when this method is called. |
|
1045 |
|
1046 @panic FBuf64 4 In _DEBUG mode - negative aNewFilePos value. |
|
1047 |
|
1048 @see RFileBuf64::Write() |
|
1049 @see RFileBuf64::DoFileWrite() |
|
1050 @see RFileBuf64::DoFileWrite1() |
|
1051 @see RFileBuf64::Invariant() |
|
1052 */ |
|
1053 TInt RFileBuf64::DoFileWrite2(TInt64 aNewFilePos) |
|
1054 { |
|
1055 __FBUF64_ASSERT(aNewFilePos >= 0, EFBufPanicFilePos); |
|
1056 __FILEBUF64_INVARIANT(); |
|
1057 TInt err = KErrNone; |
|
1058 if(iDirty) |
|
1059 { |
|
1060 err = DoFileWrite(); |
|
1061 } |
|
1062 if(err == KErrNone) |
|
1063 { |
|
1064 iFilePos = aNewFilePos; |
|
1065 iLength = 0; |
|
1066 } |
|
1067 iDirty = EFalse; |
|
1068 __FILEBUF64_INVARIANT(); |
|
1069 return err; |
|
1070 } |
|
1071 |
|
1072 /** |
|
1073 This function discards the buffer content if the buffer contains cached read data. |
|
1074 The function is called from RFileBuf64::Write(), because if the buffer contains cached read data, |
|
1075 they cannot be mixed with the cached write data. |
|
1076 Reason: for example the buffer contains 8Kb cached read data from file offset 0. |
|
1077 The data write request is 10 bytes at offset 4000. The write data will be cached, |
|
1078 because the buffer contains data from from this file area: [0..8192]. |
|
1079 The iDirty flag will be set. Later when RFileBuf64::Flush() is called, the whole |
|
1080 8Kb buffer will be written. There is nothing wrong with that, the file content will be consistent. |
|
1081 But from performance point of view: 8Kb written vs. 10 bytes written - that may badly impact the performance. |
|
1082 |
|
1083 @see RFileBuf64::Write() |
|
1084 |
|
1085 See RFileBuf64::Invariant() for other possible panics that may occur when this method is called. |
|
1086 */ |
|
1087 void RFileBuf64::DoDiscardBufferedReadData() |
|
1088 { |
|
1089 __FILEBUF64_INVARIANT(); |
|
1090 if(!iDirty && iLength > 0) |
|
1091 { |
|
1092 iLength = 0; |
|
1093 iFilePos = 0; |
|
1094 iNextReadFilePos = KNextReadFilePosNotSet; |
|
1095 iNextReadFilePosHits = 0; |
|
1096 } |
|
1097 __FILEBUF64_INVARIANT(); |
|
1098 } |
|
1099 |
|
1100 #ifdef _DEBUG |
|
1101 |
|
1102 /** |
|
1103 RFileBuf64 invariant. Called in _DEBUG mode at the beginning and before the end of every RFileBuf64 method |
|
1104 (except the init/destroy methods). |
|
1105 |
|
1106 @panic FBuf64 11 In _DEBUG mode - null "this" pointer. |
|
1107 @panic FBuf64 1 In _DEBUG mode - negative iCapacity value. |
|
1108 @panic FBuf64 2 In _DEBUG mode - the buffer pointer is null (possible the buffer is not allocated or already destroyed). |
|
1109 @panic FBuf64 3 In _DEBUG mode - invalid iLength value (negative or bigger than iCapacity). |
|
1110 @panic FBuf64 4 In _DEBUG mode - negative iFilePos value. |
|
1111 @panic FBuf64 5 In _DEBUG mode - set but negative iFileSize value. |
|
1112 @panic FBuf64 6 In _DEBUG mode - null file handle (the RFile64 object is not created or already destroyed). |
|
1113 @panic FBuf64 13 In _DEBUG mode - set but negative iNextReadFilePos value. |
|
1114 @panic FBuf64 14 In _DEBUG mode - negative iNextReadFilePosHits value. |
|
1115 @panic FBuf64 15 In _DEBUG mode - iReadAheadSize is negative or is not power of two. |
|
1116 */ |
|
1117 void RFileBuf64::Invariant() const |
|
1118 { |
|
1119 __FBUF64_ASSERT(this != 0, EFBufPanicNullThis); |
|
1120 __FBUF64_ASSERT(iCapacity > 0, EFBufPanicCapacity); |
|
1121 __FBUF64_ASSERT(iBase != 0, EFBufPanicNullBuf); |
|
1122 __FBUF64_ASSERT(iLength >= 0 && iLength <= iCapacity, EFBufPanicBufLen); |
|
1123 __FBUF64_ASSERT(iFilePos >= 0, EFBufPanicFilePos); |
|
1124 __FBUF64_ASSERT(iFileSize == KFileSizeNotSet || iFileSize >= 0, EFBufPanicFileSize); |
|
1125 __FBUF64_ASSERT(iFile.SubSessionHandle() != 0, EFBufPanicFileHandle); |
|
1126 __FBUF64_ASSERT(iNextReadFilePos == KNextReadFilePosNotSet || iNextReadFilePos >= 0, EFBufPanicNextReadFilePos); |
|
1127 __FBUF64_ASSERT(iNextReadFilePosHits >= 0, EFBufPanicNextReadFilePosHits); |
|
1128 __FBUF64_ASSERT(iReadAheadSize > 0 && (iReadAheadSize & (iReadAheadSize - 1)) == 0, EFBufPanicFileBlockSize); |
|
1129 } |
|
1130 |
|
1131 #endif |