First public contribution.
1 // Copyright (c) 1995-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 the License "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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
17 #include "sf_file_cache.h"
20 #if defined(_DEBUG) || defined(_DEBUG_RELEASE)
22 TInt OutputTraceInfo(CFsRequest* aRequest,TCorruptNameRec* aNameRec)
26 TBool nameUnknown=EFalse;
27 TInt r=aRequest->Message().Client(tT,EOwnerThread);
55 TPtrC t(aRequest->Src().FullName());
56 // output a message via the debug port
57 RDebug::Print(_L("@@@@ Corrupt file check %S tried to open %S"),&n,&t);
58 // make a new log record & chain it in
59 TCorruptLogRec* pLogRec= new TCorruptLogRec;
63 if(pLogRec->Construct(aNameRec,&nPtr,gCorruptLogRecordList)!=KErrNone)
70 gCorruptLogRecordList=pLogRec;
71 // really a count of number of log records
72 gNumberOfCorruptHits++;
77 TCorruptLogRec::TCorruptLogRec()
78 :iProcessName(NULL),iNameRec(NULL),iNext(NULL)
81 TCorruptLogRec::~TCorruptLogRec()
82 { // free off name memory
87 void TCorruptLogRec::DestroyList()
89 TCorruptLogRec* pList=gCorruptLogRecordList;
93 TCorruptLogRec* pThis=pList;
97 gCorruptLogRecordList=NULL;
98 gNumberOfCorruptHits=0;
101 TInt TCorruptLogRec::Construct(TCorruptNameRec* aNameRec, TPtrC* aProcessName, TCorruptLogRec* aChain)
103 iProcessName=aProcessName->Alloc();
104 if(iProcessName==NULL)
112 TInt TCorruptLogRec::GetLogRecord(TFsDebugCorruptLogRecordBuf& aLogRecord,TInt aLogRecNum)
118 else if(aLogRecNum>gNumberOfCorruptHits)
123 TCorruptLogRec* pList=gCorruptLogRecordList;
125 for(TInt i=1;i<aLogRecNum && pList!=NULL;i++)
134 aLogRecord().iProcessName=pList->iProcessName->Des();
135 aLogRecord().iFileName=pList->iNameRec->Name();
136 aLogRecord().iError=pList->iNameRec->ReturnCode();
143 TCorruptNameRec::TCorruptNameRec()
144 :iName(NULL),iNext(NULL){}
146 TInt TCorruptNameRec::Construct(TPtr* aName,TInt aReturnCode, TBool aUseOnce, TCorruptNameRec* aChain)
148 iName=aName->Alloc();
151 iReturnCode=aReturnCode;
158 void TCorruptNameRec::ResetListConsumed()
160 TCorruptNameRec* pList=gCorruptFileNameList;
163 pList->iConsumed=EFalse;
168 LOCAL_C void checkCorruptNamesList(CFsRequest* aRequest, TInt &aError)
171 TPtrC path(aRequest->Src().FullName());
172 TCorruptNameRec* pList=gCorruptFileNameList;
175 if(pList->Name().MatchF(path)==0)
177 if(!pList->Consumed())
179 aError=pList->ReturnCode();
180 pList->SetConsumed();
181 OutputTraceInfo(aRequest,pList);
191 LOCAL_C TInt DoInitNoParse(CFsRequest* aRequest)
193 // Common init for read and write access to files
196 CFileShare* share = GetShareFromHandle(aRequest->Session(), aRequest->Message().Int3());
198 return(KErrBadHandle);
199 aRequest->SetDrive(&share->File().Drive());
200 aRequest->SetScratchValue64( MAKE_TINT64(ETrue, (TUint) share) );
204 _LIT(KDrivePath,"?:");
205 LOCAL_C TInt DoInitialise(CFsRequest* aRequest)
207 // Common initialisation code use file share to determine asychronicity
210 CFileShare* share = GetShareFromHandle(aRequest->Session(), aRequest->Message().Int3());
212 return(KErrBadHandle);
213 aRequest->SetDrive(&share->File().Drive());
214 aRequest->SetScratchValue64( MAKE_TINT64(ETrue, (TUint) share) );
215 TBuf<2> drive(KDrivePath);
216 drive[0]=TText(aRequest->DriveNumber()+'A');
217 aRequest->Src().Set(share->File().FileName(),NULL,&drive);
221 LOCAL_C TInt InitialiseScratchToShare(CFsRequest* aRequest)
223 // Common code used to initialise the scratch value to the CFileShare* from the request
226 CFileShare* share=GetShareFromHandle(aRequest->Session(), aRequest->Message().Int3());
228 return(KErrBadHandle);
229 aRequest->SetScratchValue64( MAKE_TINT64(ETrue, (TUint) share) );
234 LOCAL_C TInt FsFileOpenL(CFsRequest* aRequest, TFileOpen anOpen)
241 TUint32 mode=aRequest->Message().Int1();
242 if (anOpen==EFileCreate || anOpen==EFileReplace)
244 r = CheckDiskSpace(0, aRequest);
252 r=aRequest->Drive()->FileOpen(aRequest,h,aRequest->Src().FullName().Mid(2),mode,anOpen);
256 TPtrC8 pH((TUint8*)&h,sizeof(TInt));
257 TRAP(r, aRequest->WriteL(KMsgPtr3,pH))
258 CheckForLeaveAfterOpenL(r, aRequest, h);
259 aRequest->Session()->IncResourceCount();
264 TInt TFsFileOpen::DoRequestL(CFsRequest* aRequest)
269 __PRINT(_L("TFsFileOpen::DoRequestL(CFsRequest* aRequest)"));
270 return FsFileOpenL(aRequest, EFileOpen);
273 TInt TFsFileCreate::DoRequestL(CFsRequest* aRequest)
279 __PRINT(_L("TFsFileCreate::DoRequestL(CFsRequest* aRequest)"));
280 return FsFileOpenL(aRequest, EFileCreate);
283 TInt TFsFileCreate::Initialise(CFsRequest* aRequest)
288 TInt r=ParseNoWildSubstCheckPtr0(aRequest,aRequest->Src());
291 r=PathCheck(aRequest,aRequest->Src().FullName().Mid(2),&KCapFsSysFileCreate,&KCapFsPriFileCreate,&KCapFsROFileCreate, __PLATSEC_DIAGNOSTIC_STRING("Create File"));
294 if (OpenOnDriveZOnly)
296 aRequest->SetDrive(&TheDrives[EDriveZ]);
297 aRequest->SetSubstedDrive(NULL);
304 TInt TFsFileReplace::DoRequestL(CFsRequest* aRequest)
309 __PRINT(_L("TFsFileReplace::DoRequestL(CFsRequest* aRequest)"));
310 return FsFileOpenL(aRequest, EFileReplace);
313 TInt TFsFileReplace::Initialise(CFsRequest* aRequest)
318 TInt r=ParseNoWildSubstCheckPtr0(aRequest,aRequest->Src());
321 r=PathCheck(aRequest,aRequest->Src().FullName().Mid(2),&KCapFsSysFileReplace,&KCapFsPriFileReplace,&KCapFsROFileReplace, __PLATSEC_DIAGNOSTIC_STRING("Replace File"));
325 if (OpenOnDriveZOnly) // Yuck! yet another global
327 aRequest->SetDrive(&TheDrives[EDriveZ]);
328 aRequest->SetSubstedDrive(NULL);
334 #ifdef __REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__
336 #define __PLATSEC_DIAGNOSTIC_MESSAGE(s) NULL
337 static const TInt KMsgBuffSize = KMaxPath;
341 #if defined(_UNICODE) && !defined(__KERNEL_MODE__)
343 static const TInt KCharMsgMaxLen = KMaxPath - 1;
344 static const TInt KMsgBuffSize = KMaxPath;
348 static const TInt KCharMsgMaxLen = 50;
349 static const TInt KMsgBuffSize = KMaxPath + KMsgMaxLen + 1;
351 #endif // #if defined(_UNICODE) && !defined(__KERNEL_MODE__)
353 // Local function to format a message
355 const char* FmtPlatSecMessage(TBufC<KMsgBuffSize>& buff, CFsRequest& req, const char* str)
357 char* p = (char*)buff.Ptr();
358 const char* const base = p;
359 // copy message string (if any)
362 while(*str && p < &base[KCharMsgMaxLen - 2]) // 2 for trailing ": "
368 const TDesC& fname = req.Src().FullName();
369 const TInt end = Min(fname.Length(),
370 KMsgBuffSize * sizeof(*buff.Ptr()) - (p - base) - 1);
371 for(TInt i = 0; i < end; ++i)
372 *p++ = (char)fname[i];
377 #define __PLATSEC_DIAGNOSTIC_MESSAGE(s) FmtPlatSecMessage(thisPath, *aRequest, s)
379 #endif // #ifdef __REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__
382 TInt TFsFileOpen::Initialise(CFsRequest* aRequest)
384 // Parse and execute FileOpen service otherwise sets flag for
385 // asynchronous service
388 TInt r=ParseNoWildSubstCheckPtr0(aRequest,aRequest->Src());
392 TBufC<KMsgBuffSize> thisPath(aRequest->Src().FullName().Mid(2));
393 TUint32 mode = (aRequest->Message().Int1() & ~(EFileStreamText | EFileReadAsyncAll | EFileBigFile));
395 #if defined(_DEBUG) || defined(_DEBUG_RELEASE)
396 // see if file is on our "Most Wanted" list
398 checkCorruptNamesList(aRequest,errorCode);
399 if(errorCode!=KErrNone)
405 CFsMessageRequest* msgRequest = (CFsMessageRequest*)aRequest;
406 if (OpenOnDriveZOnly)
408 aRequest->SetDrive(&TheDrives[EDriveZ]);
409 aRequest->SetSubstedDrive(NULL);
412 if(msgRequest->IsPluginRequest())
414 // Always allow plugins to open files, regardless of the clients policy
418 if(ComparePrivate(thisPath))
420 if(! SIDCheck(aRequest,thisPath))
422 if(!KCapFsPriFileOpen.CheckPolicy(aRequest->Message(), __PLATSEC_DIAGNOSTIC_MESSAGE("File Open in private path")))
423 return KErrPermissionDenied;
426 else if(CompareResource(thisPath))
428 if(mode != EFileShareReadersOrWriters && mode != EFileShareReadersOnly && mode != EFileRead)
429 // File opening mode EFileShareReadersOrWriters|EFileRead will fail the above test and not
430 // be checked for policy, whereas file opening mode EFileShareReadersOrWriters|EFileWrite
431 // will pass the test and will be checked for policy.
432 // EFileRead is 0 whereas EFileWrite is non 0.
434 if(!KCapFsROFileOpenWr.CheckPolicy(aRequest->Message(), __PLATSEC_DIAGNOSTIC_MESSAGE("File Open in resource path")))
435 return KErrPermissionDenied;
438 else if(CompareSystem(thisPath))
440 if(!(mode & EFileShareReadersOnly) && (mode & EFileWrite))
442 if(!KCapFsSysFileOpenWr.CheckPolicy(aRequest->Message(), __PLATSEC_DIAGNOSTIC_MESSAGE("File Open in system path")))
443 return KErrPermissionDenied;
447 if(!KCapFsSysFileOpenRd.CheckPolicy(aRequest->Message(), __PLATSEC_DIAGNOSTIC_MESSAGE("File Open in system path")))
448 return KErrPermissionDenied;
455 #undef __PLATSEC_DIAGNOSTIC_MESSAGE
457 TInt TFsIsFileOpen::DoRequestL(CFsRequest* aRequest)
459 // Return whether a file is open or not
463 __PRINT(_L("TFsIsFileOpen::DoRequestL(CFsRequest* aRequest)"));
465 TInt r=aRequest->Drive()->IsFileOpen(aRequest->Src().FullName().Mid(2),file);
468 TBool isOpen = file?(TBool)ETrue:(TBool)EFalse;
469 TPtrC8 pA((TUint8*)&isOpen,sizeof(TBool));
470 aRequest->WriteL(KMsgPtr1,pA);
474 TInt TFsIsFileOpen::Initialise(CFsRequest* aRequest)
479 TInt r=ParseNoWildSubstCheckPtr0(aRequest,aRequest->Src());
482 r=PathCheck(aRequest,aRequest->Src().FullName().Mid(2),&KCapFsSysIsFileOpen,&KCapFsPriIsFileOpen, __PLATSEC_DIAGNOSTIC_STRING("Is File Open"));
487 TInt TFsListOpenFiles::DoRequestL(CFsRequest* aRequest)
493 __PRINT(_L("TFsListOpenFiles::DoRequestL(CFsRequest* aRequest)"));
495 TOpenFileListPos listPos;
496 TPckg<TOpenFileListPos> listPkg(listPos);
497 aRequest->ReadL(KMsgPtr0,listPkg);
498 TBuf8<KEntryArraySize> entryArray(0);
501 TPckgC<TThreadId> id(idClient);
504 TBool fileFound=(listPos.iEntryListPos) ? (TBool)ETrue : EFalse;
510 session=(*TheFileServer)[listPos.iSession]; //this global may not be the best way AJ
513 session->Handles().Lock();
514 count=session->Handles().Count();
517 session->Handles().Unlock();
521 entryListPos=listPos.iEntryListPos;
522 while (entryListPos<count)
524 CObjPromotion* obj=(CObjPromotion*)session->Handles()[entryListPos];
525 if (obj==NULL || obj->UniqueID()!=FileShares->UniqueID())
528 continue; // Is not a CFileShare
530 CFileCB& fileCb=((CFileShare*)obj)->File();
533 // Set kEntryAttPacked to indicate it is in packed form
534 fileEntry.iAtt=fileCb.Att() | KEntryAttPacked;
535 TInt64 fileSize = fileCb.Size64();
536 fileEntry.iSize = I64LOW(fileSize);
537 fileEntry.iModified=fileCb.Modified();
538 fileEntry.iName=fileCb.FileName();
540 // Pack - Copy iSizeHigh and reset iReserved in packed form
541 TUint32* pSizeHigh = PtrAdd((TUint32*)&fileEntry, EntrySize(fileEntry, EFalse));
543 *pSizeHigh++ = I64HIGH(fileSize); // Copy iSizeHigh
544 *pSizeHigh = 0; // Reset iReserved
546 TInt entrySize=EntrySize(fileEntry, ETrue);
547 if (entryArray.Length()+entrySize>entryArray.MaxLength())
549 TPtrC8 pfileEntry((TUint8*)&fileEntry,entrySize);
550 entryArray.Append(pfileEntry);
553 idClient = session->ThreadId();
554 session->Handles().Unlock();
556 if (entryArray.Length()==0)
558 if (fileFound==EFalse && entryArray.Length()==0)
560 listPos.iEntryListPos=entryListPos;
563 aRequest->WriteL(KMsgPtr1,id);
564 aRequest->WriteL(KMsgPtr0,listPkg);
565 aRequest->WriteL(KMsgPtr2,entryArray);
569 TInt TFsListOpenFiles::Initialise(CFsRequest* /*aRequest*/)
577 LOCAL_C void FsFileTempFinishL(CFsRequest* aRequest,TFileName& aN,TInt aH)
580 aRequest->WriteL(KMsgPtr2,aRequest->Src().Drive());
581 aRequest->WriteL(KMsgPtr2,aN,2);
582 TPtrC8 pH((TUint8*)&aH,sizeof(TInt));
583 aRequest->WriteL(KMsgPtr3,pH);
586 TInt TFsFileTemp::DoRequestL(CFsRequest* aRequest)
588 // Create a temporary file.
591 __PRINT(_L("TFsFileTemp::DoRequestL(CFsRequest* aRequest)"));
593 TInt r = CheckDiskSpace(0, aRequest);
599 r=aRequest->Drive()->FileTemp(aRequest,h,aRequest->Src().FullName().Mid(2),n,aRequest->Message().Int1());
603 TRAP(r, FsFileTempFinishL(aRequest,n,h))
604 CheckForLeaveAfterOpenL(r,aRequest,h);
605 aRequest->Session()->IncResourceCount();
610 TInt TFsFileTemp::Initialise(CFsRequest* aRequest)
615 TInt r=ParseNoWildSubstPtr0(aRequest,aRequest->Src());
618 r=PathCheck(aRequest,aRequest->Src().FullName().Mid(2),&KCapFsSysFileTemp,&KCapFsPriFileTemp,&KCapFsROFileTemp, __PLATSEC_DIAGNOSTIC_STRING("Temp File"));
621 if (aRequest->Src().NameOrExtPresent())
627 TInt TFsFileRead::DoRequestL(CFsRequest* aRequest)
633 __PRINT(_L("TFsFileRead::DoRequestL(CFsRequest* aRequest)"));
634 __PRINT1(_L("aRequest->Session() = 0x%x"),aRequest->Session());
636 CFsMessageRequest& msgRequest = *(CFsMessageRequest*) aRequest;
637 __ASSERT_DEBUG(msgRequest.CurrentOperationPtr() != NULL, Fault(EBadOperationIndex));
638 TMsgOperation& currentOperation = msgRequest.CurrentOperation();
642 GetFileFromScratch(aRequest, share, file);
644 TInt r = file->CheckMount();
645 __PRINT1(_L("share->CheckMount() returned = %d"),r);
649 TInt& len = currentOperation.iReadWriteArgs.iLength;
650 TInt& totalLen = currentOperation.iReadWriteArgs.iTotalLength;
651 TInt64 pos = currentOperation.iReadWriteArgs.iPos;
652 TInt& offset = currentOperation.iReadWriteArgs.iOffset;
655 // Needs extended file API to work (so that we can sepcify an offset)
656 // Also needs a separate drive thread to prevent excessive stack usage
657 len = Min(len, totalLen);
658 if (file->ExtendedFileInterfaceSupported() && !FsThreadManager::IsDriveSync(aRequest->DriveNumber(), EFalse))
660 len = Min(len, file->FairSchedulingLen());
662 if (pos == KCurrentPosition64)
665 currentOperation.iReadWriteArgs.iPos = pos;
667 __ASSERT_DEBUG(len > 0, Fault(EInvalidReadLength));
668 __ASSERT_DEBUG(len <= totalLen, Fault(EInvalidReadLength));
670 // The mount and any extensions must all support local buffers in order to support
671 // internally generated requests (ie - requests originating from plugins)
672 if ((aRequest->Message().Handle() == KLocalMessageHandle || !currentOperation.iClientRequest) && !file->LocalBufferSupport())
674 r = KErrNotSupported;
680 if (currentOperation.iClientRequest)
682 // Current operation points to a descriptor
683 // The request originated from a client (with a normal message handle) or a plugin (KLocalMessageHandle)
684 TRAP(r,file->ReadL(pos, len, (TPtr8*) aRequest->Message().Ptr0(), aRequest->Message(), offset))
688 // Current operation points to a local buffer
689 // The request originated from the file server (e.g. file cache) with a local message handle (KLocalMessageHandle)
690 TPtr8 dataDesc((TUint8*) currentOperation.iReadWriteArgs.iData + currentOperation.iReadWriteArgs.iOffset, len, len);
691 const RLocalMessage msg;
692 TRAP(r,file->ReadL(pos, len, &dataDesc, msg, 0));
697 #if defined(_DEBUG) || defined(_DEBUG_RELEASE)
698 CCacheManager* manager = CCacheManagerFactory::CacheManager();
701 manager->Stats().iUncachedPacketsRead++;
702 manager->Stats().iUncachedBytesRead+= len;
706 //RDebug::Print(_L("ReadR: req %08X pos %ld\t len %d file %08X\n"), aRequest, pos, len, file);
709 #if defined (_DEBUG_READ_AHEAD)
710 RDebug::Print(_L("ReadR: req %08X pos %ld\t len %d nextPos %ld file %08X\n"), aRequest, pos, len, pos + len, file);
714 currentOperation.iReadWriteArgs.iPos+= len;
718 // update the file share's position IF this request came from the client
719 if (share && r==KErrNone && currentOperation.iClientRequest)
721 __e32_atomic_store_ord64(&share->iPos, pos + len);
724 // re-issue request if not complete (to support fair scheduling)
725 if (r == KErrNone && totalLen > 0)
726 return CFsRequest::EReqActionBusy; // dispatch request again to back of queue
732 TInt TFsFileRead::Initialise(CFsRequest* aRequest)
737 CFsMessageRequest& msgRequest = *(CFsMessageRequest*) aRequest;
739 TInt r = DoInitNoParse(aRequest);
745 GetFileFromScratch(aRequest, share, file);
747 TMsgOperation* msgOp = msgRequest.CurrentOperationPtr();
748 if (!msgOp) // initialised already ?
750 r = msgRequest.PushOperation(TFsFileRead::Complete);
753 msgOp = msgRequest.CurrentOperationPtr();
755 // try to serialize requests to prevent asynchronous requests being processed out of sequence -
756 // this isn't possible if a plugin is loaded as this may issue it's own requests
757 if (!share->RequestStart(&msgRequest))
758 return CFsRequest::EReqActionPending;
760 TDrive& drive = share->File().Drive();
765 reqLen = len = aRequest->Message().Int1();
767 if(aRequest->IsDescData(KMsgPtr2))
768 {//-- 64-bit file addressing, absolute read position is TInt64
769 TPckg<TInt64> pkPos(reqPos);
770 aRequest->ReadL(KMsgPtr2, pkPos);
774 if(aRequest->Message().Int2() == (TInt)I64LOW(KCurrentPosition64))
775 reqPos = KCurrentPosition64; // Position is KCurrentPosition64 (-1)
776 else //-- legacy, RFile addressing
777 reqPos = MAKE_TINT64(0,aRequest->Message().Int2()); // Position is absolute value < 4GB, it's TUint
780 msgOp->iClientPosition = pos = reqPos;
786 return CFsRequest::EReqActionComplete;
788 if (pos == KCurrentPosition64)
791 const TInt64 fileSize = file->CachedSize64();
795 if ((r = file->CheckLock64(share,pos,len)) != KErrNone)
799 TDes8* pD = (TDes8*) aRequest->Message().Ptr0();
801 if((share->iMode & EFileReadAsyncAll) && (aRequest->Message().ClientStatus() != NULL))
804 if (pos + len > fileSize)
806 r = share->File().AddAsyncReadRequest(share, reqPos, reqLen, aRequest);
808 return (r == KErrNone)?CFsRequest::EReqActionComplete:r;
815 __e32_atomic_store_ord64(&share->iPos, pos);
816 r = aRequest->Write(KMsgPtr0, KNullDesC8);
817 return(r == KErrNone?CFsRequest::EReqActionComplete:r);
820 if (pos + len > fileSize)
822 // filesize - pos shall of TInt size
823 // Hence to suppress warning
824 len = (TInt)(fileSize - pos);
827 msgOp->Set(pos, len, (TDesC8*) pD);
829 //RDebug::Print(_L("ReadI: req %08X pos %ld\t len %d file %08X\n"), aRequest, pos, len, file);
831 #if defined (_DEBUG_READ_AHEAD)
832 RDebug::Print(_L("ReadI: req %08X pos %ld\t len %d file %08X\n"), aRequest, pos, len, file);
838 TInt TFsFileRead::PostInitialise(CFsRequest* aRequest)
840 CFileShare* share = (CFileShare*) aRequest->ScratchValue();
841 CFileCB* file = &share->File();
844 CFileCache* fileCache = file->FileCache();
847 r = fileCache->ReadBuffered(*(CFsMessageRequest*)aRequest, share->iMode);
849 // if we're not reading from cache, force read ahead position & length to be recalculated
851 fileCache->ResetReadAhead();
857 TInt TFsFileRead::Complete(CFsRequest* aRequest)
859 // RDebug::Print(_L("TFsFileRead::Complete() aRequest %08X"), aRequest);
861 CFsMessageRequest& msgRequest = *(CFsMessageRequest*) aRequest;
865 GetFileFromScratch(aRequest, share, file);
867 // Flag the request as having ended to allow another async read to occur
868 share->RequestEnd(&msgRequest);
872 CFileCache* fileCache = file->FileCache();
873 if (fileCache && msgRequest.LastError() == KErrNone)
874 fileCache->ReadAhead(msgRequest, share->iMode);
876 return CFsRequest::EReqActionComplete;
880 void GetFileFromScratch(CFsRequest* aRequest, CFileShare*& aShare, CFileCB*& aFile)
883 TInt64 scratchValue = aRequest->ScratchValue64();
884 TBool scratchValueIsShare I64HIGH(scratchValue);
885 TUint32 scratchValueLow = I64LOW(scratchValue);
890 if (scratchValueIsShare)
892 aShare = (CFileShare*) scratchValueLow;
894 aFile = &aShare->File();
898 aFile = (CFileCB*) scratchValueLow;
903 Common init preamble for TFsFileWrite::Initialise() and TFsFileWrite::DoRequestL()
905 @param aShare pointer to the file share
906 @param aFile pointer to the file object this function is called for
907 @param aPos file position to write data. Note that it can be KCurrentPosition64 i.e. KMaxTUint64
908 @param aLen length of the data to write
909 @param aFileSize current file size
910 @param aFsOp File Server message code. See TFsMessage. It must be ether EFsFileWrite for normal write, or EFsFileWriteDirty when file cache flushes dirty data
913 TInt TFsFileWrite::CommonInit(CFileShare* aShare, CFileCB* aFile, TInt64& aPos, TInt& aLen, TInt64 aFileSize, TFsMessage aFsOp)
916 if (aShare && aPos==KCurrentPosition64)
917 {//-- write to the current position in the file
924 //-- check that the new position won't exceed maximum file size
926 const TUint64 endPos = aPos+aLen;
928 //-- Large file mode check. Legacy RFile size can't exceed 2G-1
929 if(aShare && !(aShare->IsFileModeBig()) && (endPos > KMaxLegacyFileSize))
932 //-- check CMountCB limitation on maximum file size
933 if(endPos > aFile->MaxSupportedSize())
934 return KErrNotSupported; //-- this is for the sake of error codes consistency; current FSYs return
935 //-- this code in the case of accessing a file beyond its limit
941 if ((r=aFile->CheckLock64(aShare,aPos,aLen))!=KErrNone)
945 ASSERT(aFsOp == EFsFileWrite || aFsOp == EFsFileWriteDirty);
946 if(aFsOp == EFsFileWrite)
947 {//-- this call is originated from explicit file write operation. Set 'Archive' attribute and new file time.
948 aFile->SetArchiveAttribute(); //-- it will also set KEntryAttModified
951 {//-- don't touch data and attributes if it is cache flushing dirty data
952 aFile->iAtt |= KEntryAttModified;
959 void TFsFileWrite::CommonEnd(CFsMessageRequest* aMsgRequest, TInt aRetVal, TUint64 aInitSize, TUint64 aNewSize, TInt64 aNewPos, TBool aFileWrite)
961 // Common end for TFsFileWrite::DoRequestL() and CFileCache::WriteBuffered()
967 GetFileFromScratch(aMsgRequest, share, file);
968 CFileCache* fileCache = file->FileCache();
969 ASSERT(aFileWrite || fileCache);
971 TMsgOperation& currentOperation = aMsgRequest->CurrentOperation();
973 if (aRetVal == KErrNone || aRetVal == CFsRequest::EReqActionComplete)
977 __e32_atomic_store_ord64(&share->iPos, aNewPos);
980 if ((TUint64)aNewPos > aNewSize)
983 file->SetSize64(aNewPos, EFalse);
985 fileCache->SetSize64(aNewPos);
989 // ensure cached file is at least as big as uncached file
990 if (fileCache && fileCache->Size64() < aNewPos)
992 file->SetCachedSize64(aNewPos);
995 // Service async reads if the file has grown & this is the last fair-scheduled request
997 // If the file has grown, flag this and call CFileCB::NotifyAsyncReaders()
998 // later in TFsFileWrite::Complete() - we need to delay the call because
999 // CFileCB::NotifyAsyncReaders() may requeue a request which will cause
1000 // the drive thread to spin because this file share is still marked as in use
1001 // (by CFileShare::RequestStart())
1002 if((aNewSize > aInitSize) && (currentOperation.iReadWriteArgs.iTotalLength == 0))
1004 file->SetNotifyAsyncReadersPending(ETrue);
1007 file->iAtt |= KEntryAttModified;
1010 else if (aRetVal == KErrCorrupt)
1011 file->SetFileCorrupt(ETrue);
1012 else if (aRetVal == KErrBadPower || (aRetVal == KErrAbort && !PowerOk()))
1013 file->SetBadPower(ETrue);
1015 file->ResetReadAhead();
1016 aMsgRequest->SetFreeChanged(aNewSize != aInitSize);
1019 TInt TFsFileWrite::DoRequestL(CFsRequest* aRequest)
1024 __PRINT(_L("TFsFileWrite::DoRequestL(CFsRequest* aRequest)"));
1026 CFsMessageRequest& msgRequest = *(CFsMessageRequest*) aRequest;
1027 __ASSERT_DEBUG(msgRequest.CurrentOperationPtr() != NULL, Fault(EBadOperationIndex));
1028 TMsgOperation& currentOperation = msgRequest.CurrentOperation();
1034 GetFileFromScratch(aRequest, share, file);
1036 TInt64 initSize = file->Size64();
1038 r = file->CheckMount();
1043 TInt& len = currentOperation.iReadWriteArgs.iLength;
1045 // Fair scheduling -
1046 // Needs extended file API to work (so that we can specify an offset)
1047 // Also needs a separate drive thread to prevent excessive stack usage
1048 len = Min(len, currentOperation.iReadWriteArgs.iTotalLength);
1049 if (file->ExtendedFileInterfaceSupported() && !FsThreadManager::IsDriveSync(aRequest->DriveNumber(), EFalse))
1051 len = Min(len, file->FairSchedulingLen());
1054 __ASSERT_DEBUG(len <= currentOperation.iReadWriteArgs.iTotalLength, Fault(EInvalidWriteLength));
1057 const TFsMessage fsOp = (TFsMessage)aRequest->Operation()->Function();
1058 r = CommonInit(share, file, currentOperation.iReadWriteArgs.iPos, len, initSize, fsOp);
1063 TInt64 pos = currentOperation.iReadWriteArgs.iPos;
1065 TInt64 upos = pos+len;
1066 if (upos > initSize)
1068 r = CheckDiskSpace(upos - initSize, aRequest);
1073 // The mount and any extensions must all support local buffers in order to support
1074 // internally generated requests (ie - requests originating from plugins)
1075 if ((aRequest->Message().Handle() == KLocalMessageHandle || !currentOperation.iClientRequest) && !file->LocalBufferSupport())
1077 r = KErrNotSupported;
1082 if (currentOperation.iClientRequest)
1084 TRAP(r,file->WriteL(pos, len, (const TPtrC8*) aRequest->Message().Ptr0(), aRequest->Message(), currentOperation.iReadWriteArgs.iOffset))
1088 TPtr8 dataDesc((TUint8*) currentOperation.iReadWriteArgs.iData + currentOperation.iReadWriteArgs.iOffset, len, len);
1089 const RLocalMessage msg;
1090 TRAP(r,file->WriteL(pos, len, &dataDesc, msg, 0));
1094 //RDebug::Print(_L("WriteR: req %08X pos %ld\t len %d file %08X\n"), aRequest, pos, len, file);
1096 #if defined(_DEBUG) || defined(_DEBUG_RELEASE)
1097 CCacheManager* manager = CCacheManagerFactory::CacheManager();
1100 manager->Stats().iUncachedPacketsWritten++;
1101 manager->Stats().iUncachedBytesWritten+= len;
1107 // update position, offset & length remaining
1108 currentOperation.iReadWriteArgs.iOffset+= len;
1109 currentOperation.iReadWriteArgs.iPos+= len;
1110 currentOperation.iReadWriteArgs.iTotalLength-= len;
1112 TUint64 currentSize = MAKE_TUINT64(file->iBody->iSizeHigh,file->iSize);
1113 CommonEnd(&msgRequest, r, initSize, currentSize, pos+len, ETrue);
1115 // re-issue request if not complete (to support fair scheduling)
1116 if (r == KErrNone && currentOperation.iReadWriteArgs.iTotalLength > 0)
1117 return CFsRequest::EReqActionBusy; // dispatch request again to back of queue
1122 TInt TFsFileWrite::Initialise(CFsRequest* aRequest)
1127 CFsMessageRequest& msgRequest = *(CFsMessageRequest*) aRequest;
1129 TInt r = DoInitNoParse(aRequest);
1133 // If the drive has been dismounted, don't even attempt to write to the file as that
1134 // will create dirty data which can then not be flushed without hitting ASSERTs etc.
1135 if (!FsThreadManager::IsDriveAvailable(aRequest->DriveNumber(), EFalse))
1136 return KErrNotReady;
1140 GetFileFromScratch(aRequest, share, file);
1142 // Bail out if there's a new mount which isn't ours - this would fail
1143 // later on anyway when TFsFileWrite::DoRequestL() called CFileCB::CheckMount()
1144 if ( !file->Drive().IsCurrentMount(file->Mount()) )
1145 return KErrDisMounted;
1148 TMsgOperation* msgOp = msgRequest.CurrentOperationPtr();
1149 if (!msgOp) // initialised already ?
1151 r = msgRequest.PushOperation(TFsFileWrite::Complete);
1154 msgOp = msgRequest.CurrentOperationPtr();
1156 // try to serialize requests to prevent asynchronous requests being processed out of sequence -
1157 // this isn't possible if a plugin is loaded as this may issue it's own requests
1158 if (share && !share->RequestStart(&msgRequest))
1159 return CFsRequest::EReqActionPending;
1163 if(aRequest->IsDescData(KMsgPtr2))
1164 {//-- 64-bit file addressing, absolute read position is TInt64
1165 TPckg<TInt64> pkPos(pos);
1166 aRequest->ReadL(KMsgPtr2, pkPos);
1170 if(aRequest->Message().Int2() == (TInt)I64LOW(KCurrentPosition64))
1171 pos = KCurrentPosition64;// Position is KCurrentPosition64 (-1)
1173 pos = MAKE_TINT64(0,aRequest->Message().Int2());// Position is absolute value < 4GB, it's a TUint type
1176 msgOp->iClientPosition = pos;
1177 TInt len = aRequest->Message().Int1();
1179 TDesC8* pD = (TDes8*) aRequest->Message().Ptr0();
1182 return CFsRequest::EReqActionComplete;
1185 return KErrArgument;
1187 //if this request was sent down from a plugin, then we want to
1188 //ignore the mode that the files was opened in.
1189 if (share && !msgRequest.IsPluginRequest())
1191 if ((share->iMode & EFileWrite)==0 ||
1192 (share->iMode & KFileShareMask) == EFileShareReadersOnly)
1194 return(KErrAccessDenied);
1199 const TFsMessage fsOp = (TFsMessage)aRequest->Operation()->Function();
1200 r = CommonInit(share, file, pos, len, file->CachedSize64(), fsOp);
1204 msgOp->Set(pos, len, pD);
1210 TInt TFsFileWrite::PostInitialise(CFsRequest* aRequest)
1212 CFileShare* share = (CFileShare*) aRequest->ScratchValue();
1213 CFileCB* file = &share->File();
1216 CFileCache* fileCache = file->FileCache();
1219 // If there's no data left proceed straight to completion stage
1220 // This can happen when re-posting a completed write request to
1221 // start the dirty data timer
1222 if (((CFsMessageRequest*) aRequest)->CurrentOperation().iReadWriteArgs.iTotalLength == 0)
1223 return CFsRequest::EReqActionComplete;
1225 r = fileCache->WriteBuffered(*(CFsMessageRequest*)aRequest, share->iMode);
1231 TInt TFsFileWrite::Complete(CFsRequest* aRequest)
1233 CFsMessageRequest& msgRequest = *(CFsMessageRequest*) aRequest;
1238 GetFileFromScratch(aRequest, share, file);
1241 share->RequestEnd(&msgRequest);
1243 if (file->NotifyAsyncReadersPending())
1244 file->NotifyAsyncReaders();
1246 return CFsRequest::EReqActionComplete;
1249 TInt TFsFileLock::DoRequestL(CFsRequest* aRequest)
1251 // Lock a region of the file.
1255 __PRINT(_L("TFsFileLock::DoRequestL(CFsRequest* aRequest)"));
1256 CFileShare* share=(CFileShare*)aRequest->ScratchValue();
1258 // We must wait for ALL shares to have no active requests (see RequestStart())
1259 // and post this request to the back of the queue if there are any. This is to
1260 // avoid a fair-scheduled write from writing to a locked region of a file
1261 CSessionFs* session = aRequest->Session();
1264 TBool fileInUse = EFalse;
1265 session->Handles().Lock();
1266 TInt count = session->Handles().Count();
1267 CFileCB* file = &share->File();
1269 for (TInt n=0; n<count; n++)
1271 CObjPromotion* obj = (CObjPromotion*)session->Handles()[n];
1273 obj->UniqueID() == FileShares->UniqueID() &&
1274 (file == &((CFileShare*) obj)->File()) &&
1275 ((CFileShare*) obj)->RequestInProgress())
1277 CFsMessageRequest& msgRequest = *(CFsMessageRequest*)aRequest;
1278 if(msgRequest.IsPluginRequest())
1285 session->Handles().Unlock();
1287 return CFsRequest::EReqActionBusy;
1291 if(aRequest->IsDescData(KMsgPtr0))
1293 TPckg<TInt64> pkPos(pos);
1294 aRequest->ReadL(KMsgPtr0, pkPos);
1298 pos = MAKE_TINT64(0, aRequest->Message().Int0());
1301 if(aRequest->IsDescData(KMsgPtr1))
1303 TPckg<TInt64> pkLength(length);
1304 aRequest->ReadL(KMsgPtr1, pkLength);
1306 User::Leave(ELockLengthZero);
1310 length = aRequest->Message().Int1();
1312 User::Leave(ELockLengthZero);
1314 return(share->File().AddLock64(share, pos, length));
1317 TInt TFsFileLock::Initialise(CFsRequest* aRequest)
1322 return(DoInitNoParse(aRequest));
1326 TInt TFsFileUnlock::DoRequestL(CFsRequest* aRequest)
1328 // Unlock a region of the file.
1331 __PRINT(_L("TFsFileUnlock::DoRequestL(CFsRequest* aRequest)"));
1332 CFileShare* share=(CFileShare*)aRequest->ScratchValue();
1336 if(aRequest->IsDescData(KMsgPtr0))
1338 TPckg<TInt64> pkPos(pos);
1339 aRequest->ReadL(KMsgPtr0, pkPos);
1343 pos = MAKE_TINT64(0, aRequest->Message().Int0());
1346 if(aRequest->IsDescData(KMsgPtr1))
1348 TPckg<TInt64> pkLength(length);
1349 aRequest->ReadL(KMsgPtr1, pkLength);
1351 User::Leave(EUnlockLengthZero);
1355 length = aRequest->Message().Int1();
1357 User::Leave(EUnlockLengthZero);
1359 return(share->File().RemoveLock64(share, pos, length));
1362 TInt TFsFileUnlock::Initialise(CFsRequest* aRequest)
1367 return(DoInitNoParse(aRequest));
1371 TInt TFsFileSeek::DoRequestL(CFsRequest* aRequest)
1373 // Set the file position.
1377 __PRINT(_L("TFsFileSeek::DoRequestL(CFsRequest* aRequest)"));
1378 CFileShare* share=(CFileShare*)aRequest->ScratchValue();
1379 TInt64 size = share->File().CachedSize64();
1381 if(aRequest->IsDescData(KMsgPtr0))
1383 TPckg<TInt64> pkPos(pos);
1384 aRequest->ReadL(KMsgPtr0, pkPos);
1388 pos = aRequest->Message().Int0();
1393 if (share->iPos != pos)
1394 share->File().ResetReadAhead();
1396 switch (aRequest->Message().Int1())
1406 // Large file mode check
1407 if((!(share->IsFileModeBig())) && ((TUint64)pos > KMaxLegacyFileSize))
1408 return (KErrTooBig);
1417 // Large file mode check
1418 if((!(share->IsFileModeBig())) && ((TUint64)pos > KMaxLegacyFileSize))
1419 return (KErrTooBig);
1424 r = share->File().Address(t);
1435 return(KErrArgument);
1437 return(KErrArgument);
1439 __e32_atomic_store_ord64(&share->iPos, pos);
1441 TPckgC<TInt64> pkNewPos(pos);
1442 aRequest->WriteL(KMsgPtr2, pkNewPos);
1446 TInt TFsFileSeek::Initialise(CFsRequest* aRequest)
1451 return(DoInitNoParse(aRequest));
1455 TInt TFsFileFlush::DoRequestL(CFsRequest* aRequest)
1457 // Commit any data in memory to the media.
1461 __PRINT(_L("TFsFileFlush::DoRequestL(CFsRequest* aRequest)"));
1462 CFileShare* share=(CFileShare*)aRequest->ScratchValue();
1464 // if any write requests are being fair scheduled, wait for them to complete
1465 if (share->RequestInProgress())
1466 return CFsRequest::EReqActionBusy;
1468 // flush the write cache
1470 CFileCache* fileCache = share->File().FileCache();
1471 if (fileCache && (r = fileCache->FlushDirty(aRequest)) != CFsRequest::EReqActionComplete)
1473 //To be used in notification framework
1474 //CFsMessageRequest& msgRequest = (CFsMessageRequest&)*aRequest;
1475 //msgRequest.iUID = msgRequest.Message().Identity();
1479 if ((share->File().Att()&KEntryAttModified)==0)
1481 if ((share->iMode&EFileWrite)==0)
1482 return(KErrAccessDenied);
1483 r=share->CheckMount();
1487 TRACE1(UTF::EBorder, UTraceModuleFileSys::ECFileCBFlushDataL, EF32TraceUidFileSys, &share->File());
1488 TRAP(r,share->File().FlushDataL());
1489 TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECFileCBFlushDataLRet, EF32TraceUidFileSys, r);
1494 TInt TFsFileFlush::Initialise(CFsRequest* aRequest)
1499 return(DoInitNoParse(aRequest));
1503 TInt TFsFileSize::DoRequestL(CFsRequest* aRequest)
1505 // Get the file size.
1509 __PRINT(_L("TFsFileSize::DoRequestL(CFsRequest* aRequest)"));
1510 CFileShare* share=(CFileShare*)aRequest->ScratchValue();
1511 TInt64 size = share->File().CachedSize64();
1512 // Large file mode check and error handling is done at client library side.
1513 // Return file size even if it is greater than 2GB - 1.
1514 TPckgC<TInt64> pkSize(size);
1515 aRequest->WriteL(KMsgPtr0, pkSize);
1519 TInt TFsFileSize::Initialise(CFsRequest* aRequest)
1524 return(DoInitNoParse(aRequest));
1528 TInt TFsFileSetSize::DoRequestL(CFsRequest* aRequest)
1530 // Set the file size.
1533 __PRINT(_L("TFsFileSetSize::DoRequestL(CFsRequest* aRequest)"));
1535 CFileShare* share=(CFileShare*)aRequest->ScratchValue();
1536 if ((share->iMode&EFileWrite)==0)
1537 return(KErrAccessDenied);
1538 TInt r=share->CheckMount();
1543 if(aRequest->IsDescData(KMsgPtr0))
1545 TPckg<TInt64> pkSize(size);
1546 aRequest->ReadL(KMsgPtr0, pkSize);
1550 size = aRequest->Message().Int0();
1554 User::Leave(ESizeNegative);
1556 // Large file mode check
1557 if((!(share->IsFileModeBig())) && ((TUint64)size > KMaxLegacyFileSize))
1558 return (KErrTooBig);
1560 CFileCB& file=share->File();
1562 // flush the write cache
1563 CFileCache* fileCache = share->File().FileCache();
1564 if (fileCache && (r = fileCache->FlushDirty(aRequest)) != CFsRequest::EReqActionComplete)
1567 if (size==file.Size64())
1570 TBool fileHasGrown = size > file.Size64();
1573 r = CheckDiskSpace(size - file.Size64(), aRequest);
1577 r=file.CheckLock64(share,file.Size64(),size-file.Size64());
1580 r=file.CheckLock64(share,size,file.Size64()-size);
1583 __PRINT1(_L("Owner mount size before SetSize() = %d"),I64LOW(file.Mount().Size()));
1584 TRAP(r,file.SetSizeL(size))
1588 __PRINT1(_L("SetSize() failed = %d"),r);
1589 __PRINT1(_L("Owner mount size now = %d"),I64LOW(file.Mount().Size()));
1592 file.SetArchiveAttribute();
1593 file.SetSize64(size, EFalse);
1594 file.SetCachedSize64(size);
1597 file.NotifyAsyncReaders(); // Service outstanding async reads if the file has grown
1602 TInt TFsFileSetSize::Initialise(CFsRequest* aRequest)
1607 return(DoInitNoParse(aRequest));
1611 TInt TFsFileAtt::DoRequestL(CFsRequest* aRequest)
1613 // Get the file attributes.
1617 __PRINT(_L("TFsFileAtt::DoRequestL(CFsRequest* aRequest)"));
1619 CFileShare* share=(CFileShare*)aRequest->ScratchValue();
1620 // TInt att=(TInt)aRequest->FileShare()->File().Att()&KEntryAttMaskSupported;
1621 TInt att=(TInt)share->File().Att(); // DRM: let ROM XIP attribute through
1622 TPtrC8 pA((TUint8*)&att,sizeof(TInt));
1623 aRequest->WriteL(KMsgPtr0,pA);
1628 TInt TFsFileAtt::Initialise(CFsRequest* aRequest)
1633 return(DoInitNoParse(aRequest));
1637 TInt TFsFileSetAtt::DoRequestL(CFsRequest* aRequest)
1639 // Set the file attributes.
1642 __PRINT(_L("TFsFileSetAtt::DoRequestL(CSessionFs* aSession)"));
1644 TInt r = CheckDiskSpace(0, aRequest);
1648 CFileShare* share=(CFileShare*)aRequest->ScratchValue();
1649 r=share->CheckMount();
1653 if ((share->iMode&EFileWrite)==EFalse)
1654 return(KErrAccessDenied);
1656 TUint setAttMask=(TUint)(aRequest->Message().Int0());
1657 TUint clearAttMask=(TUint)aRequest->Message().Int1();
1658 ValidateAtts(share->File().Att(),setAttMask,clearAttMask);
1660 TRACE5(UTF::EBorder, UTraceModuleFileSys::ECFileCBSetEntryL, EF32TraceUidFileSys, &share->File(), 0, 0, setAttMask,clearAttMask);
1661 TRAP(r,share->File().SetEntryL(TTime(0),setAttMask,clearAttMask))
1662 TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECFileCBSetEntryLRet, EF32TraceUidFileSys, r);
1668 TInt TFsFileSetAtt::Initialise(CFsRequest* aRequest)
1670 // Call GetShareFromHandle to determine asynchronicity ***
1673 return(DoInitNoParse(aRequest));
1677 TInt TFsFileModified::DoRequestL(CFsRequest* aRequest)
1679 // Get the modified date and time.
1682 __PRINT(_L("TFsFileModified::DoRequestL(CFsRequest* aRequest)"));
1684 CFileShare* share=(CFileShare*)aRequest->ScratchValue();
1685 TTime mod=share->File().Modified();
1686 TPtrC8 pM((TUint8*)&mod,sizeof(TTime));
1687 aRequest->WriteL(KMsgPtr0,pM);
1693 TInt TFsFileModified::Initialise(CFsRequest* aRequest)
1695 // Call GetShareFromHandle to determine asynchronicity ***
1698 return(DoInitNoParse(aRequest));
1702 TInt TFsFileSetModified::DoRequestL(CFsRequest* aRequest)
1704 // Set the modified date and time.
1707 __PRINT(_L("TFsFileSetModified::DoRequestL(CFsRequest* aRequest)"));
1709 TInt r = CheckDiskSpace(0, aRequest);
1714 CFileShare* share=(CFileShare*)aRequest->ScratchValue();
1715 r=share->CheckMount();
1719 if ((share->iMode&EFileWrite)==EFalse)
1720 return(KErrAccessDenied);
1723 TPtr8 t((TUint8*)&time,sizeof(TTime));
1724 aRequest->ReadL(KMsgPtr0,t);
1726 TRACE5(UTF::EBorder, UTraceModuleFileSys::ECFileCBSetEntryL, EF32TraceUidFileSys, &share->File(), 0, 0, KEntryAttModified,0);
1727 TRAP(r,share->File().SetEntryL(time,KEntryAttModified,0))
1728 TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECFileCBSetEntryLRet, EF32TraceUidFileSys, r);
1734 TInt TFsFileSetModified::Initialise(CFsRequest* aRequest)
1736 // Call GetShareFromHandle to determine asynchronicity ***
1739 return(DoInitNoParse(aRequest));
1742 TInt TFsFileSet::DoRequestL(CFsRequest* aRequest)
1744 // Set the attributes and the modified date and time.
1747 __PRINT(_L("TFsFileSet::DoRequestL(CFsRequest* aRequest)"));
1749 TInt r = CheckDiskSpace(0, aRequest);
1753 CFileShare* share=(CFileShare*)aRequest->ScratchValue();
1754 r=share->CheckMount();
1758 if (share->File().Att()&KEntryAttReadOnly)
1759 return(KErrAccessDenied);
1761 if ((share->iMode&EFileWrite)==0)
1763 if(share->File().Drive().IsWriteProtected())
1764 return(KErrAccessDenied);
1768 TPtr8 t((TUint8*)&time,sizeof(TTime));
1769 aRequest->ReadL(KMsgPtr0,t);
1770 TUint setAttMask=(TUint)(aRequest->Message().Int1()|KEntryAttModified);
1771 TUint clearAttMask=(TUint)aRequest->Message().Int2();
1772 ValidateAtts(share->File().Att(),setAttMask,clearAttMask);// Validate attributes
1774 TRACE5(UTF::EBorder, UTraceModuleFileSys::ECFileCBSetEntryL, EF32TraceUidFileSys, &share->File(), 0, 0, setAttMask,clearAttMask);
1775 TRAP(r,share->File().SetEntryL(time,setAttMask,clearAttMask))
1776 TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECFileCBSetEntryLRet, EF32TraceUidFileSys, r);
1781 TInt TFsFileSet::Initialise(CFsRequest* aRequest)
1786 return(DoInitNoParse(aRequest));
1790 TInt TFsFileChangeMode::DoRequestL(CFsRequest* aRequest)
1792 // The access to a file may be changed from share exclusive to share readers only or vice versa.
1793 // KErrAccessDenied is returned if the file has multiple readers.
1796 __PRINT(_L("TFsFileChangeMode::DoRequestL(CFsRequest* aRequest)"));
1797 CFileShare* share=(CFileShare*)aRequest->ScratchValue();
1798 TInt r=share->CheckMount();
1802 const TFileMode currentMode = (TFileMode)share->iMode;
1803 const TFileMode newMode = (TFileMode)aRequest->Message().Int0();
1806 // (only EFileShareExclusive and EFileShareReadersOnly are allowed)
1807 if((newMode & ~EFileShareReadersOnly) != 0)
1808 return KErrArgument;
1810 // check if the file is in EFileShareAny mode
1811 if( (currentMode & EFileShareAny) ||
1812 // or the file has been opened for writing in EFileShareExclusive mode,
1813 // and an attempt is made to change the access mode to EFileShareReadersOnly
1814 ((currentMode & EFileWrite) &&
1815 (currentMode & KFileShareMask) == EFileShareExclusive &&
1816 newMode == EFileShareReadersOnly) )
1817 return KErrAccessDenied;
1819 // check if an attempt is made to change the share mode to EFileShareExclusive
1820 // while the file has multiple readers
1821 if (newMode == EFileShareExclusive && (currentMode & KFileShareMask) != EFileShareExclusive)
1823 // Check no other CFileCB is reading the file.
1825 TInt count=FileShares->Count();
1829 CFileShare* fileShare=(CFileShare*)(*FileShares)[count];
1830 if (&fileShare->File()==&share->File())
1834 FileShares->Unlock();
1835 return(KErrAccessDenied);
1840 FileShares->Unlock();
1842 share->iMode&=~KFileShareMask;
1843 share->iMode|=newMode;
1844 share->File().SetShare(newMode);
1849 TInt TFsFileChangeMode::Initialise(CFsRequest* aRequest)
1854 TInt r = DoInitNoParse(aRequest);
1857 CFileShare* share=(CFileShare*)aRequest->ScratchValue();
1858 if(CompareResource(share->File().FileName().Mid(2)) )
1860 if(!KCapFsFileChangeMode.CheckPolicy(aRequest->Message(), __PLATSEC_DIAGNOSTIC_STRING("File Change Mode")))
1861 return KErrPermissionDenied;
1867 TInt TFsFileRename::DoRequestL(CFsRequest* aRequest)
1869 // Rename the file if it was openned EFileShareExclusive
1872 __PRINT(_L("TFsFileRename::DoRequestL(CFsRequest* aRequest)"));
1874 TInt r = CheckDiskSpace(0, aRequest);
1878 CFileShare* share=(CFileShare*)aRequest->ScratchValue();
1879 r=share->CheckMount();
1883 TInt currentMode=(share->iMode&KFileShareMask);
1884 if ((currentMode&EFileShareAny) || (currentMode&EFileShareReadersOnly))
1885 return(KErrAccessDenied); // File must be EFileShareExclusive
1887 if ((share->iMode&EFileWrite)==0)
1888 return(KErrAccessDenied); // File must have write permission
1890 TPtrC filePath = aRequest->Dest().FullName().Mid(2);
1891 CFileCB& file = share->File();
1893 TRACEMULT2(UTF::EBorder, UTraceModuleFileSys::ECFileCBRenameL, EF32TraceUidFileSys,
1894 (TUint) &file, filePath);
1895 TRAP(r,file.RenameL(filePath));
1896 TRACERETMULT1(UTF::EBorder, UTraceModuleFileSys::ECFileCBRenameLRet, EF32TraceUidFileSys, r);
1898 // Re-write the file's folded name & re-calculate the hash
1901 TFileName filePathF;
1902 filePathF.CopyF(filePath);
1903 TRAP(r, AllocBufferL(file.iFileNameF, filePathF));
1904 file.iNameHash=CalcNameHash(*file.iFileNameF);
1910 TInt TFsFileRename::Initialise(CFsRequest* aRequest)
1915 TInt r=DoInitialise(aRequest);
1918 CFileShare* share=(CFileShare*)aRequest->ScratchValue();
1920 TRAP(r,aRequest->ReadL(KMsgPtr0,newName));
1923 TDriveUnit currentDrive(share->File().Mount().Drive().DriveNumber());
1924 TDriveName driveName=currentDrive.Name();
1925 r=aRequest->Dest().Set(newName,&share->File().FileName(),&driveName);
1928 if (aRequest->Dest().IsWild())
1929 return(KErrBadName);
1931 if ((r=RFs::CharToDrive(aRequest->Dest().Drive()[0],driveNo))!=KErrNone)
1933 TDrive& drive=TheDrives[driveNo];
1934 if(drive.IsSubsted())
1936 if ((drive.Subst().Length()+aRequest->Dest().FullName().Length())>(KMaxFileName+3))
1937 return(KErrBadName);
1938 TFileName n=drive.Subst();
1939 n+=aRequest->Dest().FullName().Mid(3);
1940 r=aRequest->Dest().Set(n,NULL,NULL);
1945 TDriveUnit newDrive(aRequest->Dest().Drive());
1946 if (newDrive!=currentDrive)
1947 return(KErrBadName);
1948 if (IsIllegalFullName(aRequest->Dest().FullName().Mid(2)))
1949 return(KErrBadName);
1950 r=PathCheck(aRequest,aRequest->Dest().FullName().Mid(2),&KCapFsSysFileRename,&KCapFsPriFileRename,&KCapFsROFileRename, __PLATSEC_DIAGNOSTIC_STRING("File Rename"));
1955 TInt TFsFileDrive::DoRequestL(CFsRequest* aRequest)
1957 // Get the drive info for the file.
1960 __PRINT(_L("TFsFileDrive::DoRequestL(CFsRequest* aRequest)"));
1961 CFileShare* share=(CFileShare*)aRequest->ScratchValue();
1962 TDrive *dr = &share->File().Drive();
1964 TPckgBuf<TInt> pkiF(dr->DriveNumber()); // copy drive number to user
1965 aRequest->WriteL(KMsgPtr0, pkiF);
1967 TDriveInfo di; // copy drive info to user
1969 TPckgC<TDriveInfo> pkdiF(di);
1970 aRequest->WriteL(KMsgPtr1, pkdiF);
1976 TInt TFsFileDrive::Initialise(CFsRequest* aRequest)
1981 return(DoInitNoParse(aRequest));
1985 TInt TFsFileDuplicate::DoRequestL(CFsRequest* aRequest)
1987 // Duplicate the received file handle ready for transfer to another process.
1988 // The new file handle is written back to the client in a a mangled form to prevent
1989 // it from being used. Calling TFsFileAdopt will de-mangle the handle.
1992 CFileShare* pS = (CFileShare*)aRequest->ScratchValue();
1994 // get the file control block from the client's file share
1995 CFileCB& fileCB = pS->File();
1997 // Create a new file share and initialize it with the
1998 // client file share's file control block, position & mode
2000 CFileShare* pNewFileShare = new CFileShare(&fileCB);
2001 if (pNewFileShare == NULL)
2002 return KErrNoMemory;
2004 // We need to call CFileCB::PromoteShare immediately after the CFileShare
2005 // instance is created since the destructor calls CFileCB::DemoteShare()
2006 // which checks the share count is non-zero
2007 pNewFileShare->iMode = pS->iMode;
2008 fileCB.PromoteShare(pNewFileShare);
2011 TInt r = fileCB.Open(); // increment the ref count
2014 TRAP(r, pNewFileShare->InitL());
2015 __e32_atomic_store_ord64(&pNewFileShare->iPos, pS->iPos);
2017 // Add new file share to the global file share container
2019 TRAP(r, FileShares->AddL(pNewFileShare,ETrue));
2021 // Add new file share to list owned by this session
2024 TRAP(r,newHandle = aRequest->Session()->Handles().AddL(pNewFileShare,ETrue));
2028 pNewFileShare->Close();
2032 newHandle^= KSubSessionMangleBit;
2034 TPtrC8 pH((TUint8*)&newHandle, sizeof(TInt));
2035 aRequest->WriteL(KMsgPtr3, pH);
2036 aRequest->Session()->IncResourceCount();
2040 TInt TFsFileDuplicate::Initialise(CFsRequest* aRequest)
2042 TInt handle = aRequest->Message().Int0();
2043 CFileShare* share = GetShareFromHandle(aRequest->Session(), handle);
2045 // If the handle is invalid, either panic (CFsMessageRequest::Dispatch() will
2046 // panic if we return KErrBadHandle) or complete the request with KErrArgument.
2047 // The latter case is the behaviour for the (deprecated) RFile::Adopt() to
2048 // prevent a server from panicing if the passed file handle is invalid.
2050 return aRequest->Message().Int1()?KErrBadHandle:KErrArgument;
2052 aRequest->SetDrive(&share->File().Drive());
2053 aRequest->SetScratchValue64( MAKE_TINT64(ETrue, (TUint) share) );
2059 TInt TFsFileAdopt::DoRequestL(CFsRequest* aRequest)
2061 // Adopt the passed file handle. This assumes that the handle has already been
2062 // duplicated by calling TFsFileDuplicate and is therefore mangled.
2065 if (((CFileShare*)aRequest->ScratchValue()) == NULL)
2066 return KErrBadHandle;
2068 TInt adoptType = aRequest->Message().Int1();
2069 // EFileBigFile mode check
2073 // Request is from RFile::Adopt or RFile::AdoptFromXXX: Force NO EFileBigFile
2074 ((CFileShare*)aRequest->ScratchValue())->iMode &= ~EFileBigFile;
2077 // Request is from RFile64::AdoptFromXXX: Force EFileBigFile
2078 ((CFileShare*)aRequest->ScratchValue())->iMode |= EFileBigFile;
2080 case KFileDuplicate:
2081 // Request is from RFile::Duplucate
2082 // adopt original file mode - do nothing
2088 // De-mangle the existing sub-session handle and return it to the client
2089 TInt newHandle = aRequest->Message().Int0() ^ KSubSessionMangleBit;
2091 TPtrC8 pH((TUint8*)&newHandle,sizeof(TInt));
2092 aRequest->WriteL(KMsgPtr3,pH);
2096 TInt TFsFileAdopt::Initialise(CFsRequest* aRequest)
2098 TInt handle = aRequest->Message().Int0() ^KSubSessionMangleBit;
2100 CFileShare* share = GetShareFromHandle(aRequest->Session(), handle);
2101 // Normally returning KErrBadHandle will result in a panic, but when a server calls
2102 // RFile::AdoptXXX() and it's client has given it a bad handle then it's not a good
2103 // idea to panic the server. So we return KErrNone here and allow
2104 // TFsFileAdopt::DoRequestL() to return KErrBadHandle
2106 aRequest->SetDrive(&share->File().Drive());
2108 aRequest->SetScratchValue64( MAKE_TINT64(ETrue, (TUint) share) );
2113 TInt TFsFileName::DoRequestL(CFsRequest* aRequest)
2115 // Get the name of a file.
2116 // i.e. including the name & extension but excluding the drive and path
2119 CFileShare* share = (CFileShare*)aRequest->ScratchValue();
2121 // Search backwards until a backslash is found
2122 // This should always succeed as this is a full pathname
2123 TPtrC name(share->File().FileName());
2124 TInt offset = name.LocateReverse('\\');
2125 aRequest->WriteL(KMsgPtr0, name.Mid(offset+1));
2130 TInt TFsFileName::Initialise(CFsRequest* aRequest)
2132 // Get the full name of a file, including path and drive
2136 return InitialiseScratchToShare(aRequest);
2140 TInt TFsFileFullName::DoRequestL(CFsRequest* aRequest)
2142 // Get the full name of a file, including path and drive
2145 CFileShare* share = (CFileShare*)aRequest->ScratchValue();
2147 // Write the drive letter and ':'
2148 TBuf<2> driveBuf(KDrivePath);
2149 driveBuf[0]=TText('A' + share->File().Drive().DriveNumber());
2150 aRequest->WriteL(KMsgPtr0, driveBuf);
2152 // Write the file and path including leading '\'
2153 TPtrC name(share->File().FileName());
2154 aRequest->WriteL(KMsgPtr0, name, 2);
2160 TInt TFsFileFullName::Initialise(CFsRequest* aRequest)
2165 return InitialiseScratchToShare(aRequest);
2168 TInt TFsGetMediaSerialNumber::DoRequestL(CFsRequest* aRequest)
2170 // Acquire capability from media and return serial number if supported.
2173 // Get request parameters
2174 const TInt drvNum = aRequest->Message().Int1();
2176 // Get media capability
2177 TLocalDriveCapsV5Buf capsBuf;
2181 // is the drive local?
2182 if (!IsProxyDrive(drvNum))
2184 // if not valid local drive, use default values in localDriveCaps
2185 // if valid local drive and not locked, use TBusLocalDrive::Caps() values
2186 // if valid drive and locked, hard-code attributes
2187 r = GetLocalDrive(drvNum).Caps(capsBuf);
2189 else // this need to be made a bit nicer
2191 CExtProxyDrive* pD = GetProxyDrive(drvNum);
2193 r = pD->Caps(capsBuf);
2201 TLocalDriveCapsV5& capsV5 = capsBuf();
2203 // Return serial number if supported
2204 if (capsV5.iSerialNumLength == 0)
2205 return KErrNotSupported;
2207 TPtrC8 snPtr(capsV5.iSerialNum, capsV5.iSerialNumLength);
2208 aRequest->WriteL(KMsgPtr0, snPtr);
2213 TInt TFsGetMediaSerialNumber::Initialise(CFsRequest* aRequest)
2215 // Validate drive number and its attributes passed in a request object.
2218 const TInt drvNum = aRequest->Message().Int1();
2220 TInt nRes = ValidateDrive(drvNum, aRequest);
2221 if(nRes != KErrNone)
2222 return KErrBadName; //-- incorrect drive number
2224 if(aRequest->Drive()->IsSubsted())
2225 return KErrNotSupported; //-- the drive is substed, this operation doesn't make a sense
2227 if(!IsValidLocalDriveMapping(drvNum))
2228 return KErrNotReady;
2233 TInt TFsBlockMap::Initialise(CFsRequest* aRequest)
2235 TInt r = DoInitNoParse(aRequest);
2239 TInt blockMapUsage = aRequest->Message().Int2();
2240 if ( blockMapUsage == EBlockMapUsagePaging )
2242 CFileShare* share = (CFileShare*) aRequest->ScratchValue();
2243 CFileCB& file = share->File();
2245 // To determine whether the drive where this file resides is pageable, we need to locate
2246 // the specific TBusLocalDrive object first; querying the drive attributes directly from the
2247 // (composite) file system is no good as this API treats all slave file systems as "ROM & not pageable.
2248 TBusLocalDrive* localDrive;
2249 TInt r = file.LocalDrive(localDrive);
2252 TLocalDriveCapsV4Buf caps;
2253 r = localDrive->Caps(caps);
2256 __PRINT4(_L("TFsBlockMap::Initialise, drive %d file %S iMediaAtt %08X iDriveAtt %08X\n"), file.DriveNumber(), &file.FileName(), caps().iMediaAtt, caps().iDriveAtt);
2257 if ( !(caps().iDriveAtt & KDriveAttPageable))
2258 return KErrNotSupported;
2264 TInt TFsBlockMap::DoRequestL(CFsRequest* aRequest)
2266 __PRINT(_L("TFsBlockMap::DoRequestL(CFsRequest* aRequest)"));
2267 __PRINT1(_L("aRequest->Session() = 0x%x"), aRequest->Session());
2269 CFileShare* share = (CFileShare*) aRequest->ScratchValue();
2271 TInt r = share->CheckMount();
2273 __PRINT1(_L("share->CheckMount() returned - %d"), r);
2274 if ( r != KErrNone )
2277 SBlockMapInfo reqInfo;
2279 TPckg<SBlockMapArgs> pkArgs(args);
2280 aRequest->ReadL(KMsgPtr1, pkArgs);
2282 CFileCB& file = share->File();
2283 TInt64& reqStartPos = args.iStartPos;
2284 TInt64 reqEndPos = args.iEndPos;
2286 if ( ( reqStartPos > file.Size64() ) || ( reqStartPos < 0 ) )
2287 return KErrArgument;
2289 const TInt64 KReadToEOF = -1;
2290 if ( reqEndPos != KReadToEOF )
2292 if ( !( reqEndPos >= reqStartPos ) )
2293 return KErrArgument;
2296 reqEndPos = file.Size64();
2298 // If the requested start position is equal to the size of the file
2299 // then we read no data and return an empty BlockMap.
2300 if ( reqStartPos == file.Size64() || reqEndPos == 0 || reqEndPos == reqStartPos )
2302 TPckg<SBlockMapInfo> pkInfo(reqInfo);
2303 TRAP(r,aRequest->WriteL(KMsgPtr0,pkInfo) );
2304 if ( r == KErrNone )
2305 return(KErrArgument);
2309 r = share->File().BlockMap(reqInfo, reqStartPos, reqEndPos);
2310 TPckg<SBlockMapInfo> pkInfo(reqInfo);
2311 aRequest->WriteL(KMsgPtr0, pkInfo);
2312 aRequest->WriteL(KMsgPtr1, pkArgs);
2317 #pragma warning( disable : 4705 ) // statement has no effect
2321 EXPORT_C CFileCB::CFileCB()
2324 #pragma warning( default : 4705 )
2332 Frees resources before destruction of the object.
2334 EXPORT_C CFileCB::~CFileCB()
2336 // NB Must be careful to close the file cache BEFORE deleting iFileNameF
2337 // as CFileCache may steal it (!)
2339 FileCache()->Close();
2340 if (iBody && iBody->iDeleteOnClose)
2342 TRACEMULT2(UTF::EBorder, UTraceModuleFileSys::ECMountCBDeleteL, EF32TraceUidFileSys, DriveNumber(), FileName());
2344 TRAP(r, iMount->DeleteL(FileName()));
2345 TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECMountCBDeleteLRet, EF32TraceUidFileSys, r);
2350 if (iMountLink.iNext!=NULL)
2358 iFileLocks->Close();
2366 Initialise CFileCB object.
2370 @param aCreatedDrive
2371 @param aName file name descriptor
2373 EXPORT_C void CFileCB::InitL(TDrive* aDrive, TDrive* aCreatedDrive, HBufC* aName)
2375 // Take ownership of heap-allocated objects aName and aLock before attempting any memory allocation
2376 // to avoid leaking memory
2379 DoInitL(aDrive->DriveNumber());
2381 iCreatedDrive=aCreatedDrive;
2383 tempName.CopyF(*aName);
2384 iFileNameF=tempName.AllocL();
2385 iNameHash=CalcNameHash(*iFileNameF);
2389 // see whether the file system supports the CFileCB extended API
2390 MExtendedFileInterface* extendedFileInterface = NULL;
2391 GetInterfaceTraced(CFileCB::EExtendedFileInterface, (void*&) extendedFileInterface, NULL);
2392 iBody = new(ELeave)CFileBody(this, extendedFileInterface);
2394 iMount=&iDrive->CurrentMount();
2396 User::LeaveIfError(iMount->Open());
2398 //-- create file locks array
2399 ASSERT(!iFileLocks);
2400 iFileLocks = new(ELeave) TFileLocksArray(KFileShareLockGranularity, _FOFF(TFileShareLock, iPosLow));
2405 TInt CFileCB::FindLock(TInt aPosLow,TInt aPosHigh)
2407 return FindLock64(aPosLow, aPosHigh);
2410 TInt CFileCB::AddLock(CFileShare* aFileShare,TInt aPos,TInt aLength)
2412 return AddLock64(aFileShare, aPos, aLength);
2415 TInt CFileCB::RemoveLock(CFileShare* aFileShare,TInt aPos,TInt aLength)
2417 return RemoveLock64(aFileShare, aPos, aLength);
2420 TInt CFileCB::CheckLock(CFileShare* aFileShare,TInt aPos,TInt aLength)
2422 return CheckLock64(aFileShare, aPos, aLength);
2426 Remove any locks held by aFileShare.
2428 void CFileCB::RemoveLocks(CFileShare* aFileShare)
2432 while (i<FileLocks().Count())
2434 if (FileLocks()[i].MatchOwner(aFileShare))
2435 FileLocks().Remove(i);
2442 void CFileCB::PromoteShare(CFileShare* aShare)
2444 // Manages share promotion after the share has been added to the FilsShares container.
2446 // - Assumes the share has already been validated using ValidateShare()
2448 // - The count of promoted shares (ie - non-EFileShareReadersOrWriters) is incremented
2449 // to allow the share mode to be demoted when the last promoted share is closed.
2452 TShare reqShare = (TShare)(aShare->iMode & KFileShareMask);
2453 if(reqShare != EFileShareReadersOrWriters)
2455 iBody->iPromotedShares++;
2461 void CFileCB::DemoteShare(CFileShare* aShare)
2463 // Manages share demotion after the share has been removed from the FileShares container.
2465 // - If the share being removed is not EFileShareReadersOrWriters, then the current
2466 // share mode may require demotion back to EFileShareReadersOrWriters.
2468 // - This is determined by the iPromotedShares count, incremented in PromoteShare()
2471 if((aShare->iMode & KFileShareMask) != EFileShareReadersOrWriters)
2473 if(--iBody->iPromotedShares == 0)
2475 // Don't worry if the file has never been opened as EFileShareReadersOrWriters
2476 // - in this case the CFileCB object is about to be closed anyway.
2477 iShare = EFileShareReadersOrWriters;
2480 __ASSERT_DEBUG(iBody->iPromotedShares>=0,Fault(EFileShareBadPromoteCount));
2484 RArray<TAsyncReadRequest>& CFileCB::AsyncReadRequests()
2486 // Gets a reference to the pending asynchronous read requests for this file.
2488 // - The request is completed when all data is available or the request is cancelled.
2491 return(*iBody->iAsyncReadRequests);
2495 TInt CFileCB::AddAsyncReadRequest(CFileShare* aShareP, TInt64 aPos, TInt aLen, CFsRequest* aRequestP)
2497 // Adds a pending asynchronous read request to the list.
2499 // - The request is completed when all data is available or the request is cancelled.
2503 __ASSERT_ALWAYS(aRequestP->Operation()->Function() == EFsFileRead, Fault(EBaseRequestMessage));
2505 TAsyncReadRequest req(aPos + aLen, aShareP, aRequestP);
2506 TInt err = AsyncReadRequests().InsertInSignedKeyOrderAllowRepeats(req);
2510 aRequestP->SetCompleted(EFalse);
2515 TInt CFileCB::CancelAsyncReadRequest(CFileShare* aShareP, TRequestStatus* aStatusP)
2517 // Cancels (and completes) an outstanding read request for the specified share.
2519 // - aStatusP == NULL cancels all outstanding read requests.
2525 while (i < AsyncReadRequests().Count())
2527 TAsyncReadRequest& req = AsyncReadRequests()[i];
2528 if(req.CompleteIfMatching(aShareP, aStatusP, KErrCancel))
2530 iBody->iAsyncReadRequests->Remove(i);
2531 if(aStatusP != NULL)
2548 void CFileCB::NotifyAsyncReaders()
2550 // Determine if any outstanding read requests require completion.
2552 // - Called whenever the file size changes (due to a write operation or SetSize)
2554 // - Any outstanding read requests are re-issued (rather then completed in the
2555 // context of the current operation so not to affect performance of the writer).
2557 // - Should the file size shrink before the request is serviced, the request will
2558 // be added back onto the queue.
2560 // - A future optimisation may issue the request as data becomes available (which
2561 // would minimise the final latency between writer and reader) but the current
2562 // implementation reads all requested data in one operation.
2567 SetNotifyAsyncReadersPending(EFalse);
2569 while(AsyncReadRequests().Count())
2571 TAsyncReadRequest& req = AsyncReadRequests()[0];
2572 if(req.iEndPos > CachedSize64())
2575 // Make a copy and then remove it from the queue before releasing the lock -
2576 // because the file server thread could append to the RArray and this might
2577 // cause a re-allocation which would move the whole array (!)
2578 TAsyncReadRequest reqCopy = req;
2579 AsyncReadRequests().Remove(0);
2582 // allocate a new request, push a TMsgOperation onto the request's stack (duplicating
2583 // the functionality of TFsFileRead::Initialise()) & dispatch the request
2584 CFsClientMessageRequest* pRequest = NULL;
2585 const TOperation& oP = OperationArray[EFsFileRead];
2586 TInt r = RequestAllocator::GetMessageRequest(oP, reqCopy.iMessage, pRequest);
2589 reqCopy.iMessage.Complete(r); // complete the client's message with an error
2592 pRequest->Set(reqCopy.iMessage, oP, reqCopy.iSessionP);
2594 r = DoInitNoParse(pRequest);
2597 pRequest->Complete(r); // complete the client's message with an error
2601 r = pRequest->PushOperation(TFsFileRead::Complete);
2604 pRequest->Complete(r); // complete the client's message with an error
2608 pRequest->CurrentOperation().Set(
2609 reqCopy.iEndPos - pRequest->Message().Int1(),
2610 pRequest->Message().Int1(),
2611 (TDes8*) pRequest->Message().Ptr0());
2613 // don't call Initialise()
2614 pRequest->SetState(CFsRequest::EReqStatePostInitialise);
2616 pRequest->Dispatch();
2624 Gets the address of the file that the file control block represents.
2626 The default implementation returns KErrNotSupported and should only
2627 be overridden for ROM file systems.
2629 @param aPos On return, should contain the address of the file that
2630 the file control block represents.
2632 @return KErrNone, if successful,otherwise one of the other system wide error
2635 EXPORT_C TInt CFileCB::Address(TInt& /*aPos*/) const
2638 return(KErrNotSupported);
2643 Sets the archive attribute, KEntryAttArchive, in iAtt.
2645 EXPORT_C void CFileCB::SetArchiveAttribute()
2648 iAtt|=KEntryAttArchive;
2649 iAtt|=KEntryAttModified;
2650 iModified.UniversalTime();
2654 EXPORT_C TInt CFileCB::GetInterface(TInt aInterfaceId,TAny*& aInterface,TAny* /*aInput*/)
2656 switch(aInterfaceId)
2658 case EGetLocalDrive:
2659 return Mount().LocalDrive((TBusLocalDrive*&) aInterface);
2661 return(KErrNotSupported);
2666 CFileCache* CFileCB::FileCache() const
2667 {return iBody?iBody->iFileCache:NULL;}
2669 TBool CFileCB::LocalBufferSupport() const
2670 {return iBody?iBody->iLocalBufferSupport:EFalse;}
2672 void CFileCB::SetLocalBufferSupport(TBool aEnabled)
2673 {iBody->iLocalBufferSupport = aEnabled;}
2675 TInt CFileCB::CheckMount()
2677 // Check that the media is still mounted.
2681 TDrive& d = Drive();
2682 TInt r=d.CheckMount();
2685 if (&Mount() != &d.CurrentMount())
2686 return(KErrDisMounted);
2688 return(KErrCorrupt);
2692 SetBadPower(EFalse);
2694 return(KErrBadPower);
2699 TInt64 CFileCB::CachedSize64() const
2701 CFileCache* fileCache = iBody?iBody->iFileCache:NULL;
2702 return fileCache? fileCache->Size64(): Size64();
2705 void CFileCB::SetCachedSize64(TInt64 aSize)
2708 FileCache()->SetSize64(aSize);
2710 SetSize64(aSize, EFalse); // assume not locked
2715 Locks the mount resource to which the shared file resides.
2717 @param aFileCB File to be shared.
2719 CFileShare::CFileShare(CFileCB* aFileCB)
2722 AddResource(iFile->Mount());
2728 Frees mount resource to which the shared file resides,
2729 removes share status from the shared file and finally closes
2732 CFileShare::~CFileShare()
2734 // We shouldn't be deleting the file share with a valid request queue or there will be request (& memory) leakage
2735 __ASSERT_DEBUG(iCurrentRequest == NULL, Fault(ERequestQueueNotEmpty));
2737 RemoveResource(iFile->Mount());
2738 iFile->RemoveLocks(this);
2739 iFile->DemoteShare(this);
2740 iFile->CancelAsyncReadRequest(this, NULL);
2745 Check that the media is still mounted.
2747 @return KErrNone if successful.
2748 KErrDisMounted if media has dismounted.
2749 KErrCorrupted if shared file is corrupted.
2750 KErrBadPower if insufficent power supply.
2751 or other system wide error code.
2753 TInt CFileShare::CheckMount()
2755 return File().CheckMount();
2759 Initialise the object
2761 void CFileShare::InitL()
2763 DoInitL(iFile->Drive().DriveNumber());
2765 // override the close operation so that we can flush the write cache if necessary
2766 iRequest->Set(FileShareCloseOp,NULL);
2767 iRequest->SetDriveNumber(DriveNumber());
2768 iRequest->SetScratchValue((TUint)this);
2771 // Mark the start of a request -
2772 // the is to prevent fair-scheduled async read/writes from being processed out of sequence. This is especially
2773 // important when considering a client which appends to a file by issuing more than one asynchronous request as each
2774 // write request must be entirely satisfied before a subsequent request can append to the file
2775 TBool CFileShare::RequestStart(CFsMessageRequest* aRequest)
2779 TDrive& drive = File().Drive();
2782 if (iCurrentRequest == NULL || iCurrentRequest == aRequest)
2784 iCurrentRequest = aRequest;
2789 // add to end of linked list of requests if there is already an active request for this share
2790 CFsClientMessageRequest* request;
2791 for (request = (CFsClientMessageRequest*) iCurrentRequest; request->iNext != NULL; request = request->iNext)
2794 request->iNext = (CFsClientMessageRequest*) aRequest;
2803 // Mark the end of a request
2804 void CFileShare::RequestEnd(CFsMessageRequest* aRequest)
2806 TDrive& drive = File().Drive();
2809 if (aRequest == iCurrentRequest)
2811 // Any requests in the queue ?
2812 if (((CFsClientMessageRequest*) iCurrentRequest)->iNext)
2814 iCurrentRequest = ((CFsClientMessageRequest*) aRequest)->iNext;
2815 ((CFsClientMessageRequest*) aRequest)->iNext = NULL;
2817 // if the current request has been cancelled, cancel all requests in the queue
2818 TInt lastError = aRequest->LastError();
2819 if (lastError == KErrCancel || lastError == KErrNotReady)
2821 // take ownership of this queue and make it invisible to anyone else by setting iCurrentRequest to NULL
2822 CFsClientMessageRequest* currentRequest = (CFsClientMessageRequest*) iCurrentRequest;
2823 iCurrentRequest = NULL;
2825 while(currentRequest)
2827 CFsClientMessageRequest* nextRequest = ((CFsClientMessageRequest*) currentRequest)->iNext;
2828 ((CFsClientMessageRequest*) currentRequest)->iNext = NULL;
2829 currentRequest->Complete(lastError);
2830 currentRequest = nextRequest;
2836 iCurrentRequest->Dispatch(EFalse);
2841 iCurrentRequest = NULL;
2845 else // if (aRequest == iCurrentRequest)
2851 TBool CFileShare::RequestInProgress() const
2853 return (iCurrentRequest != NULL)?(TBool)ETrue:(TBool)EFalse;
2859 Initialise the object
2861 TInt TFsCloseFileShare::DoRequestL(CFsRequest* aRequest)
2864 __PRINT(_L("TFsCloseFileCache::DoRequestL()"));
2866 CFileShare* share=(CFileShare*)aRequest->ScratchValue();
2868 // flush the write cache before closing the file share
2870 CFileCache* fileCache = share->File().FileCache();
2871 if (fileCache && (r = fileCache->FlushDirty(aRequest)) == CFsRequest::EReqActionBusy)
2877 TInt TFsCloseFileShare::Complete(CFsRequest* aRequest)
2879 __PRINT(_L("TFsCloseFileShare::Complete()"));
2880 return TFsCloseObject::Complete(aRequest);
2884 TAsyncReadRequest::TAsyncReadRequest(TInt64 aEndPos, CFileShare* aOwningShareP, CFsRequest* aRequestP)
2886 // Constructor for TAsyncReadRequest
2887 // - Maintains information about oustanding async read requests
2890 iOwningShareP(aOwningShareP)
2892 iMessage = aRequestP->Message();
2893 iSessionP = aRequestP->Session();
2894 iStatusP = iMessage.ClientStatus();
2898 TBool TAsyncReadRequest::CompleteIfMatching(CFileShare* aShareP, TRequestStatus* aStatusP, TInt aError)
2900 // Completes an asynchronous read request.
2903 if (iOwningShareP == aShareP && (aStatusP == NULL || aStatusP == iStatusP))
2905 iMessage.Complete(aError);
2913 TInt TFsFileReadCancel::Initialise(CFsRequest* aRequest)
2915 // Initialise function for RFile::ReadCancel [EFsReadCancel]
2918 return InitialiseScratchToShare(aRequest);
2922 TInt TFsFileReadCancel::DoRequestL(CFsRequest* aRequest)
2924 // Request function for RFile::ReadCancel [EFsReadCancel]
2927 CFileShare* share = (CFileShare*)aRequest->ScratchValue();
2928 TRequestStatus* status = (TRequestStatus*)aRequest->Message().Ptr0();
2929 share->File().CancelAsyncReadRequest(share, status);
2933 void CFileCB::ReadL(TInt64 aPos,TInt& aLength,TDes8* aDes,const RMessagePtr2& aMessage, TInt aOffset)
2935 TRACETHREADID(aMessage);
2936 TRACE7(UTF::EBorder, UTraceModuleFileSys::ECFileCBReadL, EF32TraceUidFileSys,
2937 this, I64LOW(aPos), I64HIGH(aPos), aLength, aDes, threadId, aOffset);
2939 iBody->iExtendedFileInterface->ReadL(aPos,aLength,aDes,aMessage,aOffset);
2941 TRACE1(UTF::EBorder, UTraceModuleFileSys::ECFileCBReadLRet, EF32TraceUidFileSys, KErrNone);
2944 void CFileCB::WriteL(TInt64 aPos,TInt& aLength,const TDesC8* aDes,const RMessagePtr2& aMessage, TInt aOffset)
2946 TRACETHREADID(aMessage);
2947 TRACE7(UTF::EBorder, UTraceModuleFileSys::ECFileCBWriteL, EF32TraceUidFileSys,
2948 this, I64LOW(aPos), I64HIGH(aPos), aLength, aDes, threadId, aOffset);
2950 iBody->iExtendedFileInterface->WriteL(aPos,aLength,aDes,aMessage,aOffset);
2952 TRACE1(UTF::EBorder, UTraceModuleFileSys::ECFileCBWriteLRet, EF32TraceUidFileSys, KErrNone);
2955 void CFileCB::SetSizeL(TInt64 aSize)
2957 TRACE3(UTF::EBorder, UTraceModuleFileSys::ECFileCBSetSizeL, EF32TraceUidFileSys, this, I64LOW(aSize), I64HIGH(aSize));
2959 iBody->iExtendedFileInterface->SetSizeL(aSize);
2961 TRACE1(UTF::EBorder, UTraceModuleFileSys::ECFileCBSetSizeLRet, EF32TraceUidFileSys, KErrNone);
2964 TBool CFileCB::ExtendedFileInterfaceSupported()
2966 return iBody->ExtendedFileInterfaceSupported();
2969 TInt CFileCB::FairSchedulingLen() const
2971 return iBody->iFairSchedulingLen;
2974 void CFileCB::SetNotifyAsyncReadersPending(TBool aNotifyAsyncReadersPending)
2976 // Notify the asynchronous reader that a file has grown so that it may service outstanding async reads
2979 iBody->iNotifyAsyncReadersPending = aNotifyAsyncReadersPending;
2982 TBool CFileCB::NotifyAsyncReadersPending() const
2984 return iBody->iNotifyAsyncReadersPending;
2988 void CFileCB::ResetReadAhead()
2990 CFileCache* fileCache = FileCache();
2992 fileCache->ResetReadAhead();
2995 void CFileCB::SetDeleteOnClose()
2997 iBody->iDeleteOnClose = ETrue;
3000 TBool CFileCB::DeleteOnClose() const
3002 return iBody->iDeleteOnClose;
3005 TInt CFileCB::GetInterfaceTraced(TInt aInterfaceId, TAny*& aInterface, TAny* aInput)
3007 TRACE2(UTF::EBorder, UTraceModuleFileSys::ECFileCBGetInterface, EF32TraceUidFileSys, aInterfaceId, aInput);
3009 TInt r = GetInterface(aInterfaceId, aInterface, aInput);
3011 TRACERET2(UTF::EBorder, UTraceModuleFileSys::ECFileCBGetInterfaceRet, EF32TraceUidFileSys, r, aInterface);
3016 CFileBody::CFileBody(CFileCB* aFileCB, CFileCB::MExtendedFileInterface* aExtendedFileInterface)
3018 iExtendedFileInterface(aExtendedFileInterface ? aExtendedFileInterface : this),
3021 iFairSchedulingLen = TFileCacheSettings::FairSchedulingLen(iFileCB->DriveNumber());
3022 iMaxSupportedFileSize = KMaxSupportedFileSize;
3026 CFileBody::~CFileBody()
3028 if (iAsyncReadRequests)
3030 iAsyncReadRequests->Close();
3031 delete iAsyncReadRequests;
3036 void CFileBody::InitL()
3038 iAsyncReadRequests = new(ELeave) RArray<TAsyncReadRequest>(KAsyncRequestArrayGranularity, _FOFF(TAsyncReadRequest, iEndPos));
3043 TInt TFsFileClamp::Initialise(CFsRequest* aRequest)
3045 // Initialise function for RFile::Clamp [EFsFileClamp]
3048 TSecureId aUID = aRequest->Message().SecureId();
3049 if (aUID!=KEstartUidValue && aUID!=KFileServerUidValue)
3053 info.iCaps.iCaps[0]=0;
3054 info.iCaps.iCaps[1]=0;
3055 info.iSecureId=KEstartUidValue;
3056 PlatSec::PolicyCheckFail(aRequest->Message(),info,"File Clamp");
3057 info.iSecureId=KFileServerUidValue;
3058 PlatSec::PolicyCheckFail(aRequest->Message(),info,"File Clamp");
3059 return KErrPermissionDenied;
3062 TInt r=DoInitialise(aRequest);
3066 // The clamp API is only supported on non-removable media
3067 CFileShare* share=(CFileShare*)aRequest->ScratchValue();
3069 share->File().Drive().DriveInfo(di);
3070 if (!(di.iDriveAtt & KDriveAttInternal))
3071 r = KErrNotSupported;
3077 TInt TFsFileClamp::DoRequestL(CFsRequest* aRequest)
3079 // Request function for RFile::Clamp [EFsFileClamp]
3084 // Flush data for this file, if it is open for writing, before clamping
3085 CFileShare* share=(CFileShare*)aRequest->ScratchValue();
3087 if (((share->iMode&EFileWrite)) || ((share->File().Att()&KEntryAttModified)))
3089 r=share->CheckMount();
3093 TRACE1(UTF::EBorder, UTraceModuleFileSys::ECFileCBFlushDataL, EF32TraceUidFileSys, &share->File());
3094 TRAP(r,share->File().FlushDataL());
3095 TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECFileCBFlushDataLRet, EF32TraceUidFileSys, r);
3102 r=aRequest->Drive()->ClampFile(aRequest->Src().FullName().Mid(2),
3104 // Write clamp information to user
3105 TPckgC<RFileClamp> pkClamp(clamp);
3106 aRequest->WriteL(KMsgPtr0, pkClamp);
3111 TInt TFsUnclamp::Initialise(CFsRequest* aRequest)
3113 // Initialise function for RFs::Unclamp [EFsUnclamp]
3116 TSecureId aUID = aRequest->Message().SecureId();
3117 if (aUID!=KEstartUidValue && aUID!=KFileServerUidValue)
3121 info.iCaps.iCaps[0]=0;
3122 info.iCaps.iCaps[1]=0;
3123 info.iSecureId=KEstartUidValue;
3124 PlatSec::PolicyCheckFail(aRequest->Message(),info,"File Unclamp");
3125 info.iSecureId=KFileServerUidValue;
3126 PlatSec::PolicyCheckFail(aRequest->Message(),info,"File Unclamp");
3127 return KErrPermissionDenied;
3130 TPckg<RFileClamp> pkClamp(clamp);
3131 aRequest->ReadL(KMsgPtr0, pkClamp);
3132 TInt driveNo=(I64HIGH(clamp.iCookie[1]));
3133 TDrive& drive=TheDrives[driveNo];
3134 aRequest->SetDrive(&drive);
3139 TInt TFsUnclamp::DoRequestL(CFsRequest* aRequest)
3141 // Request function for RFs::Unclamp [EFsUnclamp]
3145 TPckg<RFileClamp> pkClamp(clamp);
3146 aRequest->ReadL(KMsgPtr0, pkClamp);
3147 TDrive* drive=aRequest->Drive();
3148 CMountCB* mount=(CMountCB*)&(drive->CurrentMount());
3149 return(drive->UnclampFile(mount,&clamp));
3152 CMountBody::CMountBody(CMountCB* aMountCB, CMountCB::MFileAccessor* aFileAccessor, CMountCB::MFileExtendedInterface* aFileInterface)
3154 // Constructor for private body class
3156 : iMountCB(aMountCB),
3157 iFileAccessor(aFileAccessor?aFileAccessor:this),
3158 iFileExtendedInterface(aFileInterface?aFileInterface:this)
3162 CMountBody::~CMountBody()
3164 // Destructor for private body class
3167 __ASSERT_DEBUG(iClampIdentifiers.Count() == 0, User::Invariant());
3168 iClampIdentifiers.Close();
3171 TInt CMountBody::ClampFile(const TInt aDriveNo,const TDesC& aName,TAny* aHandle)
3173 // Need CMountCB::MFileAccessor interface support
3174 if(iFileAccessor==this)
3175 return KErrNotSupported;
3177 // Get unique identifier for the file
3178 TInt64 uniqueId = 0;
3179 TInt r = iFileAccessor->GetFileUniqueId(aName,uniqueId);
3183 // Populate the RFileClamp clamp instance and store it in iClampIdentifiers
3184 RFileClamp* newClamp = (RFileClamp*)aHandle;
3185 newClamp->iCookie[0]=uniqueId;
3186 newClamp->iCookie[1]=MAKE_TINT64(aDriveNo,++iClampCount);
3187 r = iClampIdentifiers.InsertInOrder((const RFileClamp&)*newClamp,&CompareClampsByIdAndCount);
3191 // Indicate that (at least) one file is clamped on this drive
3192 iMountCB->Drive().SetClampFlag(ETrue);
3193 AddResource(*iMountCB);
3198 TInt CMountBody::UnclampFile(RFileClamp* aHandle)
3200 // Need CMountCB::MFileAccessor interface support
3201 if(iFileAccessor==this)
3202 return KErrNotSupported;
3205 if((idx = iClampIdentifiers.Find((const RFileClamp&)*aHandle,&FindClampByIdAndCount)) < KErrNone)
3207 // This file is not 'clamped'
3211 // If we're removing the last clamp and a dismount has been deferred (due to files being clamped),
3212 // then DeferredDismount() will trigger a dismount: before this happens we need to flush all
3213 // dirty data on this drive;
3214 TDrive& drive = iMountCB->Drive();
3215 TInt noOfClamps = NoOfClamps();
3216 if (noOfClamps == 1 && drive.DismountDeferred())
3218 TInt r = drive.FlushCachedFileInfo(ETrue);
3219 if (r == CFsRequest::EReqActionBusy)
3223 RemoveResource(*iMountCB);
3224 iClampIdentifiers.Remove(idx);
3227 // If this was the last clamp, check for outstanding dismount requests
3228 if (noOfClamps == 1)
3230 ASSERT(NoOfClamps() == 0);
3231 drive.SetClampFlag(EFalse);
3232 if (drive.DismountDeferred())
3233 r = drive.DeferredDismount();
3240 TInt CMountBody::IsFileClamped(const TInt64 aUniqueId)
3242 // Need CMountCB::MFileAccessor interface support
3243 if(iFileAccessor==this)
3244 return KErrNotSupported;
3246 // Encapsulate the unique identifier in an appropriate class
3247 RFileClamp newClamp;
3248 newClamp.iCookie[0]=aUniqueId;
3249 // Search for (any) entry in iClampIdentifiers holding this value
3250 TInt index=iClampIdentifiers.Find((const RFileClamp&)newClamp,&FindClampById);
3251 return (index==KErrNotFound?0:1);
3254 TInt CMountBody::NoOfClamps()
3256 // Need CMountCB::MFileAccessor interface support
3257 if(iFileAccessor==this)
3258 return KErrNotSupported;
3260 // This will return zero if ClampFile has not previously been invoked
3261 return iClampIdentifiers.Count();
3264 TInt CMountBody::CompareClampsById(const RFileClamp& aClampA, const RFileClamp& aClampB)
3266 if(aClampA.iCookie[0] < aClampB.iCookie[0]) return 1;
3267 if(aClampA.iCookie[0] > aClampB.iCookie[0]) return -1;
3271 TInt CMountBody::CompareClampsByIdAndCount(const RFileClamp& aClampA, const RFileClamp& aClampB)
3273 if(aClampA.iCookie[0] > aClampB.iCookie[0]) return 1;
3274 if(aClampA.iCookie[0] < aClampB.iCookie[0]) return -1;
3275 // Now compare the count values
3276 if(I64LOW(aClampA.iCookie[1]) > I64LOW(aClampB.iCookie[1])) return 1;
3277 if(I64LOW(aClampA.iCookie[1]) < I64LOW(aClampB.iCookie[1])) return -1;
3281 TInt CMountBody::FindClampById(const RFileClamp& aClampA, const RFileClamp& aClampB)
3283 return (TInt)(!CompareClampsById(aClampA, aClampB));
3287 TInt CMountBody::FindClampByIdAndCount(const RFileClamp& aClampA, const RFileClamp& aClampB)
3289 return (TInt)(!CompareClampsByIdAndCount(aClampA, aClampB));
3292 void CMountBody::SetProxyDriveDismounted()
3294 iProxyDriveDismounted = ETrue;
3297 TBool CMountBody::ProxyDriveDismounted()
3299 return iProxyDriveDismounted;
3303 TInt CMountBody::GetFileUniqueId(const TDesC& /*aName*/, TInt64& /*aUniqueId*/)
3305 return KErrNotSupported;
3307 TInt CMountBody::Spare3(TInt /*aVal*/, TAny* /*aPtr1*/, TAny* /*aPtr2*/)
3309 return KErrNotSupported;
3311 TInt CMountBody::Spare2(TInt /*aVal*/, TAny* /*aPtr1*/, TAny* /*aPtr2*/)
3313 return KErrNotSupported;
3315 TInt CMountBody::Spare1(TInt /*aVal*/, TAny* /*aPtr1*/, TAny* /*aPtr2*/)
3317 return KErrNotSupported;
3319 void CMountBody::ReadSection64L(const TDesC& aName,TInt64 aPos,TAny* aTrg,TInt aLength,const RMessagePtr2& aMessage)
3321 if((TUint64)aPos > KMaxLegacyFileSize)
3322 User::Leave(KErrNotSupported);
3324 iMountCB->ReadSectionL(aName, I64LOW(aPos), aTrg, aLength, aMessage);
3327 TBool CFileBody::ExtendedFileInterfaceSupported()
3329 return (iExtendedFileInterface==this) ? (TBool)EFalse : (TBool)ETrue;
3332 // default implementations of MExtendedFileInterface
3333 void CFileBody::ReadL(TInt64 aPos,TInt& aLength,TDes8* aDes,const RMessagePtr2& aMessage, TInt aOffset)
3335 if ((TUint64)aPos > KMaxLegacyFileSize || aOffset > 0)
3336 User::Leave(KErrNotSupported);
3338 iFileCB->ReadL((TInt) aPos, aLength, aDes, aMessage);
3341 void CFileBody::WriteL(TInt64 aPos,TInt& aLength,const TDesC8* aDes,const RMessagePtr2& aMessage, TInt aOffset)
3343 if ((TUint64)aPos > KMaxLegacyFileSize || aOffset > 0)
3344 User::Leave(KErrNotSupported);
3346 iFileCB->WriteL((TInt) aPos, aLength, aDes, aMessage);
3349 void CFileBody::SetSizeL(TInt64 aSize)
3351 if ((TUint64)aSize > KMaxLegacyFileSize)
3352 User::Leave(KErrNotSupported);
3354 iFileCB->SetSizeL((TInt) aSize);
3357 //---------------------------------------------------------------------------------------------------------------------
3359 This method allows file system to set maximum file size it supports.
3360 This can be called on instantiation of the CFileCB derived class object by the file system implementation.
3361 If this method is not called, the iMaxSupportedFileSize will have default value KMaxTUint64
3363 @param aMaxFileSize maximum file size supported by file system
3365 EXPORT_C void CFileCB::SetMaxSupportedSize(TUint64 aMaxFileSize)
3367 iBody->iMaxSupportedFileSize = aMaxFileSize;
3371 @return maximum supported file size (depends on the file system created it)
3373 TUint64 CFileCB::MaxSupportedSize(void) const
3375 return iBody->iMaxSupportedFileSize;
3378 //---------------------------------------------------------------------------------------------------------------------
3381 Gets the size of the file.
3383 This is 64-bit variant for CFileCB::Size().
3384 This shall be used by File Systems supporting file size > 4GB - 1 to query the file size
3385 inplace of CFileCB::Size() or CFileCB::iSize.
3388 @see CFileCB::Size()
3392 @return The size of the file.
3394 EXPORT_C TInt64 CFileCB::Size64() const
3396 __ASSERT_DEBUG(iBody != NULL, Fault(EFileBodyIsNull));
3397 const TInt64 size = MAKE_TINT64(iBody->iSizeHigh,iSize);
3401 //---------------------------------------------------------------------------------------------------------------------
3403 Sets the size of the file.
3405 This is 64-bit variant for CFileCB::SetSize().
3406 This should be used by File Systems supporting file size > 4GB - 1 to set the file size
3407 inplace of CFileCB::SetSize() or CFileCB::iSize.
3410 @see CFileCB::SetSize()
3414 @param aSize The size of the file.
3415 @param aDriveLocked The status of the Drive Lock. If it is EFalse,
3416 the file size shall be modified after acquiring the iLock mutex and if it is ETrue,
3417 the file size shall be modified without aquiring the iLock mutex.
3419 EXPORT_C void CFileCB::SetSize64(TInt64 aSize, TBool aDriveLocked)
3423 iSize = (TInt)I64LOW(aSize);
3424 iBody->iSizeHigh = (TInt)I64HIGH(aSize);
3429 iSize = (TInt)I64LOW(aSize);
3430 iBody->iSizeHigh = (TInt)I64HIGH(aSize);
3436 /** used to organize key comparison for the TFileShareLock*/
3437 TInt LockOrder(const TFileShareLock& aMatch, const TFileShareLock& anEntry)
3440 if(aMatch.PosLow() > anEntry.PosLow())
3442 else if(aMatch.PosLow() < anEntry.PosLow())
3449 //---------------------------------------------------------------------------------------------------------------------
3451 Find a lock inclusive of aPosLow to aPosHigh.
3453 TInt CFileCB::FindLock64(TInt64 aPosLow, TInt64 aPosHigh)
3456 const TInt count=FileLocks().Count();
3457 for (TInt i=0; i<count; i++)
3460 const TFileShareLock& lock=FileLocks()[i];
3462 if(lock.PosLow() > (TUint64)aPosHigh)
3463 return KErrNotFound;
3465 if(lock.MatchByPos(aPosLow, aPosHigh))
3469 return KErrNotFound;
3472 //---------------------------------------------------------------------------------------------------------------------
3474 Add a lock on a range.
3476 TInt CFileCB::AddLock64(CFileShare* aFileShare,TInt64 aPos,TInt64 aLength)
3478 const TUint64 posHigh=aPos+aLength-1;
3481 {//-- Lock overflow check
3482 const TUint64 KMaxFileSize = aFileShare->IsFileModeBig() ? MaxSupportedSize() : KMaxLegacyFileSize;
3483 if(posHigh > KMaxFileSize)
3484 return KErrArgument;
3488 TInt r=CheckLock64(NULL, aPos, aLength);
3492 TFileShareLock lock(aFileShare, aPos, posHigh);
3494 TLinearOrder<TFileShareLock> lockOrder(LockOrder);
3495 r=FileLocks().InsertInOrder(lock, lockOrder);
3496 __ASSERT_ALWAYS(r!=KErrAlreadyExists,Fault(EFileDuplicateLock));
3501 //---------------------------------------------------------------------------------------------------------------------
3503 Remove a lock on a range.
3505 TInt CFileCB::RemoveLock64(CFileShare* aFileShare, TInt64 aPos, TInt64 aLength)
3507 const TUint64 posHigh = aPos+aLength-1;
3509 {//-- Lock overflow check
3510 const TUint64 KMaxFileSize = aFileShare->IsFileModeBig() ? MaxSupportedSize() : KMaxLegacyFileSize;
3511 if(posHigh > KMaxFileSize)
3512 return KErrArgument;
3515 const TInt pos=FindLock64(aPos, posHigh);
3516 if (pos==KErrNotFound)
3517 return KErrNotFound;
3519 const TFileShareLock& lock=FileLocks()[pos];
3520 if (!lock.MatchOwner(aFileShare) || lock.PosLow() != (TUint64)aPos || lock.PosHigh() != posHigh)
3521 return KErrNotFound;
3524 FileLocks().Remove(pos);
3529 //---------------------------------------------------------------------------------------------------------------------
3531 Check if a range is available.
3532 @param aFileShare pointer to FileShare object. NULL only when is called from CFileCB::AddLock64()
3535 TInt CFileCB::CheckLock64(CFileShare* aFileShare,TInt64 aPos,TInt64 aLength)
3537 const TUint64 posHigh=aPos+aLength-1;
3539 //-- Lock overflow check. It is OK to have a lock that is beyond the real file size.
3540 //-- if aFileShare == NULL, this is the call from AddLock64 and the position is already checked.
3543 const TUint64 KMaxFileSize = aFileShare->IsFileModeBig() ? MaxSupportedSize() : KMaxLegacyFileSize;
3544 if(posHigh > KMaxFileSize)
3545 return KErrNone; //-- OK, there can't be any locks beyond the max. supported file length
3549 TInt lockIdx=FindLock64(aPos, posHigh);
3550 if (lockIdx == KErrNotFound)
3553 const TInt count=FileLocks().Count();
3554 const TFileShareLock* lock=(&FileLocks()[lockIdx]);
3558 if (!lock->MatchOwner(aFileShare))
3561 if (lock->PosHigh() >= posHigh)
3565 if (lockIdx >= count)
3568 lock=&FileLocks()[lockIdx];
3570 if (posHigh < lock->PosLow())
3578 //#####################################################################################################################
3579 //# TFileShareLock class implementation
3580 //#####################################################################################################################
3582 TFileShareLock::TFileShareLock(const CFileShare* aOwner, TUint64 aPosLow, TUint64 aPosHigh)
3583 : iOwner(aOwner), iPosLow(aPosLow), iPosHigh(aPosHigh)
3589 TUint64 TFileShareLock::PosLow() const
3595 TUint64 TFileShareLock::PosHigh() const
3600 TBool TFileShareLock::MatchOwner(const CFileShare* aShare) const
3602 return (aShare == iOwner);
3606 @return ETrue if aPosLow and PosHigh match the lock boundaries
3608 TBool TFileShareLock::MatchByPos(TUint64 aPosLow, TUint64 aPosHigh) const
3610 if(PosLow() > aPosHigh)
3613 if ((aPosLow >= PosLow() && aPosLow <= PosHigh()) ||
3614 (aPosHigh >= PosLow() && aPosHigh <= PosHigh()) ||
3615 (aPosLow <= PosLow() && aPosHigh >= PosHigh() ))