featuremgmt/featureregistry/src/setup/featregsetup.cpp
changeset 0 08ec8eefde2f
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     1 // Copyright (c) 2005-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 // Reads feature config file, checks it is valid, defines feature property from it and quits.
       
    15 // Debug builds panic if config file could not be read or is invalid, but only after all
       
    16 // processing is complete so debug and release executables still work roughly the same.
       
    17 // 
       
    18 //
       
    19 
       
    20 /**
       
    21  @file
       
    22  @internalComponent
       
    23 */
       
    24 
       
    25 #include <e32base.h>
       
    26 #include <e32cmn.h>
       
    27 #include <e32property.h>
       
    28 #include <f32file.h>
       
    29 #include "featregpan.h"
       
    30 #include "featregcmn.h"
       
    31 
       
    32 static TBool IsFeatureDataValid(const TDesC8& aFeatureDes)
       
    33 	{
       
    34 	// size from number of entries and ranges in header must match descriptor size
       
    35 	const TFeatureHeader* header = reinterpret_cast<const TFeatureHeader*>(aFeatureDes.Ptr());
       
    36 	if (header->IsInvalidOrBadSize(aFeatureDes.Size()))
       
    37 		{
       
    38 		return EFalse;
       
    39 		}
       
    40 
       
    41 	// check feature entries are non-repeating and sorted from lowest to highest UID
       
    42 	const TFeatureEntry* entry = reinterpret_cast<const TFeatureEntry*>(header + 1);
       
    43 	TInt i = header->iFeatureEntryCount;
       
    44 	TUint32 previousEntryUid = 0;
       
    45 	if (i > 0)
       
    46 		{
       
    47 		previousEntryUid = entry->iUid;
       
    48 		++entry;
       
    49 		--i;
       
    50 		}
       
    51 	for (; i > 0; --i)
       
    52 		{
       
    53 		if (previousEntryUid >= entry->iUid)
       
    54 			{
       
    55 			return EFalse;
       
    56 			}
       
    57 		previousEntryUid = entry->iUid;
       
    58 		++entry;
       
    59 		}
       
    60 
       
    61 	// check default=supported ranges are in low-high UID pairs
       
    62 	const TFeatureRange* range = reinterpret_cast<const TFeatureRange*>(entry);
       
    63 	for (i = header->iFeatureRangeCount; i > 0; --i)
       
    64 		{
       
    65 		if (range->iLowUid > range->iHighUid)
       
    66 			{
       
    67 			return EFalse;
       
    68 			}
       
    69 		++range;
       
    70 		}
       
    71 
       
    72 	return ETrue;
       
    73 	}
       
    74 
       
    75 /**
       
    76  * Reads contents of a file into aBuf, reallocating if needed
       
    77  * Afterwards aBuf may own memory even in case of failure - up to calling code to clean it up
       
    78  * @return KErrNone on success, KErrCorrupt if invalid file size, otherwise other system-wide error code
       
    79  */
       
    80 static TInt ReadFeatureFileToBuf(RFs &aFs, const TDesC& aFileName, RBuf8& aBuf)
       
    81 	{
       
    82 	RFile inFile;
       
    83 	TInt result = inFile.Open(aFs, aFileName, EFileRead|EFileShareReadersOnly|EFileStream);
       
    84 	if (result != KErrNone)
       
    85 		{
       
    86 		return result;
       
    87 		}
       
    88 	TInt fileSize;
       
    89 	result = inFile.Size(fileSize);
       
    90 	if ((fileSize < sizeof(TFeatureHeader)) || (fileSize > RProperty::KMaxLargePropertySize))
       
    91 		{
       
    92 		result = KErrCorrupt;
       
    93 		}
       
    94 	if (result == KErrNone)
       
    95 		{
       
    96  		result = aBuf.ReAlloc(fileSize);
       
    97 		}
       
    98 	if (result == KErrNone)
       
    99 		{
       
   100 		result = inFile.Read(aBuf);
       
   101 		}
       
   102 	inFile.Close();
       
   103 	if (result == KErrNone && !IsFeatureDataValid(aBuf))
       
   104 		{
       
   105 		result = KErrCorrupt;
       
   106 		}	
       
   107 	return result;
       
   108 	}
       
   109 
       
   110 static TInt CompareFeatureEntry(const TFeatureEntry& aEntry1,const TFeatureEntry& aEntry2)
       
   111 	{
       
   112 	return (aEntry1.iUid-aEntry2.iUid);
       
   113 	}
       
   114 	
       
   115 static TInt CompareFeatureRange(const TFeatureRange& aEntry1,const TFeatureRange& aEntry2)
       
   116 	{
       
   117 	//the comparison when both default supported range are the same
       
   118 	if (aEntry1.iLowUid==aEntry2.iLowUid && aEntry1.iHighUid==aEntry2.iHighUid)
       
   119 		{
       
   120 		return 0;		
       
   121 		}
       
   122 	return (aEntry1.iLowUid<aEntry2.iLowUid?-1:1);
       
   123 	}	
       
   124 
       
   125 static void ResetRBufArray(RArray<RBuf8>& aRBuf8Array)
       
   126 	{
       
   127 	TInt count=aRBuf8Array.Count();
       
   128 	for (TInt i=0;i<count;i++)
       
   129 		{
       
   130 		aRBuf8Array[i].Close();
       
   131 		}
       
   132 	aRBuf8Array.Reset();
       
   133 	aRBuf8Array.Close();
       
   134 	}
       
   135 
       
   136 /**
       
   137 This function will try to find and open all the "featreg.cfg" files from the path specified
       
   138 process them in the order of increasing rom image id before copying the aggregate content
       
   139 into the buffer aBuf. Validation of each of the file is also performed inside this function.
       
   140 @param aFs an opened file server session
       
   141 @param aPath the path to look for the featreg files
       
   142 @param aBuf the buffer to contain the aggregated file content
       
   143 @return KErrNoMemory if no memory, KErrCorrupt if any of the featreg.cfg files it found in the path
       
   144 		is corrupt.
       
   145 */
       
   146 GLDEF_C TInt ReadMultipleFeatureFileToBuf(RFs& aFs,const TDesC& aPath,RBuf8& aBuf)
       
   147 	{
       
   148 	CDir* featregList=NULL;
       
   149 	HBufC* matchPattern=HBufC::New(aPath.Length()+KFeatregMatchPattern().Length());
       
   150 	if (!matchPattern)
       
   151 		{
       
   152 		return KErrNoMemory;
       
   153 		}
       
   154 	TPtr matchPatternPtr(matchPattern->Des());		
       
   155 	matchPatternPtr.Append(aPath);
       
   156 	matchPatternPtr.Append(KFeatregMatchPattern);
       
   157 	TInt ret=aFs.GetDir(*matchPattern,KEntryAttReadOnly | KEntryAttHidden | KEntryAttSystem | KEntryAttArchive,ESortByName,featregList);
       
   158 	delete matchPattern;
       
   159 	if (ret!=KErrNone)
       
   160 		{
       
   161 		return ret;
       
   162 		}
       
   163 	TInt fileCount=featregList->Count();
       
   164 	//if only one file we do not need the array
       
   165 	if (fileCount==1)
       
   166 		{
       
   167 		TFileName fullName(aPath);
       
   168 		fullName.Append((*featregList)[0].iName);
       
   169 		delete featregList;
       
   170 		return ReadFeatureFileToBuf(aFs,fullName,aBuf);
       
   171 		}
       
   172 		
       
   173 	//else if there are more than one file we need to open and validate each file
       
   174 	//before appending each file content to the buffer array
       
   175 	RArray<RBuf8> featregFileBufArray;
       
   176 	for (TInt i=0;i<fileCount;i++)
       
   177 		{
       
   178 		TFileName fullName(aPath);
       
   179 		fullName.Append((*featregList)[i].iName);
       
   180 		RBuf8 fileBuffer;
       
   181 		//first try to read the file into buffer and if successful append to the array
       
   182 		if ((ret=ReadFeatureFileToBuf(aFs,fullName,fileBuffer))!=KErrNone || (ret=featregFileBufArray.Append(fileBuffer))!=KErrNone)
       
   183 			{
       
   184 			//something wrong here reset the buffer and return the error code
       
   185 			fileBuffer.Close();
       
   186 			delete featregList;
       
   187 			ResetRBufArray(featregFileBufArray);
       
   188 			return ret;
       
   189 			}
       
   190 		}
       
   191 	//the list of files no longer needed we can delete now
       
   192 	delete featregList;
       
   193 
       
   194 	//at this stage we are sure all the featreg files are not corrupt
       
   195 	//we need to read the single feature entries and the default
       
   196 	//supported range before reconstructing the output buffer
       
   197 	RArray<TFeatureEntry> singleArray;
       
   198 	RArray<TFeatureRange> rangeArray;
       
   199 	//process it in the reverse order as we read it as rom image with higher id will be mounted first
       
   200 	for (TInt idx=fileCount-1;idx>=0;idx--)
       
   201 		{
       
   202 		const TFeatureHeader* header = reinterpret_cast<const TFeatureHeader*>(featregFileBufArray[idx].Ptr());
       
   203 		const TFeatureEntry* entry=reinterpret_cast<const TFeatureEntry*>(header+1);
       
   204 		const TFeatureRange* range=reinterpret_cast<const TFeatureRange*>(entry+header->iFeatureEntryCount);		
       
   205 		for (TInt s=0;s<header->iFeatureEntryCount;s++)
       
   206 			{
       
   207 			ret=singleArray.InsertInOrder(*(reinterpret_cast<const TFeatureEntry*>(entry+s)),TLinearOrder<TFeatureEntry>(CompareFeatureEntry));
       
   208 			//ignore KErrAlreadyExists as we purposely do not want duplicate entries
       
   209 			if (ret!=KErrNone && ret!=KErrAlreadyExists)
       
   210 				{
       
   211 				singleArray.Close();
       
   212 				rangeArray.Close();
       
   213 				ResetRBufArray(featregFileBufArray);
       
   214 				return ret;			
       
   215 				}
       
   216 			}
       
   217 		//for range, we just insert them but ignore duplicate
       
   218 		for (TInt r=0;r<header->iFeatureRangeCount;r++)
       
   219 			{
       
   220 			ret=rangeArray.InsertInOrder(*(reinterpret_cast<const TFeatureRange*>(range+r)),TLinearOrder<TFeatureRange>(CompareFeatureRange));
       
   221 			if (ret!=KErrNone && ret!=KErrAlreadyExists)
       
   222 				{
       
   223 				singleArray.Close();
       
   224 				rangeArray.Close();
       
   225 				ResetRBufArray(featregFileBufArray);
       
   226 				return ret;	
       
   227 				}
       
   228 			}
       
   229 		}
       
   230 	//now the final step is to construct the aggregate RBuf
       
   231 	RBuf8 buf8;
       
   232 	TInt singleCount=singleArray.Count();
       
   233 	TInt rangeCount=rangeArray.Count();
       
   234 	ret=buf8.Create(sizeof(TFeatureHeader)+singleCount*sizeof(TFeatureEntry)+rangeCount*sizeof(TFeatureRange));
       
   235 	if (ret==KErrNone)
       
   236 		{
       
   237 		TFeatureHeader header={validTypePrefix,0,singleCount,rangeCount};
       
   238 		buf8.Append(reinterpret_cast<const TUint8*>(&header),sizeof(TFeatureHeader));
       
   239 		for (TInt s=0;s<singleCount;s++)
       
   240 			{
       
   241 			buf8.Append(reinterpret_cast<const TUint8*>(&(singleArray[s])),sizeof(TFeatureEntry));
       
   242 			}
       
   243 		for (TInt r=0;r<rangeCount;r++)
       
   244 			{
       
   245 			buf8.Append(reinterpret_cast<const TUint8*>(&(rangeArray[r])),sizeof(TFeatureRange));
       
   246 			}	
       
   247 		//transfer ownership now
       
   248 		aBuf.Assign(buf8);	
       
   249 		}
       
   250 	//perform cleanup
       
   251 	singleArray.Close();
       
   252 	rangeArray.Close();
       
   253 	ResetRBufArray(featregFileBufArray);	
       
   254 	return ret;	
       
   255 	}
       
   256 
       
   257 
       
   258 /**
       
   259  * @return KErrNone (0) if successful, KErrNoMemory or KErrCorrupt if file read failed,
       
   260  * otherwise error result from calling RProperty::Define/Set
       
   261  */
       
   262 #ifndef FEATREGSETUPTEST
       
   263 TInt E32Main()
       
   264 	{
       
   265 	__UHEAP_MARK;
       
   266 	CTrapCleanup* trapCleanup=CTrapCleanup::New();
       
   267 	if (!trapCleanup)
       
   268 		{
       
   269 		return KErrNoMemory;
       
   270 		}
       
   271 
       
   272 	// if the following RProperty is defined, look for config file on the C: private
       
   273 	// data cage instead of the normal Z:. Used for testing only.
       
   274 	TInt testPropertyValue;
       
   275 	TInt testResult = RProperty::Get(KFeaturePropCat, KFeatRegConfigTestKey, testPropertyValue);
       
   276 	const TBool useCDataCage = testResult != KErrNotFound;
       
   277 
       
   278 	RBuf8 featureBuf;
       
   279 	RFs fs;
       
   280 	TInt readResult = KErrNone;
       
   281 	TInt publishResult = KErrNone;
       
   282 	readResult = fs.Connect();
       
   283 	if (readResult == KErrNone)
       
   284 		{
       
   285 		if (useCDataCage)
       
   286 			{
       
   287 			TConfigFileName filename;
       
   288 			GetSystemDrivePath(filename);
       
   289 			readResult = ReadFeatureFileToBuf(fs, filename, featureBuf);
       
   290 			}
       
   291 		else
       
   292 			{
       
   293 			readResult=ReadMultipleFeatureFileToBuf(fs,KFeatregRomPrivatePath,featureBuf);
       
   294 			}
       
   295 		fs.Close();
       
   296 		}
       
   297 
       
   298 	// lack of memory may be temporary, so end rather than publishing invalid property now
       
   299 	if (readResult != KErrNoMemory)
       
   300 		{
       
   301 		RProcess thisProcess;
       
   302 		// sanity check that feature property category in common header equals SID of this process
       
   303 		ASSERT(KFeaturePropCat == thisProcess.SecureId());
       
   304 		TSecurityPolicy readPolicy(TSecurityPolicy::EAlwaysPass);
       
   305 		TSecurityPolicy writePolicy(thisProcess.SecureId());
       
   306 		publishResult = RProperty::Define(KFeaturePropKey, RProperty::ELargeByteArray, readPolicy, writePolicy);
       
   307 
       
   308 		if ((publishResult == KErrNone) || (publishResult == KErrAlreadyExists))
       
   309 			{
       
   310 			if (readResult == KErrNone)
       
   311 				{
       
   312 				publishResult = RProperty::Set(KFeaturePropCat, KFeaturePropKey, featureBuf);
       
   313 				}
       
   314 			else
       
   315 				{
       
   316 				// bad config file: set up invalid property with number of features/ranges not consistent
       
   317 				// with size of property, so Feature Registry API always returns KErrCorrupt
       
   318 				TFeatureHeader corruptHeader;
       
   319 				corruptHeader.SetInvalid();
       
   320 				TPckg<TFeatureHeader> corruptFeaturePckg(corruptHeader);
       
   321 				publishResult = RProperty::Set(KFeaturePropCat, KFeaturePropKey, corruptFeaturePckg);
       
   322 				}
       
   323 			}
       
   324 
       
   325 		if (readResult != KErrNone)
       
   326 			{
       
   327 			readResult = KErrCorrupt;
       
   328 			// panic in debug mode alerts system integrators that config file is missing,
       
   329 			// unreadable or invalid in this OS configuration: a serious problem
       
   330 			__ASSERT_DEBUG(EFalse, Panic(EFeatRegBadConfig));
       
   331 			}
       
   332 		}
       
   333 
       
   334 	featureBuf.Close();
       
   335 	delete trapCleanup;
       
   336 	__UHEAP_MARKEND;
       
   337 	return (readResult != KErrNone) ? readResult : publishResult;
       
   338 	}
       
   339 #endif