persistentstorage/store/USTOR/UT_PERM.CPP
changeset 0 08ec8eefde2f
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     1 // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include <s32file.h>
       
    17 #include "UT_STD.H"
       
    18 
       
    19 //The default media block size, used in the computations, if the file system guarantees atomic "block write" file operations.
       
    20 const TInt KDefaultMediaBlockSize = 512;
       
    21 
       
    22 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
    23 /////////////////////              TPermanentStoreHeader               /////////////////////////////////////////////////////
       
    24 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
    25 
       
    26 //Returns false, if:
       
    27 // - the dirty bit is set (indicates commit phase #2 or #3 is not complete);
       
    28 // - the CRC check fails ("backup TOC ref", "handle" and "TOC ref" are protected by 16-bit CRC in the permanent store file header);
       
    29 TBool TPermanentStoreHeader::IsValid() const
       
    30 	{
       
    31 	if (IsDirty())
       
    32 		return EFalse;
       
    33 //
       
    34 	TUint16 crc=0;
       
    35 	Mem::Crc(crc,Ptr(),_FOFF(TPermanentStoreHeader,iCrc));
       
    36 	return crc==iCrc;
       
    37 	}
       
    38 
       
    39 //Sets the "backup TOC ref", "handle" and "TOC ref" in current TPermanentStoreHeader object.
       
    40 //16-bit CRC is calculated, based on the values of the input parameters, and stored together with them in the 
       
    41 //TPermanentStoreHeader object.
       
    42 void TPermanentStoreHeader::Set(TInt aBackupToc,TInt aHandle,TInt aReference)
       
    43 	{
       
    44 	iBackup=TUint32(aBackupToc)<<1;
       
    45 	iHandle=aHandle;
       
    46 	iRef=aReference;
       
    47 	iCrc=0;
       
    48 	Mem::Crc(iCrc,Ptr(),_FOFF(TPermanentStoreHeader,iCrc));
       
    49 	__ASSERT_DEBUG(IsValid(),User::Invariant());
       
    50 	}
       
    51 
       
    52 const TInt KTocGranularity=12;
       
    53 
       
    54 struct STocEntry
       
    55 	{
       
    56 	TInt32 handle;
       
    57 	TInt32 ref;
       
    58 	};
       
    59 
       
    60 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
    61 /////////////////////              CPermanentStoreToc               ////////////////////////////////////////////////////////
       
    62 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
    63 
       
    64 TInt CPermanentStoreToc::TEntry::Compare(const TEntry& aLeft, const TEntry& aRight)
       
    65 //
       
    66 // Ordering for Stream handles, return <0,0,>0 depending on comparison
       
    67 // The index part of the handle is only 24 bits, so just subtract the handles for result
       
    68 //
       
    69 	{
       
    70 	return (aLeft.handle&KMaskHandleIndex) - (aRight.handle&KMaskHandleIndex);
       
    71 	}
       
    72 
       
    73 CPermanentStoreToc* CPermanentStoreToc::NewL(TStreamPos aBase,TStreamExchange& aHost,TInt aToc,TInt aBaseReloc)
       
    74 	{
       
    75 	CPermanentStoreToc* table=new(ELeave) CPermanentStoreToc(aBase,aHost);
       
    76 	CleanupStack::PushL(table);
       
    77 	table->ConstructL(aToc,aBaseReloc);
       
    78 	CleanupStack::Pop();
       
    79 	return table;
       
    80 	}
       
    81 
       
    82 TBool CPermanentStoreToc::IsDelta() const
       
    83 //
       
    84 // Report whether the current TOC should be written as a delta, or a base TOC
       
    85 //
       
    86 	{
       
    87 	TInt delta = iEntries.Count();
       
    88 	if (delta >= KTocDeltaCap)
       
    89 		return EFalse;
       
    90 	TInt magic = iMagic + delta;
       
    91 	if (magic > KMaxTocDeltaMagic)
       
    92 		return EFalse;
       
    93 	return magic*KSizeTocDeltaEntry <= iCount*KSizeTocEntry - KSizeTocDeltaExtra;
       
    94 	}
       
    95 
       
    96 void CPermanentStoreToc::Move(TInt aToc,TInt anExtent)
       
    97 //
       
    98 // Final stage of compaction, update to address new TOC
       
    99 //
       
   100 	{
       
   101 	__ASSERT_DEBUG(anExtent<=iOff&&anExtent>=aToc&&anExtent-(aToc+KOffsetTocHeader)==iExt-iOff,User::Invariant());
       
   102 	if (!HasDelta())
       
   103 		{
       
   104 		// Base-toc only, update the base toc position as well
       
   105 		TInt window=iWindow-iTocExt;
       
   106 		iTocOff=aToc+KOffsetTocHeader;
       
   107 		iTocExt=anExtent;
       
   108 		iWindow=anExtent+window;
       
   109 		}
       
   110 	iOff = aToc+KOffsetTocHeader;
       
   111 	iExt = anExtent;
       
   112 	}
       
   113 
       
   114 TInt CPermanentStoreToc::RealizeL(TInt aPrimary,TInt anExtent) const
       
   115 	{
       
   116 	__ASSERT_DEBUG(IsVirtual(),User::Invariant());
       
   117 	RFrame16Buf buf(Base());
       
   118 	buf.PushL();
       
   119 	const TBool delta = IsDelta();
       
   120 	aPrimary &= KMaskStreamIdValue;
       
   121 	if (delta)
       
   122 		aPrimary |= KTocDelta;
       
   123 	STocHead h;
       
   124 	h.primary=TInt32(aPrimary);
       
   125 	h.avail=TInt32(iAvail);
       
   126 	h.count=TUint32(iCount);
       
   127 //
       
   128 	TInt off;
       
   129 	if (delta)
       
   130 		off=DeltaL(buf,anExtent,h);
       
   131 	else
       
   132 		off=RewriteL(buf,anExtent,h);
       
   133 //
       
   134 	buf.SynchL();
       
   135 	CleanupStack::PopAndDestroy(&buf);
       
   136 	return off-KOffsetTocHeader;
       
   137 	}
       
   138 
       
   139 void CPermanentStoreToc::Adopt(TInt aToc,TInt aPrimary)
       
   140 //
       
   141 // Final stage of Commit - all file changes have been successful
       
   142 // Record the new Toc location and reset the changed flag
       
   143 //
       
   144 	{
       
   145 	__ASSERT_DEBUG(aToc+KOffsetTocHeader>=iExt,User::Invariant());
       
   146 
       
   147 	if (IsDelta())
       
   148 		{
       
   149 		// Adjust the TOC-delta location
       
   150 		TInt c = iEntries.Count();
       
   151 		iOff=aToc+KOffsetTocHeader;
       
   152 		iExt=aToc + KSizeTocDeltaExtra + KSizeTocDeltaEntry*c;
       
   153 		if (c > KTocDeltaMagic)
       
   154 			iMagic += c - KTocDeltaMagic;
       
   155 		}
       
   156 	else
       
   157 		{
       
   158 		// Adjust all the TOC data and reset the delta-set
       
   159 		TInt window = iTocOff>=0 ? iWindow-iTocOff : -KOffsetTocHeader;
       
   160 		iTocOff=iOff=aToc+KOffsetTocHeader;
       
   161 		iTocExt=iExt=aToc+KSizeTocEntry*iCount;
       
   162 		iWindow = iTocOff + window;
       
   163 		iEntries.Reset();
       
   164 		iMagic = 0;
       
   165 		}
       
   166 	iPrimary=aPrimary;
       
   167 	__ASSERT_DEBUG(!IsVirtual(),User::Invariant());
       
   168 	}
       
   169 
       
   170 TInt CPermanentStoreToc::AllocL(TInt anOffset)
       
   171 	{
       
   172 	TEntry& entry=DoAllocL();
       
   173 	entry.ref=anOffset;
       
   174 	return entry.handle;
       
   175 	}
       
   176 
       
   177 TInt CPermanentStoreToc::AllocL()
       
   178 	{
       
   179 	TEntry& entry=DoAllocL();
       
   180 	entry.ref=KFrameNonexistent16;
       
   181 	return entry.handle|=KHandleInvalid;
       
   182 	}
       
   183 
       
   184 void CPermanentStoreToc::Cancel(TInt aHandle)
       
   185 	{
       
   186 	__ASSERT_DEBUG(aHandle<0&&IsVirtual(),User::Invariant());
       
   187 	TEntry* entry=Entry(aHandle);
       
   188 	__ASSERT_DEBUG((entry!=NULL) && (entry->handle==aHandle),User::Invariant());
       
   189 	entry->ref=iAvail;
       
   190 	iAvail=aHandle;
       
   191 	}
       
   192 
       
   193 void CPermanentStoreToc::FreeL(TInt aHandle)
       
   194 	{
       
   195 	__ASSERT_DEBUG(aHandle>0,User::Invariant());
       
   196 	TEntry& entry=FetchL(aHandle);
       
   197 	aHandle|=KHandleInvalid;
       
   198 	entry.handle=aHandle;
       
   199 	entry.ref=iAvail;
       
   200 	iAvail=aHandle;
       
   201 	Changed();
       
   202 	}
       
   203 
       
   204 TInt CPermanentStoreToc::AtL(TInt aHandle) const
       
   205 	{
       
   206 	__ASSERT_DEBUG(aHandle>0,User::Invariant());
       
   207 
       
   208 	// check the delta table
       
   209 	const TEntry* entry=Entry(aHandle);
       
   210 	if (entry!=NULL )
       
   211 		{
       
   212 		// if there is an entry in the delta table, but its
       
   213 		// not an exact match leave with KErrNotFound
       
   214 		// This happens when the delta indicates it's been deleted
       
   215 		if (entry->handle!=aHandle)
       
   216 			User::Leave(KErrNotFound);
       
   217 		
       
   218 		return entry->ref;
       
   219 		}
       
   220 //
       
   221 	// if it's not in the delta table check the base TOC
       
   222 	return DoAtL(aHandle);
       
   223 	}
       
   224 
       
   225 void CPermanentStoreToc::PutL(TInt aHandle, TInt anOffset, TPut aCheck)
       
   226 //
       
   227 // Used by compaction to update a single stream reference IN-PLACE in the TOC
       
   228 // We need to check in which TOC to make the update
       
   229 //
       
   230 	{
       
   231 	__ASSERT_DEBUG(!IsVirtual(),User::Invariant());
       
   232 	__ASSERT_DEBUG(aHandle>0,User::Invariant());
       
   233 	__ASSERT_DEBUG(aHandle!=KHandleTocBase || HasDelta(),User::Invariant());
       
   234 
       
   235 	if (aHandle == KHandleTocBase)
       
   236 		{
       
   237 		// update the TOC-base link
       
   238 		PutTocL(anOffset - KOffsetTocHeader, aCheck);
       
   239 		if (iTocOff != anOffset)
       
   240 			{
       
   241 			TInt size = iTocExt - iTocOff;
       
   242 			TInt window = iWindow - iTocOff;
       
   243 			iTocOff = anOffset;
       
   244 			iTocExt = anOffset + size;
       
   245 			iWindow = anOffset + window;
       
   246 			}
       
   247 		return;
       
   248 		}
       
   249 
       
   250 	TEntry e;
       
   251 	e.handle=aHandle;
       
   252 	TInt i;
       
   253 	if (iEntries.FindInOrder(e,i,&TEntry::Compare)==0)
       
   254 		{
       
   255 		// update TOC-delta entry
       
   256 		TEntry& entry=iEntries[i];
       
   257 		if (entry.handle==aHandle && entry.ref != anOffset)
       
   258 			{
       
   259 			PutDeltaL(i,aHandle,anOffset);
       
   260 			entry.ref=anOffset;
       
   261 			}
       
   262 		return;
       
   263 		}
       
   264 
       
   265 	// update TOC-base entry
       
   266 	if (aCheck==EWrite || DoAtL(aHandle)!=anOffset)
       
   267 		PutBaseL(aHandle,anOffset);
       
   268 	}
       
   269 
       
   270 TInt CPermanentStoreToc::GetL(TInt aHandle)
       
   271 	{
       
   272 	__ASSERT_DEBUG(aHandle>0,User::Invariant());
       
   273 	TEntry& entry=FetchL(aHandle);
       
   274 	return entry.ref;
       
   275 	}
       
   276 
       
   277 TInt CPermanentStoreToc::Set(TInt aHandle,TInt anOffset)
       
   278 	{
       
   279 	__ASSERT_DEBUG(aHandle!=0,User::Invariant());
       
   280 	TEntry* entry=Entry(aHandle);
       
   281 	__ASSERT_DEBUG((entry!=NULL) && (entry->handle==aHandle),User::Invariant());
       
   282 	aHandle&=KMaskStreamIdValue;
       
   283 	entry->handle=aHandle;
       
   284 	entry->ref=anOffset;
       
   285 	Changed();
       
   286 	return aHandle;
       
   287 	}
       
   288 
       
   289 CPermanentStoreToc::CPermanentStoreToc(TStreamPos aBase,TStreamExchange& aHost)
       
   290 	: /*iPrimary(0),iAvail(0),iCount(0),*/iEntries(KTocGranularity),
       
   291 		iBase(aBase),iHost(&aHost),iOff(KFrameNonexistent16)/*,iExt(0)*/,
       
   292 		iTocOff(KFrameNonexistent16)/*,iTocExt(0),iWindow(0)*/
       
   293 	{}
       
   294 
       
   295 CPermanentStoreToc::~CPermanentStoreToc()
       
   296 	{
       
   297 	iEntries.Close();
       
   298 	}
       
   299 
       
   300 void CPermanentStoreToc::ConstructL(TInt aToc,TInt aBaseReloc)
       
   301 //
       
   302 // Read and validate the TOC header at aToc.
       
   303 // aBaseReloc may contain a relocated TOC-base offset, which should override the one in a TOC-delta
       
   304 //
       
   305 	{
       
   306 	if (aToc==0)
       
   307 		return;
       
   308 	__ASSERT_DEBUG(aToc>0&&iEntries.Count()==0,User::Invariant());
       
   309 	RFrame16Buf buf(Base());
       
   310 	aToc+=KOffsetTocHeader;
       
   311 	buf.OpenL(Host(),aToc,EFrameDescriptive16|buf.ERead);
       
   312 	buf.PushL();
       
   313 	RReadStream stream(&buf);
       
   314 	STocHead h;
       
   315 	stream.ReadL((TUint8*)&h,sizeof(STocHead)); // platform dependency
       
   316 	if ((h.primary&~(KMaskStreamIdValue|static_cast<TUint>(KTocDelta)))!=0||
       
   317 		h.avail>0||(h.avail&KMaskHandleClear)!=0||(h.count&~KMaskHandleIndex)!=0)
       
   318 		__LEAVE(KErrCorrupt);
       
   319 //
       
   320 	iPrimary=TInt(h.primary) & ~KTocDelta;
       
   321 	iAvail=TInt(h.avail);
       
   322 	iCount=TInt(h.count);
       
   323 	iOff = aToc;
       
   324 //
       
   325 	if (h.primary & KTocDelta)
       
   326 		{
       
   327 		// This is a TOC-delta
       
   328 		aToc = InternalizeL(stream, aBaseReloc) + KOffsetTocHeader;
       
   329 
       
   330 		// Now locate and validate the base TOC
       
   331 		buf.Release();
       
   332 		buf.OpenL(Host(),aToc,EFrameDescriptive16|buf.ERead);
       
   333 		stream.ReadL((TUint8*)&h,sizeof(STocHead)); // platform dependency
       
   334 		if ((h.primary&~KMaskStreamIdValue)!=0||(h.count&~KMaskHandleIndex)!=0||
       
   335 			h.avail>0||(h.avail&KMaskHandleClear)!=0||TInt(h.count)>iCount)
       
   336 			__LEAVE(KErrCorrupt);
       
   337 		}
       
   338 	TInt size = KSizeTocEntry*TInt(h.count);
       
   339 // Eagerly load the first few TOC entries into the cache
       
   340 // This is good as it almost certainly lies in the file buffer already
       
   341 	if (size>0)
       
   342 		stream.ReadL(&iBuf[0],Min(size,TInt(KSizeTocBuf)));
       
   343 	size-=KOffsetTocHeader;
       
   344 	if (buf.SizeL()!=size)
       
   345 		__LEAVE(KErrCorrupt);
       
   346 	iTocOff=aToc;
       
   347 	iWindow=aToc-KOffsetTocHeader;
       
   348 	iTocExt=aToc+size;
       
   349 	if (iExt == 0)
       
   350 		iExt = iTocExt;		// set extent for non-delta TOC
       
   351 //
       
   352 	CleanupStack::PopAndDestroy(&buf);
       
   353 	}
       
   354 
       
   355 TInt CPermanentStoreToc::InternalizeL(RReadStream& aIn, TInt aBaseReloc)
       
   356 //
       
   357 // Load and validate the delta-toc table
       
   358 //
       
   359 	{
       
   360 	TInt tocoff = aIn.ReadInt32L();
       
   361 	if (aBaseReloc != KFrameNonexistent16)
       
   362 		tocoff = aBaseReloc - KOffsetTocHeader;
       
   363 	if (tocoff<0||tocoff>=iOff)
       
   364 		__LEAVE(KErrCorrupt);
       
   365 	iMagic = aIn.ReadUint16L();
       
   366 	if (!IsDelta())
       
   367 		__LEAVE(KErrCorrupt);
       
   368 	TInt n = aIn.ReadUint8L();
       
   369 	TInt size = -KOffsetTocHeader + KSizeTocDeltaExtra + KSizeTocDeltaEntry * n;
       
   370 	if (aIn.Source()->SizeL()!=size)
       
   371 		__LEAVE(KErrCorrupt);
       
   372 	iExt = iOff + size;
       
   373 	TInt last = 0;
       
   374 	while (--n >= 0)
       
   375 		{
       
   376 		STocEntry e;
       
   377 		aIn.ReadL((TUint8*)&e,KSizeTocDeltaEntry);	// platform dependency
       
   378 		if ((e.handle&KMaskHandleClear)!=0||e.handle>=0&&(e.ref<KFrameNonexistent16)||
       
   379 			e.handle<0&&(e.ref>0||(e.ref&KMaskHandleClear)!=0))
       
   380 			__LEAVE(KErrCorrupt);
       
   381 		TInt i = e.handle&KMaskHandleIndex;
       
   382 		if (i <= last || i > iCount)
       
   383 			__LEAVE(KErrCorrupt);
       
   384 		last = i;
       
   385 		TEntry entry;
       
   386 		entry.handle = TInt(e.handle);
       
   387 		entry.ref = TInt(e.ref);
       
   388 		User::LeaveIfError(iEntries.Append(entry));
       
   389 		}
       
   390 
       
   391 	return tocoff;
       
   392 	}
       
   393 
       
   394 TInt CPermanentStoreToc::DeltaL(RFrame16Buf& aBuf,TInt aExtent,const STocHead& aHead) const
       
   395 //
       
   396 // Write the TOC-delta
       
   397 //
       
   398 	{
       
   399 	TInt off=aBuf.ExtendL(Host(),aExtent,EFrameDescriptive16|aBuf.EWrite);
       
   400 	RWriteStream out(&aBuf);
       
   401 	out.WriteL((TUint8*)&aHead,sizeof(STocHead)); // platform dependency
       
   402 	out.WriteInt32L(iTocOff - KOffsetTocHeader);
       
   403 	TInt n = iEntries.Count();
       
   404 	TInt magic = iMagic;
       
   405 	if (n > KTocDeltaMagic)
       
   406 		magic += n - KTocDeltaMagic;
       
   407 	__ASSERT_DEBUG(magic <= KMaxTocDeltaMagic,User::Invariant());
       
   408 	__ASSERT_DEBUG(n <= (TInt)KMaxTUint8, User::Invariant());
       
   409 	out.WriteUint16L(magic);
       
   410 	out.WriteUint8L(n);
       
   411 	for (int i = 0; i < n; ++i)
       
   412 		{
       
   413 		const TEntry& entry = iEntries[i];
       
   414 		STocEntry e;
       
   415 		e.handle=TInt32(entry.handle);
       
   416 		e.ref=TInt32(entry.ref);
       
   417 		out.WriteL((TUint8*)&e,KSizeTocDeltaEntry); // platform dependency
       
   418 		}
       
   419 	return off;
       
   420 	}
       
   421 
       
   422 TInt CPermanentStoreToc::RewriteL(RFrame16Buf& aBuf,TInt aExtent,const STocHead& aHead) const
       
   423 //
       
   424 // Write the TOC-base
       
   425 //
       
   426 	{
       
   427 	const TInt KElementsRewrite=304;
       
   428 	const TInt KSizeRewriteBuf=KElementsRewrite*KSizeTocEntry;
       
   429 	TUint8 toc[KSizeRewriteBuf];
       
   430 
       
   431 	RFrame16Buf buf(Base());
       
   432 	buf.PushL();
       
   433 	TInt oldsize = 0;
       
   434 	TInt window = 0;
       
   435 	if (iTocOff>=0)
       
   436 		{
       
   437 		oldsize = iTocExt-iTocOff+KOffsetTocHeader;
       
   438 		window = iWindow + KOffsetTocHeader - iTocOff;
       
   439 		if (oldsize <= Min(KSizeTocBuf,KSizeRewriteBuf) && window == 0)
       
   440 			{
       
   441 			// the old TOC is already in the toc-base cache, no need to read it
       
   442 			Mem::Copy(&toc[0],&iBuf[0],oldsize);
       
   443 			oldsize = 0;	// this prevents the read request
       
   444 			}
       
   445 		else
       
   446 			{
       
   447 			buf.Set(Host(),iTocOff,iTocExt,EFrameDescriptive16|buf.ERead);
       
   448 			buf.SeekL(buf.ERead,TStreamPos(-KOffsetTocHeader));
       
   449 			}
       
   450 		}
       
   451 	RReadStream in(&buf);
       
   452 	// defer the initialisation of the write in roder to improve file buffering performance
       
   453 	RWriteStream out(&aBuf);
       
   454 	TInt off=-1;
       
   455 	TInt size=iCount*KSizeTocEntry;
       
   456 
       
   457 	for (TInt base=0,delta=0;base<size;base+=KSizeRewriteBuf)
       
   458 		{
       
   459 		// fill buffer with old TOC data
       
   460 		if (base < oldsize)
       
   461 			in.ReadL(&toc[0],Min(KSizeRewriteBuf,oldsize-base));
       
   462 		// apply changes to this block
       
   463 		for (TInt n=iEntries.Count();delta<n;++delta)
       
   464 			{
       
   465 			const TEntry& entry=iEntries[delta];
       
   466 			TInt pos = (entry.handle&KMaskHandleIndex)*KSizeTocEntry - KSizeTocEntry - base;
       
   467 			__ASSERT_DEBUG(pos>=0,User::Invariant());
       
   468 			if (pos>=KSizeRewriteBuf)
       
   469 				break;
       
   470 			STocEntry e;
       
   471 			e.handle=TInt32(entry.handle);
       
   472 			e.ref=TInt32(entry.ref);
       
   473 			Mem::Copy(&toc[pos],(const TUint8*)&e+KSizeHandleIndex,KSizeTocEntry);
       
   474 			pos += base - window;
       
   475 			if (TUint(pos) < TUint(KSizeTocBuf))
       
   476 				Mem::Copy(MUTABLE_CAST(TUint8*,&iBuf[pos]),(const TUint8*)&e+KSizeHandleIndex,KSizeTocEntry);
       
   477 			}
       
   478 		// write buffer to file
       
   479 		if (off == -1)
       
   480 			{
       
   481 			// initialise writing
       
   482 			off=aBuf.ExtendL(Host(),aExtent,EFrameDescriptive16|aBuf.EWrite);
       
   483 			out.WriteL((TUint8*)&aHead,sizeof(STocHead)); // platform dependency
       
   484 			}
       
   485 		out.WriteL(&toc[0],Min(KSizeRewriteBuf,size-base));
       
   486 		}
       
   487 //
       
   488 	CleanupStack::PopAndDestroy(&buf);
       
   489 	return off;
       
   490 	}
       
   491 
       
   492 CPermanentStoreToc::TEntry* CPermanentStoreToc::Entry(TInt aHandle)
       
   493 	{
       
   494 	TEntry e;
       
   495 	e.handle=aHandle;
       
   496 	TInt i;
       
   497 	if (iEntries.FindInOrder(e,i,&TEntry::Compare)!=0)
       
   498 		return NULL;
       
   499 //
       
   500 	TEntry& entry=iEntries[i];
       
   501 	
       
   502 	// allow entry to return a pointer even if not an exact match
       
   503 	return &entry;
       
   504 	}
       
   505 
       
   506 CPermanentStoreToc::TEntry& CPermanentStoreToc::FetchL(TInt aHandle)
       
   507 	{
       
   508 	TEntry e;
       
   509 	e.handle=aHandle;
       
   510 	TInt i;
       
   511 	if (iEntries.FindInOrder(e,i,&TEntry::Compare)!=0)
       
   512 		{
       
   513 		e.ref=DoAtL(aHandle);
       
   514 		User::LeaveIfError(iEntries.Insert(e,i));
       
   515 		}
       
   516 	TEntry& entry=iEntries[i];
       
   517 	if (entry.handle!=aHandle)
       
   518 		__LEAVE(KErrNotFound);
       
   519 //
       
   520 	return entry;
       
   521 	}
       
   522 
       
   523 CPermanentStoreToc::TEntry& CPermanentStoreToc::DoAllocL()
       
   524 	{
       
   525 	TInt handle=iAvail;
       
   526 	TEntry* entry;
       
   527 	if (handle==0)
       
   528 		{
       
   529 		__ASSERT_DEBUG(iEntries.Count()==0||(iEntries[iEntries.Count()-1].handle&KMaskHandleIndex)<=iCount,User::Invariant());
       
   530 		User::LeaveIfError(iEntries.Append(TEntry()));
       
   531 		entry=&iEntries[iEntries.Count()-1];
       
   532 		handle=++iCount;
       
   533 		}
       
   534 	else
       
   535 		{
       
   536 		entry=&FetchL(handle);
       
   537 		handle=(handle+KIncHandleGen)&KMaskStreamIdValue;
       
   538 //
       
   539 		TInt avail=entry->ref;
       
   540 		if (avail>0||(avail&KMaskHandleClear)!=0)
       
   541 			__LEAVE(KErrCorrupt);
       
   542 //
       
   543 		iAvail=avail;
       
   544 		}
       
   545 	entry->handle=handle;
       
   546 	Changed();
       
   547 	return *entry;
       
   548 	}
       
   549 
       
   550 TInt CPermanentStoreToc::DoAtL(TInt aHandle) const
       
   551 	{
       
   552 	TInt off=iTocOff;
       
   553 	if (off<0)
       
   554 		__LEAVE(KErrNotFound);
       
   555 //
       
   556 	off+=-KOffsetTocHeader-KSizeTocEntry+KSizeTocEntry*(aHandle&KMaskHandleIndex);
       
   557 	__ASSERT_DEBUG(off>=iTocOff-KOffsetTocHeader,User::Invariant());
       
   558 	if (off>=iTocExt)
       
   559 		__LEAVE(KErrNotFound);
       
   560 //
       
   561 	TInt window=iWindow;
       
   562 	if (off-window<0||off-window>=KSizeTocBuf)
       
   563 		{
       
   564 		TInt len=iTocOff-KOffsetTocHeader;
       
   565 		window=Max(len,Min(off-KBackTocBuf,iTocExt-KSizeTocBuf));
       
   566 		len=Min(iTocExt-len,TInt(KSizeTocBuf));
       
   567 //
       
   568 		RFrame16Buf buf(Base());
       
   569 		buf.Set(Host(),iTocOff,iTocExt,EFrameDescriptive16|buf.ERead);
       
   570 		buf.PushL();
       
   571 		buf.SeekL(buf.ERead,TStreamPos(window-iTocOff));
       
   572 		RReadStream stream(&buf);
       
   573 		MUTABLE_CAST(TInt&,iWindow)=iTocExt;
       
   574 		stream.ReadL(MUTABLE_CAST(TUint8*,&iBuf[0]),1); // assume half decent read-ahead buffering
       
   575 		stream.ReadL(MUTABLE_CAST(TUint8*,&iBuf[1]),len-1);
       
   576 		MUTABLE_CAST(TInt&,iWindow)=window;
       
   577 		CleanupStack::PopAndDestroy();
       
   578 		}
       
   579 	STocEntry e;
       
   580 	e.handle=aHandle;
       
   581 	Mem::Copy((TUint8*)&e+KSizeHandleIndex,&iBuf[off-window],KSizeTocEntry); // platform dependency
       
   582 	if ((e.handle&KMaskHandleClear)!=0||e.handle>=0&&(e.ref<KFrameNonexistent16)||
       
   583 		e.handle<0&&(e.ref>0||(e.ref&KMaskHandleClear)!=0))
       
   584 		__LEAVE(KErrCorrupt);
       
   585 //
       
   586 	if (TInt(e.handle)!=aHandle)
       
   587 		__LEAVE(KErrNotFound);
       
   588 //
       
   589 	return TInt(e.ref);
       
   590 	}
       
   591 
       
   592 void CPermanentStoreToc::PutBaseL(TInt aHandle,TInt aReference)
       
   593 //
       
   594 // Update a TOC-base entry
       
   595 //
       
   596 	{
       
   597 	__ASSERT_DEBUG(iTocOff>=0,User::Invariant());
       
   598 
       
   599 	TInt pos=-KOffsetTocHeader-KSizeTocEntry+KSizeTocEntry*(aHandle&KMaskHandleIndex);
       
   600 	RFrame16Buf buf(Base());
       
   601 	buf.Set(Host(),iTocOff,iTocExt,EFrameDescriptive16|buf.EWrite);
       
   602 	buf.PushL();
       
   603 	buf.SeekL(buf.EWrite,TStreamPos(pos));
       
   604 	RWriteStream stream(&buf);
       
   605 	STocEntry e;
       
   606 	e.handle=aHandle;
       
   607 	e.ref=aReference;
       
   608 	stream.WriteL((TUint8*)&e+KSizeHandleIndex,KSizeTocEntry); // platform dependency
       
   609 	CleanupStack::PopAndDestroy();
       
   610 	TInt off=pos+iTocOff-iWindow;
       
   611 	if (off>=0&&off<KSizeTocBuf)
       
   612 		Mem::Copy(&iBuf[off],(const TUint8*)&e+KSizeHandleIndex,KSizeTocEntry); // platform dependency
       
   613 	}
       
   614 
       
   615 void CPermanentStoreToc::PutDeltaL(TInt aPos, TInt aHandle, TInt aReference)
       
   616 //
       
   617 // Update a single stream reference IN-PLACE in the TOC-delta
       
   618 //
       
   619 	{
       
   620 	__ASSERT_DEBUG(HasDelta(),User::Invariant());
       
   621 	__ASSERT_DEBUG(iOff>=0,User::Invariant());
       
   622 	RFrame16Buf buf(Base());
       
   623 	buf.Set(Host(),iOff,iExt,EFrameDescriptive16|buf.EWrite);
       
   624 	buf.PushL();
       
   625 	buf.SeekL(buf.EWrite,TStreamPos(-KOffsetTocHeader + KSizeTocDeltaExtra + KSizeTocDeltaEntry*aPos));
       
   626 	RWriteStream stream(&buf);
       
   627 	STocEntry e;
       
   628 	e.handle=aHandle;
       
   629 	e.ref=aReference;
       
   630 	stream.WriteL((TUint8*)&e,KSizeTocDeltaEntry); // platform dependency
       
   631 	CleanupStack::PopAndDestroy();
       
   632 	}
       
   633 
       
   634 void CPermanentStoreToc::PutTocL(TInt aTocBase, TPut aCheck)
       
   635 //
       
   636 // Update the base TOC link in the TOC-delta
       
   637 //
       
   638 	{
       
   639 	__ASSERT_DEBUG(HasDelta(),User::Invariant());
       
   640 	__ASSERT_DEBUG(iOff>=0,User::Invariant());
       
   641 	RFrame16Buf buf(Base());
       
   642 	buf.Set(Host(),iOff,iExt,EFrameDescriptive16|buf.EWrite|buf.ERead);
       
   643 	buf.PushL();
       
   644 	buf.SeekL(buf.EWrite|buf.ERead,TStreamPos(-KOffsetTocHeader));
       
   645 	RReadStream in(&buf);
       
   646 	if (aCheck==EWrite || in.ReadInt32L() != aTocBase)
       
   647 		{
       
   648 		RWriteStream out(&buf);
       
   649 		out.WriteInt32L(aTocBase);
       
   650 		}
       
   651 	CleanupStack::PopAndDestroy();
       
   652 	}
       
   653 
       
   654 // Used prior to PutL to determine exactly where in the file the TOC update will be written.
       
   655 // This may be used to eliminate the pre-put write of the relocation information in the file
       
   656 // header in situations where the write is entirely within an atomic file block.
       
   657 //
       
   658 // The detailed numbers used to offset into the TOCs are dependant on the TOC formats, as
       
   659 // implicated by other members of this class
       
   660 TInt CPermanentStoreToc::RefSpan(TInt aHandle,TInt& aLength)
       
   661     {
       
   662     __ASSERT_DEBUG(!IsVirtual(),User::Invariant());
       
   663     __ASSERT_DEBUG(aHandle>0,User::Invariant());
       
   664 
       
   665     if (aHandle == KHandleTocBase)
       
   666         {    // locate the TOC-base link
       
   667         __ASSERT_DEBUG(HasDelta(),User::Invariant());
       
   668         __ASSERT_DEBUG(iOff>=0,User::Invariant());
       
   669         aLength = sizeof(TInt32);
       
   670         return RFrame16Buf::Position(Base(), iOff - KOffsetTocHeader).Offset();
       
   671         }
       
   672 
       
   673     TEntry e;
       
   674     e.handle=aHandle;
       
   675     TInt ix;
       
   676     if (iEntries.FindInOrder(e, ix, &TEntry::Compare) == 0)
       
   677         {    // locate TOC-delta entry
       
   678         TEntry& entry=iEntries[ix];
       
   679         if (entry.handle==aHandle)
       
   680             {
       
   681             __ASSERT_DEBUG(HasDelta(),User::Invariant());
       
   682             __ASSERT_DEBUG(iOff>=0,User::Invariant());
       
   683             aLength = KSizeTocDeltaEntry;
       
   684             return RFrame16Buf::Position(Base(),iOff - KOffsetTocHeader + KSizeTocDeltaExtra + KSizeTocDeltaEntry*ix).Offset();
       
   685             }
       
   686         }
       
   687 
       
   688     // locate the TOC-base entry
       
   689     __ASSERT_DEBUG(iTocOff>=0,User::Invariant());
       
   690     aLength = KSizeTocEntry;
       
   691     return RFrame16Buf::Position(Base(),iTocOff-KOffsetTocHeader-KSizeTocEntry+KSizeTocEntry*(aHandle&KMaskHandleIndex)).Offset();
       
   692     }
       
   693 
       
   694 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
   695 /////////////////////              RPermanentStoreTocIter               ////////////////////////////////////////////////////
       
   696 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
   697 
       
   698 RPermanentStoreTocIter::RPermanentStoreTocIter(const CPermanentStoreToc& aTable)
       
   699 	: iTable(aTable), iBuf(aTable.Base()), iDelta(0), iDeltaEnd(0)
       
   700 	{
       
   701 	TInt off=aTable.iTocOff;
       
   702 	__ASSERT_DEBUG(off>=KFrameNonexistent16,User::Invariant());
       
   703 	TInt ext=off<0?off:aTable.iTocExt;
       
   704 	iBuf.Set(aTable.Host(),off,ext,EFrameDescriptive16|iBuf.ERead);
       
   705 	}
       
   706 
       
   707 void RPermanentStoreTocIter::Release()
       
   708 	{
       
   709 	iBuf.Release();
       
   710 	}
       
   711 
       
   712 void RPermanentStoreTocIter::ResetL()
       
   713 	{
       
   714 	iNext = iIndex = 1;
       
   715 	if (iBuf.Offset()<0)
       
   716 		{
       
   717 		iCount=0;
       
   718 		return;
       
   719 		}
       
   720 //
       
   721 	RReadStream stream(&iBuf);
       
   722 	STocHead h;
       
   723 	stream.ReadL((TUint8*)&h,sizeof(STocHead)); // platform dependency
       
   724 	if (h.primary<0||(h.primary&~KMaskStreamIdValue)!=0||
       
   725 		h.avail>0||(h.avail&KMaskHandleClear)!=0||(h.count&~KMaskHandleIndex)!=0)
       
   726 		__LEAVE(KErrCorrupt);
       
   727 //
       
   728 	const CPermanentStoreToc& table=iTable;
       
   729 	if (table.HasDelta())
       
   730 		{
       
   731 		TInt c = table.iEntries.Count();
       
   732 		if (c)
       
   733 			{
       
   734 			iDelta = &table.iEntries[0];
       
   735 			iDeltaEnd = iDelta + c;
       
   736 			}
       
   737 		iIndex = 0;
       
   738 		}
       
   739 	iCount = iTable.iCount;
       
   740 	}
       
   741 
       
   742 TBool RPermanentStoreTocIter::NextL(TEntry& anEntry)
       
   743 	{
       
   744 	TInt i=iIndex;
       
   745 	__ASSERT_DEBUG(iCount>=0,User::Invariant());
       
   746 	if (i == 0)
       
   747 		{
       
   748 		// report TOC-base as a 'stream'
       
   749 		anEntry.handle = KHandleTocBase;
       
   750 		anEntry.ref = iTable.iTocOff;
       
   751 		iIndex = 1;
       
   752 		return ETrue;
       
   753 		}
       
   754 
       
   755 	__ASSERT_DEBUG(i>0,User::Invariant());
       
   756 	if (i>iCount)
       
   757 		return EFalse;
       
   758 //
       
   759 	const TEntry* d = iDelta;
       
   760 	if (d != iDeltaEnd && (d->handle&KMaskHandleIndex) == i)
       
   761 		{
       
   762 		anEntry = *d;
       
   763 		iDelta = d+1;
       
   764 		iIndex = i+1;
       
   765 		return ETrue;
       
   766 		}
       
   767 //
       
   768 	RReadStream stream(&iBuf);
       
   769 	TInt skip = i - iNext;
       
   770 	if (skip > 0)
       
   771 		stream.ReadL(KSizeTocEntry * skip);
       
   772 	STocEntry e;
       
   773 	e.handle=i;
       
   774 	stream.ReadL((TUint8*)&e+KSizeHandleIndex,KSizeTocEntry); // platform dependency
       
   775 	if ((e.handle&KMaskHandleClear)!=0||e.handle>=0&&e.ref<KFrameNonexistent16||
       
   776 		e.handle<0&&(e.ref>0||(e.ref&KMaskHandleClear)!=0))
       
   777 		__LEAVE(KErrCorrupt);
       
   778 //
       
   779 	iNext = iIndex = i+1;
       
   780 	anEntry.handle=TInt(e.handle);
       
   781 	anEntry.ref=TInt(e.ref);
       
   782 	return ETrue;
       
   783 	}
       
   784 
       
   785 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
   786 /////////////////////              TPermanentStoreCache               //////////////////////////////////////////////////////
       
   787 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
   788 
       
   789 const TPermanentStoreCache::TItem* TPermanentStoreCache::At(TInt aHandle) const
       
   790 	{
       
   791 	const TItem* item=&iItems[0];
       
   792 	TInt i=1;
       
   793 	TInt bit=1;
       
   794 	while (item->handle!=aHandle)
       
   795 		{
       
   796 		__ASSERT_DEBUG(item==&iItems[i-1],User::Invariant());
       
   797 		TInt step=(aHandle&bit)?i+1:i;
       
   798 		bit<<=1;
       
   799 		i+=step;
       
   800 		if (i>EItems)
       
   801 			return NULL;
       
   802 //
       
   803 		item+=step;
       
   804 		}
       
   805 	__ASSERT_DEBUG(item==&iItems[i-1],User::Invariant());
       
   806 	return item;
       
   807 	}
       
   808 
       
   809 void TPermanentStoreCache::Relocated(TInt aHandle,TInt anOffset)
       
   810 	{
       
   811 	const TItem* item=At(aHandle);
       
   812 	if (item)
       
   813 		{
       
   814 		// update the cache item with the new offset
       
   815 		// As 'extent' may only be a partial extent of a fragmented frame
       
   816 		// which is no longer fragmented, we cannot simply shift this by the same
       
   817 		// amount as 'offset'. Simplest to reset this to 'unknown', i.e. 0
       
   818 		const_cast<TItem*>(item)->offset = anOffset;
       
   819 		const_cast<TItem*>(item)->extent = 0;
       
   820 		}
       
   821 	}
       
   822 
       
   823 void TPermanentStoreCache::Put(const TItem* anItem,TInt anOffset,TInt anExtent)
       
   824 	{
       
   825 	TInt handle=anItem->handle;
       
   826 	TItem* item=&iItems[0];
       
   827 	TInt i=1;
       
   828 	TInt bit=1;
       
   829 	while (item != anItem)
       
   830 		{
       
   831 		__ASSERT_DEBUG(item==&iItems[i-1],User::Invariant());
       
   832 		TInt step=(handle&bit)?i+1:i;
       
   833 		bit<<=1;
       
   834 		i+=step;
       
   835 		__ASSERT_DEBUG(i<=EItems,User::Invariant());
       
   836 		item+=step;
       
   837 		}
       
   838 	__ASSERT_DEBUG(item==&iItems[i-1],User::Invariant());
       
   839 
       
   840 	for(;;)
       
   841 		{
       
   842 		__ASSERT_DEBUG(item==&iItems[i-1],User::Invariant());
       
   843 		TInt step=(handle&bit)?i+1:i;
       
   844 		bit<<=1;
       
   845 		i+=step;
       
   846 		if (i>EItems)
       
   847 			break;
       
   848 //
       
   849 		TItem* hole=item;
       
   850 		item+=step;
       
   851 		*hole=*item;
       
   852 		};
       
   853 	item->handle=handle;
       
   854 	item->offset=anOffset;
       
   855 	item->extent=anExtent;
       
   856 	__ASSERT_DEBUG(At(handle)==item,User::Invariant());
       
   857 	}
       
   858 
       
   859 void TPermanentStoreCache::Add(TInt aHandle,TInt anOffset,TInt anExtent)
       
   860 	{
       
   861 	TItem* item=&iItems[0];
       
   862 	TInt i=1;
       
   863 	TInt bit=1;
       
   864 	for(;;)
       
   865 		{
       
   866 		__ASSERT_DEBUG(item==&iItems[i-1]&&item->handle!=aHandle,User::Invariant());
       
   867 		TInt step=(aHandle&bit)?i+1:i;
       
   868 		bit<<=1;
       
   869 		i+=step;
       
   870 		if (i>EItems)
       
   871 			break;
       
   872 //
       
   873 		TItem* hole=item;
       
   874 		item+=step;
       
   875 		*hole=*item;
       
   876 		};
       
   877 	item->handle=aHandle;
       
   878 	item->offset=anOffset;
       
   879 	item->extent=anExtent;
       
   880 	__ASSERT_DEBUG(At(aHandle)==item,User::Invariant());
       
   881 	}
       
   882 
       
   883 void TPermanentStoreCache::Remove(TInt aHandle)
       
   884 	{
       
   885 	TItem* item=&iItems[0];
       
   886 	TInt i=1;
       
   887 	TInt bit=1;
       
   888 	while (item->handle!=aHandle)
       
   889 		{
       
   890 		__ASSERT_DEBUG(item==&iItems[i-1],User::Invariant());
       
   891 		TInt step=(aHandle&bit)?i+1:i;
       
   892 		bit<<=1;
       
   893 		i+=step;
       
   894 		if (i>EItems)
       
   895 			return;
       
   896 //
       
   897 		item+=step;
       
   898 		}
       
   899 	TItem* hole=item;
       
   900 	TInt mask=bit-1;
       
   901 	while (item!=&iItems[0])
       
   902 		{
       
   903 		__ASSERT_DEBUG(item==&iItems[i-1],User::Invariant());
       
   904 		TInt step=i;
       
   905 		bit>>=1;
       
   906 		i>>=1;
       
   907 		step-=i;
       
   908 		item-=step;
       
   909 //
       
   910 		if (((aHandle^item->handle)&mask)==0)
       
   911 			{
       
   912 			*hole=*item;
       
   913 			hole=item;
       
   914 			mask=bit-1;
       
   915 			}
       
   916 		}
       
   917 	hole->handle=0;
       
   918 	__ASSERT_DEBUG(i==1&&At(aHandle)==NULL,User::Invariant());
       
   919 	}
       
   920 
       
   921 void TPermanentStoreCache::Invalidate()
       
   922 	{
       
   923 	for (TItem* item=&iItems[0],*end=item+EItems;item<end;++item)
       
   924 		item->handle=0;
       
   925 	}
       
   926 
       
   927 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
   928 /////////////////////              CPermanentStoreCoord               //////////////////////////////////////////////////////
       
   929 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
   930 
       
   931 //Returns the file system type, according to what the "file write" operation guarantees.
       
   932 //The return result could be one of:
       
   933 // - ESimple        - "single byte write" operations are atomic;
       
   934 // - EBlockAtomic   - "block/sector write" operations are atomic;
       
   935 // - ETransactional - transactional file system;
       
   936 CPermanentStoreCoord::TFileQoS CPermanentStoreCoord::FileQoSL()
       
   937 	{
       
   938 	//Uncomment, if you want FileQoSL() to return always EBlockAtomic/EBlockAtomic.
       
   939 	//iFileQos = ETransactional;	
       
   940 	//iFileQos = EBlockAtomic;	
       
   941 	//return iFileQos;
       
   942 	//
       
   943 	if (iFileQos == EUnknown) //get the file sytem type, if iFileQos is not set yet
       
   944 		{
       
   945 		TStreamExchange &se = Host();
       
   946 		RFileBuf *sb = static_cast<RFileBuf *>(se.HostL());
       
   947 		RFile &f = sb->File();
       
   948 
       
   949 		TInt dn;
       
   950 		TDriveInfo di;
       
   951 		User::LeaveIfError(f.Drive(dn, di));
       
   952 
       
   953 		iFileQos = (di.iDriveAtt & KDriveAttTransaction) ? ETransactional : ESimple;
       
   954 		
       
   955 		if(iFileQos == ESimple && IsBlockAtomicL(dn))
       
   956 			{
       
   957 			iFileQos = EBlockAtomic;	
       
   958 			}
       
   959 		}
       
   960 	return iFileQos;
       
   961 	}
       
   962 
       
   963 //The function returns true, if the file system guarantees atomic "block write" operations on aDriveNo.
       
   964 //It is not the most effective implementation at the moment (creates/closes a file session), 
       
   965 //probably TDriveInfo::iType can be used in a more effective implementation.
       
   966 TBool CPermanentStoreCoord::IsBlockAtomicL(TInt aDriveNo) const
       
   967 	{
       
   968 	__ASSERT_DEBUG(aDriveNo >= EDriveA && aDriveNo <= EDriveZ, User::Invariant());
       
   969 	RFs fs;
       
   970 	CleanupClosePushL(fs);
       
   971 	User::LeaveIfError(fs.Connect());
       
   972 	
       
   973 	TVolumeIOParamInfo volInfo;
       
   974 	TInt err = fs.VolumeIOParam(aDriveNo, volInfo);
       
   975 	CleanupStack::PopAndDestroy(&fs);
       
   976 	
       
   977 	//If VolumeIOParam() succeeds, the media block size is >= 512 bytes and the media block size is power of two - report
       
   978 	//that the media supports atomic "block write" operations.
       
   979 	return err == KErrNone && volInfo.iBlockSize >= KDefaultMediaBlockSize && (volInfo.iBlockSize & (volInfo.iBlockSize - 1)) == 0;
       
   980 	}
       
   981 
       
   982 TStreamPos CPermanentStoreCoord::LimitL()
       
   983 	{
       
   984 	TableL();
       
   985 	return RFrame16Buf::Position(Base(),iExt);
       
   986 	}
       
   987 
       
   988 TStreamId CPermanentStoreCoord::PrimaryL()
       
   989 	{
       
   990 	return TStreamId(TableL().Primary());
       
   991 	}
       
   992 
       
   993 void CPermanentStoreCoord::ChangedL()
       
   994 	{
       
   995 	ConsolidateL().Changed();
       
   996 	}
       
   997 
       
   998 TBool CPermanentStoreCoord::CommitL(TStreamId aPrimary)
       
   999 	{
       
  1000 	__ASSERT_DEBUG(IsTrim(),User::Invariant());
       
  1001 	if (iExtend!=0)
       
  1002 		__LEAVE(KErrInUse);
       
  1003 //
       
  1004 	CPermanentStoreToc& table=ConsolidateL();
       
  1005 	if (!table.IsVirtual())
       
  1006 		return EFalse;
       
  1007 //
       
  1008 	iState|=EClip;
       
  1009 	TInt toc=table.RealizeL(aPrimary.Value(),iExt);
       
  1010 //
       
  1011 	TPermanentStoreHeader header(toc);
       
  1012 	header.SetBackupToc(iToc);
       
  1013 	MStreamBuf* buf=BeginL(header);
       
  1014 	buf->SynchL();
       
  1015 		// it's done, wrap things up
       
  1016 	Host().Share(buf);
       
  1017 	iToc=toc;
       
  1018 	table.Adopt(toc,aPrimary.Value());
       
  1019 	++iGen;
       
  1020 	iState=EBackup;
       
  1021 	iExt=table.Extent();
       
  1022 	return ETrue;
       
  1023 	}
       
  1024 
       
  1025 TBool CPermanentStoreCoord::RevertL(TStreamId& aPrimary)
       
  1026 	{
       
  1027 	__ASSERT_ALWAYS(iAccess==0,Panic(EStoreInUse));
       
  1028 		// can't revert things under people's feet
       
  1029 	CPermanentStoreToc* table=iTable;
       
  1030 	iTable=NULL;
       
  1031 	iCache.Invalidate();
       
  1032 	if (table==NULL||!table->IsVirtual())
       
  1033 		{
       
  1034 		__ASSERT_DEBUG(table==NULL||aPrimary==TStreamId(table->Primary()),User::Invariant());
       
  1035 		delete table;
       
  1036 		return EFalse;
       
  1037 		}
       
  1038 //
       
  1039 	aPrimary=TStreamId(table->Primary());
       
  1040 	delete table;
       
  1041 	iState|=EClip;
       
  1042 //
       
  1043 	TStreamExchange& host=Host();
       
  1044 	MStreamBuf* buf=host.HostL();
       
  1045 	host.Release();
       
  1046 	buf->SynchL();
       
  1047 	host.Share(buf);
       
  1048 	return ETrue;
       
  1049 	}
       
  1050 
       
  1051 TStreamId CPermanentStoreCoord::ExtendL()
       
  1052 	{
       
  1053 	return TStreamId(ConsolidateL().AllocL(KFrameNonexistent16));
       
  1054 	}
       
  1055 
       
  1056 void CPermanentStoreCoord::DeleteL(TStreamId anId)
       
  1057 	{
       
  1058 	TInt handle=anId.Value();
       
  1059 	ConsolidateL().FreeL(handle);
       
  1060 	iCache.Remove(handle);
       
  1061 	}
       
  1062 
       
  1063 CPermanentStoreCoord::CPermanentStoreCoord(TStreamPos aBase,TStreamExchange& aHost)
       
  1064 	: iBase(aBase),iHost(&aHost), iFileQos(EUnknown)
       
  1065 	{}
       
  1066 
       
  1067 //
       
  1068 // Read and analyse the store header.
       
  1069 // The whole header (14 bytes) is read from the file and:
       
  1070 // - If the dirty bit is set, the backup TOC will be used;
       
  1071 // - If the dirty bit is not set, and the backup TOC ref is not the same as the TOC ref,
       
  1072 //   then it means the the backup TOC ref has not been written successfully, so the TOC ref will be used;
       
  1073 void CPermanentStoreCoord::InternalizeL(RReadStream& aStream)
       
  1074 	{
       
  1075 	if (iTable!=NULL)
       
  1076 		__LEAVE(KErrNotReady);
       
  1077 //
       
  1078 	iState=EClip;
       
  1079 	TPermanentStoreHeader header;
       
  1080 	aStream.ReadL(header.Ptr(),KPermanentStoreHeaderLength);
       
  1081 		// determine where the toc lives
       
  1082 	TInt toc=header.BackupToc();
       
  1083 	if (header.IsDirty())
       
  1084 		{
       
  1085 		iReloc=0;
       
  1086 		iTarget=0;
       
  1087 		}
       
  1088 	else
       
  1089 		{
       
  1090 		TInt handle=header.Handle();
       
  1091 		TInt ref=header.Reference();
       
  1092 		if (handle==0&&toc!=ref)
       
  1093 			{ // toc pointer not backed up, validate as if it was
       
  1094 			toc=ref;
       
  1095 			iState|=EBackup;
       
  1096 			header.SetBackupToc(toc);
       
  1097 			}
       
  1098 		if (!header.IsValid()) // not a permanent store or damaged beyond recognition
       
  1099 			__LEAVE(KErrNotSupported);
       
  1100 	//
       
  1101 		if (toc<0||((handle&~KMaskStreamIdValue)!=0&&handle!=KHandleTocBase)||ref<0||(handle!=0&&ref>=toc+KOffsetTocHeader))
       
  1102 			__LEAVE(KErrCorrupt); // integrity compromised
       
  1103 	//
       
  1104 		iReloc=handle;
       
  1105 		iTarget=ref;
       
  1106 		}
       
  1107 	//
       
  1108 	if (iToc!=0 && iToc!=toc)		// refresh produced a different toc
       
  1109 		__LEAVE(KErrCorrupt);
       
  1110 	iToc=toc;
       
  1111 	}
       
  1112 
       
  1113 CPermanentStoreCoord::~CPermanentStoreCoord()
       
  1114 	{
       
  1115 	__ASSERT_ALWAYS(iRefs==0,Panic(EStoreInUse));
       
  1116 	delete iTable;
       
  1117 	}
       
  1118 
       
  1119 void CPermanentStoreCoord::CanExtendL()
       
  1120 	{
       
  1121 	__ASSERT_DEBUG(IsTrim(),User::Invariant());
       
  1122 	if (iExtend!=0)
       
  1123 		__LEAVE(KErrInUse);
       
  1124 //
       
  1125 	ConsolidateL();
       
  1126 	}
       
  1127 
       
  1128 TInt CPermanentStoreCoord::DoCreateL()
       
  1129 	{
       
  1130 	__ASSERT_DEBUG(IsTrim()&&iReloc==0&&iExtend==0,User::Invariant());
       
  1131 	TInt handle=Table().AllocL();
       
  1132 	iExtend=handle;
       
  1133 	Inc();
       
  1134 	++iAccess;
       
  1135 	return handle;
       
  1136 	}
       
  1137 
       
  1138 void CPermanentStoreCoord::DoReplaceL(TInt aHandle)
       
  1139 	{
       
  1140 	__ASSERT_DEBUG(IsTrim()&&iReloc==0&&iExtend==0,User::Invariant());
       
  1141 	TInt off=Table().GetL(aHandle);
       
  1142 	const TItem* item=iCache.At(aHandle);
       
  1143 	__ASSERT_DEBUG(item==NULL||iTable!=NULL&&item->handle==aHandle,User::Invariant());
       
  1144 	if (item==NULL)
       
  1145 		iCache.Add(aHandle,off,Min(off,0));
       
  1146 	iExtend=aHandle;
       
  1147 	Inc();
       
  1148 	++iAccess;
       
  1149 	}
       
  1150 
       
  1151 TInt CPermanentStoreCoord::DoOpenL(TInt& anOffset,TInt aHandle)
       
  1152 	{
       
  1153 	const TItem* item=iCache.At(aHandle);
       
  1154 	__ASSERT_DEBUG(item==NULL||iTable!=NULL&&item->handle==aHandle,User::Invariant());
       
  1155 	TInt off;
       
  1156 	TInt ext;
       
  1157 	if (item==NULL)
       
  1158 		{
       
  1159 		off=TableL().AtL(aHandle);
       
  1160 		if (iReloc==aHandle)
       
  1161 			{
       
  1162 			TInt trg=iTarget;
       
  1163 			if (trg==off)
       
  1164 				iReloc=0;
       
  1165 			else
       
  1166 				off=trg;
       
  1167 			}
       
  1168 		ext=Min(off,0); // ensures ext==off for empty streams
       
  1169 		iCache.Add(aHandle,off,ext);
       
  1170 		}
       
  1171 	else
       
  1172 		{
       
  1173 		off=item->offset;
       
  1174 		ext=item->extent;
       
  1175 		}
       
  1176 	Inc();
       
  1177 	++iAccess;
       
  1178 	anOffset=off;
       
  1179 	return ext;
       
  1180 	}
       
  1181 
       
  1182 void CPermanentStoreCoord::DoRelease(TInt aHandle,TInt anOffset,TInt anExtent)
       
  1183 	{
       
  1184 	__ASSERT_DEBUG(aHandle!=0,User::Invariant());
       
  1185 	Dec();
       
  1186 	--iAccess;
       
  1187 	if (anExtent==0)
       
  1188 		{ // failed to commit the extending stream
       
  1189 		__ASSERT_DEBUG(aHandle==iExtend&&IsTrim(),User::Invariant());
       
  1190 		iState|=EClip;
       
  1191 		iExtend=0;
       
  1192 		if (aHandle<0)
       
  1193 			Table().Cancel(aHandle);
       
  1194 		}
       
  1195 	else
       
  1196 		{
       
  1197 		const TItem* item=iCache.At(aHandle);
       
  1198 		if (item!=NULL&&item->offset==anOffset&&anExtent>item->extent)
       
  1199 			iCache.Put(item,anOffset,anExtent);
       
  1200 		}
       
  1201 	}
       
  1202 
       
  1203 TInt CPermanentStoreCoord::DoCommit(TInt aHandle,TInt anOffset,TInt anExtent)
       
  1204 	{
       
  1205 	__ASSERT_DEBUG(aHandle!=0&&aHandle==iExtend&&(anExtent>=iExt||anOffset==anExtent),User::Invariant());
       
  1206 	aHandle=Table().Set(aHandle,anOffset);
       
  1207 	if (anExtent<0)
       
  1208 		iCache.Remove(aHandle);
       
  1209 	else
       
  1210 		{
       
  1211 		iExt=anExtent;
       
  1212 		const TItem* item=iCache.At(aHandle);
       
  1213 		if (item==NULL)
       
  1214 			iCache.Add(aHandle,anOffset,anExtent);
       
  1215 		else
       
  1216 			iCache.Put(item,anOffset,anExtent);
       
  1217 		}
       
  1218 	iExtend=0;
       
  1219 	return aHandle;
       
  1220 	}
       
  1221 
       
  1222 CPermanentStoreToc& CPermanentStoreCoord::TableL()
       
  1223 	{
       
  1224 	CPermanentStoreToc* table=iTable;
       
  1225 	if (table==NULL)
       
  1226 		{
       
  1227 		table=CPermanentStoreToc::NewL(Base(),Host(),iToc,iReloc==KHandleTocBase?iTarget:KFrameNonexistent16);
       
  1228 		iExt=table->Extent();
       
  1229 		iTable=table;
       
  1230 		}
       
  1231 	return *table;
       
  1232 	}
       
  1233 
       
  1234 CPermanentStoreToc& CPermanentStoreCoord::ConsolidateL()
       
  1235 	{
       
  1236 	CPermanentStoreToc& table=TableL();
       
  1237 	if (iReloc!=0)
       
  1238 		{
       
  1239 		table.PutL(iReloc,iTarget,CPermanentStoreToc::ETestBeforeWrite);
       
  1240 		iCache.Relocated(iReloc,iTarget);
       
  1241 		iReloc=0;
       
  1242 		}
       
  1243 	return table;
       
  1244 	}
       
  1245 
       
  1246 //After stream relocation, the stream entry in the TOC has to be updated with the new stream position.
       
  1247 //If the file system is not transactional or if the file system is "block atomic", but the stream entry is split
       
  1248 //on a block/sector boundary, then the stream handle will be stored in the permanent file store header, in case
       
  1249 //if the TOC entry update fails.
       
  1250 void CPermanentStoreCoord::RelocateL(TInt aHandle,TInt anOffset)
       
  1251 	{
       
  1252 	__ASSERT_DEBUG(!Accessed(),User::Invariant());
       
  1253 	__ASSERT_DEBUG(iReloc==0,User::Invariant());
       
  1254 
       
  1255 	TBool updateStoreHeader = ETrue;	
       
  1256 	TFileQoS fileQos = FileQoSL();
       
  1257 	if(fileQos == ETransactional)
       
  1258 		{
       
  1259 		updateStoreHeader = EFalse;	
       
  1260 		}
       
  1261 	else if(fileQos == EBlockAtomic)
       
  1262 		{
       
  1263 		TInt dataLen = 0;
       
  1264 		TInt writePos = iTable->RefSpan(aHandle, dataLen);
       
  1265 		__ASSERT_DEBUG(writePos >= 0 && dataLen > 0, User::Invariant());
       
  1266 		TInt startSectorAddr = writePos & ~(KDefaultMediaBlockSize - 1);
       
  1267 		TInt endSectorAddr = (writePos + dataLen - 1) & ~(KDefaultMediaBlockSize - 1);
       
  1268 		if(startSectorAddr == endSectorAddr)
       
  1269 			{
       
  1270 			updateStoreHeader = EFalse;	
       
  1271 			}
       
  1272 		}
       
  1273 	
       
  1274 	if (updateStoreHeader)
       
  1275 		{
       
  1276 		TPermanentStoreHeader header(iToc,aHandle,anOffset);
       
  1277 		Host().Share(BeginL(header));
       
  1278 		iReloc=aHandle;
       
  1279 		iTarget=anOffset;
       
  1280 		}
       
  1281 	++iGen;
       
  1282 	iTable->PutL(aHandle,anOffset,CPermanentStoreToc::EWrite);
       
  1283 	iCache.Relocated(aHandle,anOffset);
       
  1284 	iReloc=0;
       
  1285 	}
       
  1286 
       
  1287 void CPermanentStoreCoord::MoveL(TInt aToc,TInt anExtent)
       
  1288 	{
       
  1289 	__ASSERT_DEBUG(iReloc==0,User::Invariant());
       
  1290 	CPermanentStoreToc& table=Table();
       
  1291 	TPermanentStoreHeader header(aToc);
       
  1292 	header.SetBackupToc(iToc);
       
  1293 	Host().Share(BeginL(header));
       
  1294 		// update data structures but defer the write
       
  1295 	iToc=aToc;
       
  1296 	TInt ext=table.Extent();
       
  1297 	table.Move(aToc,anExtent);
       
  1298 	iState|=EBackup;
       
  1299 	if (iExt==ext)
       
  1300 		{
       
  1301 		iExt=anExtent;
       
  1302 		iState|=EClip;
       
  1303 		}
       
  1304 	}
       
  1305 
       
  1306 //
       
  1307 // Starts a pseudo-atomic update of the permanent file store header.
       
  1308 //
       
  1309 // For the effect to be 'atomic', writes need to meet the following requirements:
       
  1310 // 1. When updating n bytes using a single write, bytes 2 through n remain unchanged unless the first byte also changes.
       
  1311 // 2. Changes associated with successive write requests happen in strict sequence.
       
  1312 // 3. Updating a single byte is atomic.
       
  1313 //
       
  1314 // Also, a failure to write to a location shall be reported no later than on the next
       
  1315 // write to that or a different location, or on buffer synchronisation.
       
  1316 //
       
  1317 // The preconditions of the operation are:
       
  1318 // - all stream insert/delete/relocate operations completed, file - updated;
       
  1319 // - the TOC reference in the file store header points to the current (valid) TOC, which does not include the most recent
       
  1320 //   changes, since the last commit;
       
  1321 // - the in-memory backup TOC reference updated and made equal to the file stored TOC reference;
       
  1322 //
       
  1323 // The procedure consists of 3 "file-write" steps:
       
  1324 // -1- write the backup TOC ref (4 bytes) to the permanent file store header.
       
  1325 //     if this operation fails, when the store is reopened, the TOC ref will be used;
       
  1326 // -2- set the dirty bit and write the whole file store header (14 bytes).
       
  1327 //     If this operation fails, but the dirty bit has been successfully set, the backup TOC ref will be used,
       
  1328 //     when the store is reopened;
       
  1329 // -3- clear the dirty bit (1 byte "file write" op). The commit operation has completed successfully;
       
  1330 MStreamBuf* CPermanentStoreCoord::BeginL(TPermanentStoreHeader& aHeader)
       
  1331 	{
       
  1332 	__ASSERT_DEBUG(!aHeader.IsDirty()&&aHeader.BackupToc()==iToc&&iReloc==0,User::Invariant());
       
  1333 	MStreamBuf& buf=*Host().HostL();
       
  1334 	buf.SeekL(buf.EWrite,Base()+KPermanentStoreHeaderOffset);
       
  1335 	TFileQoS fileQos = FileQoSL();
       
  1336 	if (fileQos<EBlockAtomic)
       
  1337 		{
       
  1338 		if (iState&EBackup)
       
  1339 			{ // we've yet to write the backup toc, do that before clobbering the header
       
  1340 			buf.WriteL(aHeader.Ptr(),KPermanentStoreBackupLength);
       
  1341 			buf.SeekL(buf.EWrite,EStreamBeginning);
       
  1342 			buf.SeekL(buf.EWrite,Base()+KPermanentStoreHeaderOffset);
       
  1343 			iState&=~EBackup;
       
  1344 			}
       
  1345 		// first write--dirty flag set in the first byte, backup toc unchanged, new header otherwise
       
  1346 		aHeader.MarkDirty();
       
  1347 		}
       
  1348 	Host().Release(); // from this point onwards any failure results in store shutdown
       
  1349 //
       
  1350 	buf.WriteL(aHeader.Ptr(),KPermanentStoreHeaderLength);
       
  1351 	if (fileQos<EBlockAtomic)
       
  1352 		{
       
  1353 		buf.SeekL(buf.EWrite,EStreamBeginning);
       
  1354 		buf.SeekL(buf.EWrite,Base()+KPermanentStoreHeaderOffset);
       
  1355 		aHeader.SetBackupToc(iToc);
       
  1356 			// second write--single byte write to clear the dirty flag, no change otherwise
       
  1357 		buf.WriteL(aHeader.Ptr(),1);
       
  1358 		}
       
  1359 		// at this point synchronisation is atomic; ie, if successful the change
       
  1360 		// has been recorded, and failure means it will never happen
       
  1361 	return &buf;
       
  1362 	}
       
  1363 
       
  1364 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
  1365 /////////////////////              HPermanentStoreBuf               ////////////////////////////////////////////////////////
       
  1366 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
  1367 
       
  1368 HPermanentStoreBuf* HPermanentStoreBuf::CreateL(CPermanentStoreCoord& aCoord,TStreamId& anId,TInt aMode)
       
  1369 	{
       
  1370 	HPermanentStoreBuf* buf=ExtendLC(aCoord,aMode);
       
  1371 	TInt handle=aCoord.DoCreateL();
       
  1372 	buf->iHandle=handle;
       
  1373 	CleanupStack::Pop();
       
  1374 	anId=TStreamId(handle&KMaskStreamIdValue);
       
  1375 	return buf;
       
  1376 	}
       
  1377 
       
  1378 HPermanentStoreBuf* HPermanentStoreBuf::ReplaceL(CPermanentStoreCoord& aCoord,TStreamId anId,TInt aMode)
       
  1379 	{
       
  1380 	HPermanentStoreBuf* buf=ExtendLC(aCoord,aMode);
       
  1381 	TInt handle=anId.Value();
       
  1382 	aCoord.DoReplaceL(handle);
       
  1383 	buf->iHandle=handle;
       
  1384 	CleanupStack::Pop();
       
  1385 	return buf;
       
  1386 	}
       
  1387 
       
  1388 HPermanentStoreBuf* HPermanentStoreBuf::OpenL(CPermanentStoreCoord& aCoord,TStreamId anId,TInt aMode)
       
  1389 	{
       
  1390 	HPermanentStoreBuf* buf=NewLC(aCoord);
       
  1391 	TInt handle=anId.Value();
       
  1392 	TInt off=KFrameNonexistent16;
       
  1393 	TInt ext=aCoord.DoOpenL(off,handle);
       
  1394 	buf->iHandle=handle;
       
  1395 	if (ext!=0)
       
  1396 		buf->RFrame16Buf::Set(aCoord.Host(),off,ext,EFrameData16|aMode);
       
  1397 	else
       
  1398 		buf->RFrame16Buf::OpenL(aCoord.Host(),off,EFrameData16|aMode);
       
  1399 	CleanupStack::Pop();
       
  1400 	return buf;
       
  1401 	}
       
  1402 
       
  1403 HPermanentStoreBuf::~HPermanentStoreBuf()
       
  1404 	{
       
  1405 	TInt handle=iHandle;
       
  1406 	if (handle!=0)
       
  1407 		Coord().DoRelease(handle,Offset(),Extent());
       
  1408 	RFrame16Buf::DoRelease();
       
  1409 	}
       
  1410 
       
  1411 HPermanentStoreBuf* HPermanentStoreBuf::NewLC(CPermanentStoreCoord& aCoord)
       
  1412 	{
       
  1413 	HPermanentStoreBuf* buf=new(ELeave) HPermanentStoreBuf(aCoord);
       
  1414 	buf->PushL();
       
  1415 	return buf;
       
  1416 	}
       
  1417 
       
  1418 HPermanentStoreBuf* HPermanentStoreBuf::ExtendLC(CPermanentStoreCoord& aCoord,TInt aMode)
       
  1419 	{
       
  1420 	aCoord.CanExtendL();
       
  1421 	HPermanentStoreBuf* buf=NewLC(aCoord);
       
  1422 	buf->RFrame16Buf::ExtendL(aCoord.Host(),aCoord.iExt,EFrameData16|aMode);
       
  1423 	__ASSERT_DEBUG(TStreamPos(aCoord.Host().SizeL())==buf->Position(buf->Offset()),User::Invariant());
       
  1424 	return buf;
       
  1425 	}
       
  1426 
       
  1427 void HPermanentStoreBuf::DoRelease()
       
  1428 	{
       
  1429 	delete this;
       
  1430 	}
       
  1431 
       
  1432 void HPermanentStoreBuf::DoSynchL()
       
  1433 	{
       
  1434 	__ASSERT_DEBUG(iHandle!=0,User::Invariant());
       
  1435 	if (IsCommitted())
       
  1436 		return;
       
  1437 //
       
  1438 	CommitL();
       
  1439 	iHandle=Coord().DoCommit(iHandle,Offset(),Extent());
       
  1440 	}
       
  1441