1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/userlibandfileserver/fileserver/sfat/sl_disk.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,502 @@
1.4 +// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// f32\sfat\sl_disk.cpp
1.18 +//
1.19 +//
1.20 +
1.21 +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1.22 +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1.23 +//!!
1.24 +//!! WARNING!! DO NOT edit this file !! '\sfat' component is obsolete and is not being used. '\sfat32'replaces it
1.25 +//!!
1.26 +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1.27 +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1.28 +
1.29 +#include "sl_disk.h"
1.30 +#include "sl_cache.h"
1.31 +#include "sl_dir_cache.h"
1.32 +
1.33 +/**
1.34 +@file
1.35 +*/
1.36 +
1.37 +
1.38 +//################################################################################################################################
1.39 +//# CRawDisk implementation
1.40 +//################################################################################################################################
1.41 +
1.42 +
1.43 +/**
1.44 + Factory function. Constructs objects of the classes derived from CRawDisk.
1.45 +
1.46 + @param aOwner reference to the onwning FAT Mount class
1.47 + @param aLocDrvCaps local drive capabilities from the media driver
1.48 + @return pointer to the constructed object. May be NULL on error.
1.49 +*/
1.50 +CRawDisk* CRawDisk::NewL(CFatMountCB& aOwner, const TLocalDriveCaps& aLocDrvCaps)
1.51 +{
1.52 + __PRINT1(_L("CRawDisk::NewL() drv:%d"), aOwner.DriveNumber());
1.53 +
1.54 + if(aLocDrvCaps.iMediaAtt & KMediaAttVariableSize)
1.55 + {//-- this is the RAM drive "attribute"
1.56 + ASSERT((aLocDrvCaps.iDriveAtt & (KDriveAttInternal|KDriveAttLocal)) && aLocDrvCaps.iType == EMediaRam);
1.57 + if(!aLocDrvCaps.iBaseAddress)
1.58 + {
1.59 + ASSERT(0);
1.60 + return NULL;
1.61 + }
1.62 +
1.63 + return CRamDisk::NewL(aOwner);
1.64 + }
1.65 +
1.66 + //-- create CAtaDisk by default
1.67 + return CAtaDisk::NewL(aOwner);
1.68 +}
1.69 +
1.70 +
1.71 +CRawDisk::CRawDisk(CFatMountCB& aOwner)
1.72 + {
1.73 + iFatMount = &aOwner;
1.74 + }
1.75 +
1.76 +/**
1.77 + Default implementation. Initialises and re-initialises the object.
1.78 +*/
1.79 +void CRawDisk::InitializeL()
1.80 + {
1.81 + ASSERT(iFatMount);
1.82 + }
1.83 +
1.84 +
1.85 +TInt CRawDisk::GetLastErrorInfo(TDes8& /*aErrorInfo*/) const
1.86 + {
1.87 + return KErrNotSupported;
1.88 + }
1.89 +
1.90 +//################################################################################################################################
1.91 +//## CAtaDisk class implementation
1.92 +//################################################################################################################################
1.93 +
1.94 +CAtaDisk::CAtaDisk(CFatMountCB& aFatMount)
1.95 + :CRawDisk(aFatMount), iDrive(aFatMount.DriveInterface())
1.96 + {
1.97 + }
1.98 +
1.99 +CAtaDisk::~CAtaDisk()
1.100 + {
1.101 + delete ipDirCache;
1.102 + delete iUidCache;
1.103 +
1.104 + }
1.105 +
1.106 +
1.107 +//-------------------------------------------------------------------------------------
1.108 +
1.109 +/**
1.110 + CAtaDisk factory method.
1.111 +
1.112 + @param aFatMount reference to the owner.
1.113 + @return pointer to the constructed object.
1.114 +*/
1.115 +CAtaDisk* CAtaDisk::NewL(CFatMountCB& aFatMount)
1.116 + {
1.117 + __PRINT1(_L("CAtaDisk::NewL() drv:%d"), aFatMount.DriveNumber());
1.118 +
1.119 + CAtaDisk* pSelf = new (ELeave) CAtaDisk(aFatMount);
1.120 +
1.121 + CleanupStack::PushL(pSelf);
1.122 +
1.123 + pSelf->ConstructL();
1.124 + pSelf->InitializeL();
1.125 +
1.126 + CleanupStack::Pop();
1.127 +
1.128 + return pSelf;
1.129 + }
1.130 +
1.131 +//-------------------------------------------------------------------------------------
1.132 +
1.133 +/** 2nd stage constructor */
1.134 +void CAtaDisk::ConstructL()
1.135 + {
1.136 + //=========================== create data WT cache that is primarily used for caching exacutable modules' UIDs
1.137 + const TUint32 KUidCachePageSzLog2 = 9; //-- 512 bytes in page
1.138 + const TUint32 KUidCachePages = 64; //-- 64 pages; total cache size is 32K
1.139 +
1.140 + iUidCache = CMediaWTCache::NewL(iDrive, KUidCachePages, KUidCachePageSzLog2);
1.141 +
1.142 +
1.143 + //=========================== create directory cache
1.144 +
1.145 + //-- Get dir. cache parameters from config. They may be set in estart.txt for a specified drive.
1.146 + const TUint32 KDirCacheSize = iFatMount->FatConfig().DirCacheSize(); //- Total directory cache size, bytes.
1.147 + const TUint32 KMaxDirCachePageSzLog2 = iFatMount->FatConfig().DirCacheMaxPageSizeLog2(); //- Log2 of the Max. dir. cache page.
1.148 +
1.149 + __PRINT2(_L("CAtaDisk::ConstructL() Dir Cache config:%d,%d"),KDirCacheSize,KMaxDirCachePageSzLog2);
1.150 +
1.151 + ASSERT(KDirCacheSize >= K1KiloByte && KDirCacheSize <= K1MegaByte);
1.152 + ASSERT((KMaxDirCachePageSzLog2 >= KDefSectorSzLog2) && (Pow2(KMaxDirCachePageSzLog2) <= KDirCacheSize));
1.153 +
1.154 + //-- calculate the size and number of pages for the dir. cache.
1.155 + //-- if the mount's cluster size is less than max. page size from config, the page size will be cluster size.
1.156 + //-- otherwise it will be the value from config. I.e the minimal page size is cluster size; the maximal page size is taken from config.
1.157 + //-- The number of pages depends on total cache size and page size.
1.158 + const TUint clustSizeLog2 = iFatMount->ClusterSizeLog2(); //-- current FAT cluster size Log2
1.159 + const TUint32 pageSzLog2 = (clustSizeLog2 <= KMaxDirCachePageSzLog2) ? clustSizeLog2 : KMaxDirCachePageSzLog2;
1.160 + const TUint32 numPages = KDirCacheSize / (Pow2(pageSzLog2));
1.161 +
1.162 + ASSERT(!ipDirCache);
1.163 +
1.164 +#ifdef USE_DP_DIR_CACHE
1.165 +
1.166 + //=========================== create Demand Paging type of the directory cache
1.167 +
1.168 + // initialize cache memory manager as all file systems have mounted by now
1.169 + if(CCacheMemoryManagerFactory::CacheMemoryManager())
1.170 + {
1.171 + // Note: the configuration data of min and max cache size are aligned with the memory size it
1.172 + // occupies in kernel as we are using demand paging subsystem for dynamic cache size support.
1.173 + // Therefore, they are refered as 'Mem Size' in following calculation.
1.174 + // However, 'Data Size' refers to the logical size of a page, i.e. the actual data size each page
1.175 + // contains.
1.176 + // The constraints we have to consider when setting up the dynamic cache:
1.177 + // 1. each page's data size is aligned with cluster size, unless cluster size is bigger than
1.178 + // the default maximum page size allowed (typically 32 KB).
1.179 + // 2. if page's data size is smaller than segment size (typically 4 KB), i.e. the unit size of
1.180 + // demand paging subsystem's page management, we will still use up the whole segment for
1.181 + // that page.
1.182 + // 3. the default min and max cache's memory size is pre-defined in fat_config.cpp file.
1.183 + // (see KDef_DynamicDirCacheMin & KDef_DynamicDirCacheMax).
1.184 +
1.185 + // calculate page data size (logical view of page size)
1.186 + const TUint32 DefMaxCachePageLog2 = iFatMount->FatConfig().DynamicDirCacheMaxPageSizeLog2();
1.187 + const TUint32 PageDataSizeLog2 = clustSizeLog2 < DefMaxCachePageLog2 ? clustSizeLog2 : DefMaxCachePageLog2;
1.188 +
1.189 + // calculate page number, based on memory size we have reserved
1.190 + const TUint32 SegmentSizeLog2 = CCacheMemoryManagerFactory::CacheMemoryManager()->SegmentSizeInBytesLog2();
1.191 + const TUint32 PageMemSizeLog2 = PageDataSizeLog2 < SegmentSizeLog2 ? SegmentSizeLog2 : PageDataSizeLog2;
1.192 + TUint32 CacheSizeMinInPages = iFatMount->FatConfig().DynamicDirCacheSizeMin() >> PageMemSizeLog2;
1.193 + TUint32 CacheSizeMaxInPages = iFatMount->FatConfig().DynamicDirCacheSizeMax() >> PageMemSizeLog2;
1.194 +
1.195 + // cache memory client is connected via name
1.196 + TBuf<0x20> clientName = _L("CACHE_MEM_CLIENT:");
1.197 + clientName.Append('A'+iFatMount->DriveNumber());
1.198 +
1.199 + TRAPD(err, ipDirCache = CDynamicDirCache::NewL(iDrive, CacheSizeMinInPages, CacheSizeMaxInPages, PageDataSizeLog2, clientName));
1.200 + if (err == KErrNone)
1.201 + {
1.202 + __PRINT4(_L("CDynamicDirCache::NewL(drv:%C, minPageNum:%u, maxPageNum:%u, pageDataSize:%u)\n"), 'A'+iFatMount->DriveNumber(), CacheSizeMinInPages, CacheSizeMaxInPages, 1<<PageDataSizeLog2);
1.203 + return;
1.204 + }
1.205 + }
1.206 +#endif // USE_DP_DIR_CACHE
1.207 +
1.208 + //=========================== create legacy type of the directory cache
1.209 + ASSERT(!ipDirCache);
1.210 +
1.211 + ipDirCache = CMediaWTCache::NewL(iDrive, numPages, pageSzLog2);
1.212 + __PRINT3(_L("CDirCache::NewL(drive: %C, NumPages=%d, PageSize=%u)"), 'A'+iFatMount->DriveNumber(), numPages, 1<<pageSzLog2);
1.213 +
1.214 + }
1.215 +
1.216 +//-------------------------------------------------------------------------------------
1.217 +
1.218 +/**
1.219 + Initialises and re-initialises the object.
1.220 +*/
1.221 +void CAtaDisk::InitializeL()
1.222 +{
1.223 + CRawDisk::InitializeL();
1.224 +
1.225 + //-- there is a little issue here. after formatting FAT mounts's cluster size can change.
1.226 + //-- dir. cache page size depends on the cluster size. This method doesn't change the dir. cache page size.
1.227 + //-- At present it is done in CFatMountCB::InitializeL() that deletes this object and then reconstructs it again.
1.228 +
1.229 + //-- invalidate directory cache here
1.230 + ipDirCache->InvalidateCache();
1.231 +
1.232 + TInt64 cacheBasePos;
1.233 +
1.234 + if(iFatMount->FatType() == EFat32)
1.235 + {
1.236 + //-- this is FAT32, all directories including Root are files and aligned to the cluster heap boundary
1.237 + //-- set dir. cache base position to the cluster heap boundary
1.238 + const TUint32 offsetMask = (1 << iFatMount->ClusterSizeLog2() )-1;
1.239 + cacheBasePos = (iFatMount->ClusterBasePosition() & offsetMask);
1.240 + }
1.241 + else
1.242 + {
1.243 + //-- this is FAT12/16. Root directory is a separate volume object and has no alignment.
1.244 + //-- set cache base position to its beginning.
1.245 + cacheBasePos = iFatMount->StartOfRootDirInBytes();
1.246 + }
1.247 +
1.248 + ipDirCache->SetCacheBasePos(cacheBasePos);
1.249 +
1.250 +}
1.251 +
1.252 +//-------------------------------------------------------------------------------------
1.253 +
1.254 +/**
1.255 + Read data from the media through LRU data cache cache.
1.256 +
1.257 + @param aPos absolute media position
1.258 + @param aLength how many bytes to read
1.259 + @param aDes data descriptor
1.260 +
1.261 + @leave on error
1.262 +*/
1.263 +void CAtaDisk::ReadCachedL(TInt64 aPos,TInt aLength,TDes8& aDes) const
1.264 + {
1.265 + __PRINT3(_L("CAtaDisk::ReadL() pos:%u:%u, len:%u"), I64HIGH(aPos), I64LOW(aPos), aLength);
1.266 + iUidCache->ReadL(aPos, aLength, aDes);
1.267 + }
1.268 +
1.269 +//-------------------------------------------------------------------------------------
1.270 +
1.271 +/**
1.272 + Write data to the media through LRU data cache
1.273 +
1.274 + @param aPos absolute media position
1.275 + @param aDes data descriptor
1.276 +
1.277 + @leave on error
1.278 +*/
1.279 +void CAtaDisk::WriteCachedL(TInt64 aPos, const TDesC8& aDes)
1.280 + {
1.281 + __PRINT3(_L("CAtaDisk::WriteL() pos:%u:%u, len:%u"), I64HIGH(aPos), I64LOW(aPos), aDes.Size());
1.282 + iUidCache->WriteL(aPos, aDes);
1.283 + }
1.284 +
1.285 +
1.286 +//-------------------------------------------------------------------------------------
1.287 +
1.288 +/**
1.289 + Read data from the media directly without any caches.
1.290 + Mostly used by file IO
1.291 +
1.292 + @param aPos absolute media position
1.293 + @param aLength how many bytes to read
1.294 + @param aTrg Pointer to the data descriptor, i.e. (const TAny*)(&TDes8)
1.295 + @param aMessage Refrence to server message from request
1.296 + @param anOffset Offset into read data to write
1.297 +
1.298 + @leave on error
1.299 +*/
1.300 +void CAtaDisk::ReadL(TInt64 aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2 &aMessage,TInt anOffset) const
1.301 + {
1.302 +
1.303 + __PRINT4(_L("CAtaDisk::ReadL() pos:%u:%u, len:%u, offset:%u"), I64HIGH(aPos), I64LOW(aPos), aLength, anOffset);
1.304 + User::LeaveIfError(iDrive.ReadNonCritical(aPos,aLength,aTrg,aMessage,anOffset));
1.305 + }
1.306 +
1.307 +//-------------------------------------------------------------------------------------
1.308 +
1.309 +/**
1.310 + Write data to the media directly without any cached.
1.311 + Mostly used by file IO
1.312 +
1.313 + This method shall invalidate some data caches to keep them in synch with the media.
1.314 +
1.315 + @param aPos Media position in bytes
1.316 + @param aLength Length in bytes of write
1.317 + @param aTrg Pointer to the data descriptor, i.e. (const TAny*)(&TDes8)
1.318 + @param aMessage Refrence to server message from request, contains data
1.319 + @param anOffset Offset into write data to use in write
1.320 +
1.321 + @leave on error
1.322 +*/
1.323 +void CAtaDisk::WriteL(TInt64 aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2 &aMessage,TInt anOffset)
1.324 + {
1.325 + __PRINT4(_L("CAtaDisk::WriteL() pos:%u:%u, len:%u, offset:%u"), I64HIGH(aPos), I64LOW(aPos), aLength, anOffset);
1.326 +
1.327 + //-- write data to the media directly
1.328 + User::LeaveIfError(iDrive.WriteNonCritical(aPos,aLength,aSrc,aMessage,anOffset));
1.329 +
1.330 + //-- we need to invalidate UID cache page that corresponds to aPos (if any). This is UID caching specific. UID is stored in the first few bytes of
1.331 + //-- the executable module and therefore belongs to one cache page only.
1.332 + //-- If someone writes to the beginning of the exe module file, corresponding UID cache page will be invalidated and re-read from the media later
1.333 + iUidCache->InvalidateCachePage(aPos);
1.334 +
1.335 + //-- invalidate affected(if any) part of the FAT cache in the case if someone used to write data to FAT area, which usually do not happen
1.336 + iFatMount->FAT().InvalidateCacheL(aPos,aLength);
1.337 +
1.338 + }
1.339 +
1.340 +//-------------------------------------------------------------------------------------
1.341 +
1.342 +/** Get information for last disk error */
1.343 +TInt CAtaDisk::GetLastErrorInfo(TDes8& aErrorInfo) const
1.344 + {
1.345 + return iDrive.GetLastErrorInfo(aErrorInfo);
1.346 + }
1.347 +
1.348 +
1.349 +//-------------------------------------------------------------------------------------
1.350 +/** Invalidate whole UID cache */
1.351 +void CAtaDisk::InvalidateUidCache()
1.352 +{
1.353 + ASSERT(iUidCache);
1.354 + iUidCache->InvalidateCache();
1.355 +}
1.356 +
1.357 +/**
1.358 + Invalidate the UID cache page that has aPos cached.
1.359 + This method doesn't pay attention to the length of the block being invalidated because
1.360 + UID lives in the very beginning of the exe module and always fits into a single page
1.361 +*/
1.362 +void CAtaDisk::InvalidateUidCachePage(TUint64 aPos)
1.363 +{
1.364 + ASSERT(iUidCache);
1.365 + iUidCache->InvalidateCachePage(aPos);
1.366 +}
1.367 +
1.368 +
1.369 +//################################################################################################################################
1.370 +//## CRamDisk class implementation
1.371 +//################################################################################################################################
1.372 +
1.373 +
1.374 +/**
1.375 + CRamDisk factory method.
1.376 +
1.377 + @param aFatMount reference to the owner.
1.378 + @return pointer to the constructed object.
1.379 +*/
1.380 +CRamDisk* CRamDisk::NewL(CFatMountCB& aFatMount)
1.381 + {
1.382 + __PRINT1(_L("CRamDisk::NewL() drv:%d"), aFatMount.DriveNumber());
1.383 + CRamDisk* pSelf = new(ELeave)CRamDisk(aFatMount);
1.384 +
1.385 + CleanupStack::PushL(pSelf);
1.386 +
1.387 + pSelf->InitializeL();
1.388 +
1.389 + CleanupStack::Pop();
1.390 +
1.391 + return pSelf;
1.392 + }
1.393 +
1.394 +CRamDisk::CRamDisk(CFatMountCB& aFatMount)
1.395 + :CRawDisk(aFatMount)
1.396 + {
1.397 + }
1.398 +
1.399 +//-------------------------------------------------------------------------------------
1.400 +
1.401 +/**
1.402 + Initialises and re-initialises the object.
1.403 +*/
1.404 +void CRamDisk::InitializeL()
1.405 +{
1.406 + CRawDisk::InitializeL();
1.407 +
1.408 + //-- set the RAM disk base
1.409 + TLocalDriveCapsV2 caps;
1.410 + TPckg<TLocalDriveCapsV2> capsPckg(caps);
1.411 + User::LeaveIfError(iFatMount->LocalDrive()->Caps(capsPckg));
1.412 +
1.413 + ASSERT(caps.iMediaAtt & KMediaAttVariableSize);
1.414 +
1.415 + //-- set RAM disk base
1.416 + iRamDiskBase = caps.iBaseAddress;
1.417 + ASSERT(iRamDiskBase);
1.418 +}
1.419 +
1.420 +
1.421 +
1.422 +/** @return the start address of the Ram Drive in low memory */
1.423 +TUint8* CRamDisk::RamDiskBase() const
1.424 + {
1.425 + return iRamDiskBase;
1.426 + }
1.427 +
1.428 +//-------------------------------------------------------------------------------------
1.429 +//
1.430 +// Read aLength of data from the disk
1.431 +//
1.432 +void CRamDisk::ReadCachedL(TInt64 aPos,TInt aLength,TDes8& aDes) const
1.433 + {
1.434 +
1.435 + __PRINT3(_L("CRamDisk::ReadL Base 0x%x Pos 0x%x, Len %d"),RamDiskBase(),I64LOW(aPos),aLength);
1.436 + __ASSERT_ALWAYS((aPos+aLength<=I64INT(iFatMount->Size())) && (aLength>=0),User::Leave(KErrCorrupt));
1.437 + Mem::Copy((TUint8*)aDes.Ptr(),RamDiskBase()+I64LOW(aPos),aLength);
1.438 + aDes.SetLength(aLength);
1.439 + }
1.440 +
1.441 +//-------------------------------------------------------------------------------------
1.442 +//
1.443 +// Write aLength of data to the disk
1.444 +//
1.445 +void CRamDisk::WriteCachedL(TInt64 aPos,const TDesC8& aDes)
1.446 + {
1.447 +
1.448 + __PRINT3(_L("CRamDisk::WriteL Base 0x%x Pos 0x%x, Len %d"),RamDiskBase(),aPos,aDes.Length());
1.449 + __ASSERT_ALWAYS(aPos+aDes.Length()<=I64INT(iFatMount->Size()),User::Leave(KErrCorrupt));
1.450 + Mem::Copy(RamDiskBase()+I64LOW(aPos),(TUint8*)aDes.Ptr(),aDes.Length());
1.451 + }
1.452 +
1.453 +
1.454 +//-------------------------------------------------------------------------------------
1.455 +//
1.456 +// Read from ramDrive into thread relative descriptor
1.457 +//
1.458 +void CRamDisk::ReadL(TInt64 aPos,TInt aLength,const TAny* /*aTrg*/,const RMessagePtr2 &aMessage,TInt anOffset) const
1.459 + {
1.460 + __PRINT2(_L("CRamDisk::ReadL TAny* Pos 0x%x, Len %d"),aPos,aLength);
1.461 + __ASSERT_ALWAYS((aPos+aLength<=I64INT(iFatMount->Size())) && (aLength>=0),User::Leave(KErrCorrupt));
1.462 + TUint8* pos=RamDiskBase()+I64LOW(aPos);
1.463 + TPtrC8 buf(pos,aLength);
1.464 + aMessage.WriteL(0,buf,anOffset);
1.465 + }
1.466 +
1.467 +//-------------------------------------------------------------------------------------
1.468 +//
1.469 +// Write from thread relative descriptor into ramDrive
1.470 +//
1.471 +void CRamDisk::WriteL(TInt64 aPos,TInt aLength,const TAny* /*aSrc*/,const RMessagePtr2 &aMessage,TInt anOffset)
1.472 + {
1.473 + __PRINT2(_L("CRamDisk::WriteL TAny* Pos 0x%x, Len %d"),aPos,aLength);
1.474 + __ASSERT_ALWAYS(aPos+aLength<=I64INT(iFatMount->Size()),User::Leave(KErrCorrupt));
1.475 + TUint8* pos=RamDiskBase()+I64LOW(aPos);
1.476 + TPtr8 buf(pos,aLength);
1.477 + aMessage.ReadL(0,buf,anOffset);
1.478 + }
1.479 +
1.480 +
1.481 +
1.482 +
1.483 +
1.484 +
1.485 +
1.486 +
1.487 +
1.488 +
1.489 +
1.490 +
1.491 +
1.492 +
1.493 +
1.494 +
1.495 +
1.496 +
1.497 +
1.498 +
1.499 +
1.500 +
1.501 +
1.502 +
1.503 +
1.504 +
1.505 +