Update contrib.
1 // Copyright (c) 1996-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.
14 // f32\sfat\sl_file.cpp
19 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
20 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
22 //!! WARNING!! DO NOT edit this file !! '\sfat' component is obsolete and is not being used. '\sfat32'replaces it
24 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
25 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
32 const TInt KSeekIndexSize=128; // Cache 128 clusters
33 const TInt KSeekIndexSizeLog2=7;
34 const TInt KFirstClusterNum=2;
36 CFatFileCB::CFatFileCB()
39 __PRINT1(_L("CFatFileCB created 0x%x"),this);
42 CFatFileCB::~CFatFileCB()
44 __PRINT1(_L("CFatFileCB deleted 0x%x"),this);
46 //-- a nasty trick to find out if the CFatFileCB is in consistent state on the moment of destruction.
47 //-- Because of OOM conditions CFatFileCB might not be fully constructed and to be deleted, while FlushAll()
48 //-- implies valid iMount.
49 const CMountCB* pMount = &Mount();
51 {//-- do some finalisation work if CMountCB is valid
52 if (iAtt&KEntryAttModified)
53 TRAP_IGNORE(FlushAllL());
60 void CFatFileCB::CreateSeekIndex()
62 // Create a seek index
66 iSeekIndex = new TUint32[KSeekIndexSize];
67 if (iSeekIndex == NULL)
70 Mem::FillZ(iSeekIndex, sizeof(TUint32) * KSeekIndexSize);
72 iSeekIndexSize=CalcSeekIndexSize(Size());
75 TInt CFatFileCB::SeekToPosition(TInt aNewRelCluster,TInt aClusterOffset)
77 // Use the seek index to set iCurrentPos.iCluster as close as possible to aNewRelCluster
78 // Return aNewRelCluster-aCurrentPos.iCluster
81 TInt clusterOffset=aClusterOffset;
82 TInt seekPos=(aNewRelCluster>>iSeekIndexSize)-1;
83 __ASSERT_DEBUG(seekPos<KSeekIndexSize,Fault(EFatFileSeekIndexTooSmall));
85 while(seekPos>=0 && iSeekIndex[seekPos]==0 && clusterOffset!=0)
90 if (clusterOffset==0) // Counted back to the current cluster
91 return(aClusterOffset);
94 iCurrentPos.iCluster=iStartCluster;
95 return(aNewRelCluster);
98 iCurrentPos.iCluster=iSeekIndex[seekPos];
99 return(aNewRelCluster-((seekPos+1)<<iSeekIndexSize));
102 void CFatFileCB::SetSeekIndexValueL(TInt aRelCluster,TInt aStoredCluster)
104 // Sets a value in the seekindex
108 TInt seekPos=(aRelCluster>>iSeekIndexSize)-1;
109 __ASSERT_DEBUG(seekPos<KSeekIndexSize,Fault(EFatFileSeekIndexTooSmall));
110 __ASSERT_DEBUG(seekPos>=0,Fault(EFatFileSeekIndexTooSmall2));
111 iSeekIndex[seekPos] = aStoredCluster;
114 TBool CFatFileCB::IsSeekBackwards(TUint aPos)
116 // Return true if aPos<currentPos
120 TUint cluster=iCurrentPos.iCluster<<ClusterSizeLog2();
121 TInt offset=ClusterRelativePos(iCurrentPos.iPos);
122 TUint currentPos=cluster+offset;
123 return(aPos<currentPos);
126 void CFatFileCB::CheckPosL(TUint aPos)
128 // Check that the file is positioned correctly.
129 // If aPos<currentPos attempt to guess the new position.
132 __PRINT1(_L("CFatFileCB::CheckPosL(%d)"), aPos);
133 if (aPos==iCurrentPos.iPos)
135 __ASSERT_DEBUG(aPos <= (TUint)Size(), Fault(EFatFilePosBeyondEnd));
137 if (iFileSizeModified && IsSeekBackwards(aPos))
140 TUint newRelCluster=aPos>>ClusterSizeLog2();
141 if ( aPos && (aPos==(newRelCluster<<ClusterSizeLog2())) )
143 TUint oldRelCluster=iCurrentPos.iPos>>ClusterSizeLog2();
144 if ( iCurrentPos.iPos && (iCurrentPos.iPos==(oldRelCluster<<ClusterSizeLog2())) )
146 TInt clusterOffset=newRelCluster-oldRelCluster;
147 TInt oldCluster=iCurrentPos.iCluster;
148 iCurrentPos.iPos=aPos;
149 if (clusterOffset==0)
151 TInt seekOffset=clusterOffset;
152 if (iSeekIndex!=NULL)
153 { // Can alter iCurrentPos.iCluster
154 seekOffset=SeekToPosition(newRelCluster,seekOffset);
158 if (clusterOffset==-1 && seekOffset!=1)
159 { // Check previous cluster
160 TInt cluster=oldCluster-1;
161 if (FAT().GetNextClusterL(cluster) && cluster==oldCluster)
163 iCurrentPos.iCluster=oldCluster-1;
169 seekOffset=newRelCluster;
170 iCurrentPos.iCluster=iStartCluster;
174 if (!FAT().GetNextClusterL(iCurrentPos.iCluster))
176 __PRINT(_L("CFatFileCB::CheckPosL() corrupt#1"));
177 User::Leave(KErrCorrupt);
179 TInt cluster=newRelCluster-seekOffset;
180 if (iSeekIndex!=NULL && cluster && (cluster>>iSeekIndexSize)<<iSeekIndexSize==cluster)
181 SetSeekIndexValueL(cluster,iCurrentPos.iCluster);
185 void CFatFileCB::SetL(const TFatDirEntry& aFatDirEntry,TShare aShare,const TEntryPos& aPos)
187 // Initialize FileCB from entry data
191 __PRINT(_L("CFatFileCB::SetL"));
192 SetSize(aFatDirEntry.Size());
193 iCurrentPos.iCluster= FatMount().StartCluster(aFatDirEntry);
194 iStartCluster=iCurrentPos.iCluster;
196 iAtt=aFatDirEntry.Attributes();
197 iModified= aFatDirEntry.Time(FatMount().TimeOffset());
201 SetMaxSupportedSize(KMaxSupportedFatFileSize);
204 //-----------------------------------------------------------------------------
205 // from CFileCB::MExtendedFileInterface
206 void CFatFileCB::ReadL(TInt64 aPos,TInt& aLength, TDes8* aDes, const RMessagePtr2& aMessage, TInt aOffset)
208 __PRINT2(_L("CFatFileCB::ReadL aFilePos=%LU aLength=%d"),aPos,aLength);
210 if((TUint64)aPos > KMaxSupportedFatFileSize-1)
211 User::Leave(KErrNotSupported); //-- max. position in the file is 0xFFFFFFFE
213 FatMount().CheckStateConsistentL();
215 CheckPosL(I64LOW(aPos));
217 const TUint startPos = iCurrentPos.iPos;
218 const TUint curSize = (TUint)Size();
219 const TUint length = (TUint)aLength;
221 if((startPos + length > curSize) || (startPos > startPos + length) )
222 aLength=curSize-startPos;
224 FatMount().ReadFromClusterListL(iCurrentPos,aLength,aDes,aMessage,aOffset);
225 aLength=iCurrentPos.iPos-startPos;
229 void CFatFileCB::ReadL(TInt aFilePos,TInt& aLength,const TAny* aTrg,const RMessagePtr2& aMessage)
231 ReadL(TInt64(aFilePos),aLength,(TDes8*) aTrg,aMessage, 0);
234 //-----------------------------------------------------------------------------
235 // from CFileCB::MExtendedFileInterface
236 void CFatFileCB::WriteL(TInt64 aPos,TInt& aLength,const TDesC8* aSrc,const RMessagePtr2& aMessage, TInt aOffset)
238 __PRINT2(_L("CFatFileCB::WriteL aFilePos=%LU aLength=%d"),aPos,aLength);
239 // FAT supports 32 bits only for file size
240 TUint64 endPos = aPos + aLength;
241 if(endPos > KMaxSupportedFatFileSize)
242 User::Leave(KErrNotSupported);
244 FatMount().CheckStateConsistentL();
245 FatMount().CheckWritableL();
246 const TUint pos = I64LOW(aPos);
249 const TUint startCluster = (TUint)iStartCluster;
250 const TUint length = (TUint)aLength;
252 endPos = iCurrentPos.iPos + length;
253 if ((endPos > (TUint)Size()) ||
254 (iCurrentPos.iPos > endPos) ) // Overflow condition
255 DoSetSizeL(iCurrentPos.iPos+length,EFalse);
257 TUint startPos=iCurrentPos.iPos;
261 TRAPD(ret, FatMount().WriteToClusterListL(iCurrentPos,aLength,aSrc,aMessage,aOffset,badcluster, goodcluster));
263 if (ret == KErrCorrupt || ret == KErrDied)
265 if(startCluster == 0)
266 { //Empty File, revert all the clusters allocated.
267 TInt cluster = iStartCluster;
272 iCurrentPos.iCluster = 0;
273 iCurrentPos.iPos = 0;
275 FAT().FreeClusterListL(cluster);
279 { //Calculate the clusters required based on file size, revert extra clusters if allocated.
280 const TUint curSize = (TUint)Size();
281 TUint ClustersNeeded = curSize >> ClusterSizeLog2();
282 if(curSize > (ClustersNeeded << ClusterSizeLog2()))
287 TInt cluster = iStartCluster;
288 while(--ClustersNeeded)
290 FAT().GetNextClusterL(cluster);
293 iCurrentPos.iCluster = cluster;
295 if (FAT().GetNextClusterL(cluster))
297 FAT().FreeClusterListL(cluster);
300 FAT().WriteFatEntryEofL(iCurrentPos.iCluster);
305 User::LeaveIfError(ret);
309 if(iStartCluster == badcluster)
311 iStartCluster = goodcluster;
312 FlushStartClusterL();
316 TInt aCluster = iStartCluster;
319 if((TUint)badcluster == FAT().ReadL(aCluster))
321 FAT().WriteL(aCluster, goodcluster);
326 while(FAT().GetNextClusterL(aCluster));
329 aLength=iCurrentPos.iPos-startPos;
331 if(FatMount().IsRuggedFSys() && pos+(TUint)aLength>(TUint)Size())
333 WriteFileSizeL(pos+aLength);
339 void CFatFileCB::WriteL(TInt aFilePos,TInt& aLength,const TAny* aSrc,const RMessagePtr2& aMessage)
341 WriteL(TInt64(aFilePos),aLength,(TDesC8*) aSrc,aMessage, 0);
346 //-----------------------------------------------------------------------------
348 void CFatFileCB::ResizeIndex(TInt aNewMult,TUint aNewSize)
350 // Resize the seek index to accomodate a larger or smaller filesize
351 // Assumes KSeekIndexSize is a power of 2.
355 TInt maxNewIndex=aNewSize>>(ClusterSizeLog2()+aNewMult);
359 TInt indexEnd=KSeekIndexSize;
360 TInt newValEnd=maxNewIndex;
362 if (iSeekIndexSize<aNewMult)
365 TInt step=1<<(aNewMult-iSeekIndexSize);
367 while(index<indexEnd && newVal<newValEnd)
369 iSeekIndex[newVal] = iSeekIndex[index];
373 while(newVal<indexEnd)
374 iSeekIndex[newVal++] = 0;
378 TInt diffSize = iSeekIndexSize-aNewMult;
379 TInt oldVal=(KSeekIndexSize>>diffSize) - 1;
380 TInt newVal=indexEnd-1;
381 TInt skip=(1<<diffSize)-1;
383 if ((iSeekIndexSize - aNewMult) > KSeekIndexSizeLog2)
385 ClearIndex(0); //-- Invalidate every entry.
392 iSeekIndex[newVal--] = iSeekIndex[oldVal--];
395 for(TInt i=skip;i>0;i--)
397 iSeekIndex[newVal--] = 0;
403 iSeekIndexSize=aNewMult;
408 Zero freed clusters in the index
410 @param aNewSize new size of the file that the index corresponds to.
411 if = 0 all existing index will be zero filled
413 void CFatFileCB::ClearIndex(TUint aNewSize)
421 //-- zero fill all the array
422 Mem::FillZ(iSeekIndex, KSeekIndexSize*sizeof(TUint32));
426 // Files that fill up a cluster exactly do not have a trailing empty
427 // cluster. So the entry for that position must also be invalidated
429 TInt firstInvalidIndex=aNewSize>>(iSeekIndexSize+ClusterSizeLog2());
431 TInt indexLen=KSeekIndexSize-firstInvalidIndex;
433 Mem::FillZ(iSeekIndex+firstInvalidIndex, indexLen * sizeof(TUint32));
436 TInt CFatFileCB::CalcSeekIndexSize(TUint aSize)
438 // Find the nearest power of 2 > aSize
442 const TUint indexSize=KSeekIndexSize<<ClusterSizeLog2();//KSeekIndexSize=128
443 if (aSize<=indexSize)
450 return (count - (KSeekIndexSizeLog2 + ClusterSizeLog2()) + 1);
453 //-----------------------------------------------------------------------------
455 void CFatFileCB::SetSizeL(TInt64 aSize)
457 __PRINT(_L("CFatFileCB::SetSizeL"));
459 // FAT supports 32 bits only for file size
461 User::Leave(KErrNotSupported);
463 if(FatMount().IsRuggedFSys())
464 DoSetSizeL(I64LOW(aSize),ETrue);
466 DoSetSizeL(I64LOW(aSize),EFalse);
470 void CFatFileCB::SetSizeL(TInt aSize)
472 // Envelope function around DoSetSizeL to enable aSize to
473 // be written to disk for rugged fat file system
476 SetSizeL(TInt64(aSize));
479 void CFatFileCB::DoSetSizeL(TUint aSize,TBool aIsSizeWrite)
481 // Extend or truncate the file.
482 // Expects the modified attribute and iSize are set afterwards.
483 // Does not alter iCurrentPos, the current file position.
484 // Writes size of file to disk if aIsSizeWrite set
487 __PRINT2(_L("CFatFileCB::DoSetSizeL sz:%d, fileWrite=%d"),aSize ,aIsSizeWrite);
489 FatMount().CheckStateConsistentL();
490 FatMount().CheckWritableL();
493 // Can not change the file size if it is clamped
494 if(Mount().IsFileClamped(MAKE_TINT64(0,iStartCluster)) > 0)
495 User::Leave(KErrInUse);
497 iFileSizeModified=ETrue;
499 TInt newIndexMult=CalcSeekIndexSize(aSize);
500 if (iSeekIndex!=NULL && newIndexMult!=iSeekIndexSize)
501 ResizeIndex(newIndexMult,aSize);
506 ClearIndex(0); //-- clear seek index array
507 TInt cluster=iStartCluster;
512 FAT().FreeClusterListL(cluster);
517 if (aSize<(TUint)Size())
519 if(aIsSizeWrite) // write file size if decreasing
520 WriteFileSizeL(aSize);
522 TInt cluster=iCurrentPos.iCluster;
523 if (FAT().GetNextClusterL(cluster))
525 FAT().WriteFatEntryEofL(iCurrentPos.iCluster);
526 FAT().FreeClusterListL(cluster);
533 TUint newSize=aSize>>ClusterSizeLog2(); // Number of clusters we now need
534 if (aSize > (newSize<<ClusterSizeLog2()))
535 newSize++; // File size is not an exact multiple of cluster size
536 // Increment the number of clusters required to accomodate tail
538 if (iStartCluster==0)
540 //-- FAT().FreeClusterHint() will give us a hint of the last free cluster
541 ClearIndex(0); //-- clear seek index array
542 TInt tempStartCluster=FAT().AllocateClusterListL(newSize, FAT().FreeClusterHint());
544 iCurrentPos.iCluster=tempStartCluster;
545 iStartCluster=tempStartCluster;
551 const TUint curSize = (TUint)Size();
552 TUint oldSize=curSize>>ClusterSizeLog2(); // Number of clusters we had previously
553 if (curSize>(oldSize<<ClusterSizeLog2()))
556 TInt newClusters=newSize-oldSize; // Number of clusters we need to prepare
559 TEntryPos currentPos=iCurrentPos;
561 FAT().ExtendClusterListL(newClusters,iCurrentPos.iCluster);
562 iCurrentPos=currentPos;
565 if(aIsSizeWrite) // write file size if increasing
566 WriteFileSizeL(aSize);
570 //-----------------------------------------------------------------------------
572 Set the entry's attributes and modified time.
574 void CFatFileCB::SetEntryL(const TTime& aTime,TUint aSetAttMask,TUint aClearAttMask)
576 __PRINT(_L("CFatFileCB::SetEntryL"));
578 FatMount().CheckStateConsistentL();
579 FatMount().CheckWritableL();
581 TUint setAttMask=aSetAttMask&KEntryAttMaskSupported;
582 if (setAttMask|aClearAttMask)
585 iAtt&=(~aClearAttMask);
587 if (aSetAttMask&KEntryAttModified)
589 iAtt|=KEntryAttModified;
593 This is a RuggedFAT - specific method. Writes file size to the corresponding field of this
594 file direcrory entry.
596 void CFatFileCB::WriteFileSizeL(TUint aSize)
598 __PRINT(_L("CFatFileCB::WriteFileSizeL"));
599 TEntryPos entryPos=iFileDirPos;
600 entryPos.iPos+=_FOFF(SFatDirEntry,iSize);
601 TPtrC8 size((TUint8*)&aSize,sizeof(TUint));
603 //-- use directory cache when dealing with directories
604 FatMount().DirWriteL(entryPos,size);
605 iFileSizeModified=EFalse;
608 //-----------------------------------------------------------------------------
610 Flush file size, attributes, time etc. to the media.
611 It doesn't matter if whole directory entry is being written of only part of it. Anyway, a single DOS
612 dir. entry always fits into 1 sector.
614 void CFatFileCB::FlushDataL()
616 __PRINT(_L("CFatFileCB::FlushDataL"));
620 //-----------------------------------------------------------------------------
622 Flush the fide directory entry data: files size, attributes, time etc.
624 void CFatFileCB::FlushAllL()
626 __PRINT(_L("CFatFileCB::FlushAllL()"));
628 if (Mount().IsCurrentMount()==EFalse)
629 User::Leave(KErrDisMounted);
631 FatMount().CheckStateConsistentL();
632 FatMount().CheckWritableL();
635 FatMount().ReadDirEntryL(iFileDirPos,entry);
636 __ASSERT_ALWAYS(entry.IsEndOfDirectory()==EFalse,User::Leave(KErrCorrupt));
637 entry.SetAttributes(iAtt&KEntryAttMaskSupported);
638 entry.SetSize(Size());
639 entry.SetTime(iModified, FatMount().TimeOffset());
640 entry.SetStartCluster(iStartCluster);
642 TBool setNotify = FatMount().GetNotifyUser();
645 FatMount().SetNotifyOff(); // do not launch a notifier
648 TRAPD(ret, FatMount().WriteDirEntryL(iFileDirPos,entry));
652 FatMount().SetNotifyOn();
655 User::LeaveIfError(ret);
656 iAtt&=(~KEntryAttModified);
657 iFileSizeModified=EFalse;
660 //-----------------------------------------------------------------------------
663 Rename already opened file.
664 @param aNewName new file name; all trailing dots from the name will be removed
666 void CFatFileCB::RenameL(const TDesC& aNewName)
668 __PRINT2(_L("CFatFileCB::RenameL[0x%x], name:%S"),this, &aNewName);
670 FatMount().CheckStateConsistentL();
671 FatMount().CheckWritableL();
673 const TPtrC fileName = RemoveTrailingDots(aNewName); //-- remove trailing dots from the name
676 FatMount().DoRenameOrReplaceL(*iFileName, fileName, CFatMountCB::EModeRename,iFileDirPos);
678 AllocBufferL(iFileName, fileName);
680 if(!FatMount().IsRuggedFSys())
685 //***********************************************************
686 //* BlockMap interface
687 //***********************************************************
689 TInt CFatFileCB::BlockMap(SBlockMapInfo& aInfo, TInt64& aStartPos, TInt64 aEndPos)
691 // Retrieves the block map of a given section of the file, in the FAT file system.
694 __PRINT2(_L("CFatFileCB::BlockMap aStartPos=%ld aEndPos=%ld"), aStartPos, aEndPos);
696 if ( I64HIGH(aStartPos) || I64HIGH(aEndPos) )
697 return KErrNotSupported;
699 TUint startPos = I64LOW(aStartPos);
700 TUint endPos = I64LOW(aEndPos);
702 // aEndPos will always be >=0 at this point
703 const TUint length = endPos - startPos;
705 // Store the position of cluster zero in aInfo
706 CFatMountCB& fatMount = FatMount();
709 TBusLocalDrive* locDrv;
710 if((fatMount.LocalDrive()->GetLocalDrive(locDrv)==KErrNone) && ((drvNo=GetLocalDriveNumber(locDrv))>=0) && (drvNo<KMaxLocalDrives))
711 aInfo.iLocalDriveNumber=drvNo;
713 return KErrNotSupported;
715 // Fetch the address of cluster 0
716 aInfo.iStartBlockAddress = fatMount.FAT().DataPositionInBytes(KFirstClusterNum);
718 TRAPD(r, CheckPosL(startPos));
722 aInfo.iBlockStartOffset = fatMount.ClusterRelativePos(iCurrentPos.iPos);
723 aInfo.iBlockGranularity = 1 << FatMount().ClusterSizeLog2();
724 const TUint myStartPos = iCurrentPos.iPos;
725 if ( myStartPos + length > (TUint)Size())
728 TRAP(r, FatMount().BlockMapReadFromClusterListL(iCurrentPos, length, aInfo));
732 aStartPos = iCurrentPos.iPos;
733 if ((I64LOW(aStartPos) == (TUint)Size()) || ( I64LOW(aStartPos) == (myStartPos + length)))
734 return KErrCompletion;
741 TInt CFatFileCB::GetInterface(TInt aInterfaceId,TAny*& aInterface,TAny* aInput)
745 case EExtendedFileInterface:
746 ((CFileCB::MExtendedFileInterface*&) aInterface) = this;
749 case EBlockMapInterface:
750 aInterface = (CFileCB::MBlockMapInterface*) this;
754 return FatMount().LocalDrive()->GetLocalDrive((TBusLocalDrive*&) aInterface);
757 return CFileCB::GetInterface(aInterfaceId,aInterface,aInput);
765 Overwrites file's start cluster (iStartCluster) in its directory entry.
767 void CFatFileCB::FlushStartClusterL()
769 __PRINT(_L("CFatFileCB::FlushStartClusterL"));
771 CFatMountCB& mount = FatMount();
772 TFatDirEntry dirEntry;
774 mount.ReadDirEntryL(iFileDirPos, dirEntry); //-- read this file's dir. entry
775 dirEntry.SetStartCluster(iStartCluster); //-- set new start cluster
776 mount.WriteDirEntryL(iFileDirPos, dirEntry);//-- write the entry back