1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/persistentdata/featuremgmt/featureregistry/src/setup/featregsetup.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,339 @@
1.4 +// Copyright (c) 2005-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 "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 +// Reads feature config file, checks it is valid, defines feature property from it and quits.
1.18 +// Debug builds panic if config file could not be read or is invalid, but only after all
1.19 +// processing is complete so debug and release executables still work roughly the same.
1.20 +//
1.21 +//
1.22 +
1.23 +/**
1.24 + @file
1.25 + @internalComponent
1.26 +*/
1.27 +
1.28 +#include <e32base.h>
1.29 +#include <e32cmn.h>
1.30 +#include <e32property.h>
1.31 +#include <f32file.h>
1.32 +#include "featregpan.h"
1.33 +#include "featregcmn.h"
1.34 +
1.35 +static TBool IsFeatureDataValid(const TDesC8& aFeatureDes)
1.36 + {
1.37 + // size from number of entries and ranges in header must match descriptor size
1.38 + const TFeatureHeader* header = reinterpret_cast<const TFeatureHeader*>(aFeatureDes.Ptr());
1.39 + if (header->IsInvalidOrBadSize(aFeatureDes.Size()))
1.40 + {
1.41 + return EFalse;
1.42 + }
1.43 +
1.44 + // check feature entries are non-repeating and sorted from lowest to highest UID
1.45 + const TFeatureEntry* entry = reinterpret_cast<const TFeatureEntry*>(header + 1);
1.46 + TInt i = header->iFeatureEntryCount;
1.47 + TUint32 previousEntryUid = 0;
1.48 + if (i > 0)
1.49 + {
1.50 + previousEntryUid = entry->iUid;
1.51 + ++entry;
1.52 + --i;
1.53 + }
1.54 + for (; i > 0; --i)
1.55 + {
1.56 + if (previousEntryUid >= entry->iUid)
1.57 + {
1.58 + return EFalse;
1.59 + }
1.60 + previousEntryUid = entry->iUid;
1.61 + ++entry;
1.62 + }
1.63 +
1.64 + // check default=supported ranges are in low-high UID pairs
1.65 + const TFeatureRange* range = reinterpret_cast<const TFeatureRange*>(entry);
1.66 + for (i = header->iFeatureRangeCount; i > 0; --i)
1.67 + {
1.68 + if (range->iLowUid > range->iHighUid)
1.69 + {
1.70 + return EFalse;
1.71 + }
1.72 + ++range;
1.73 + }
1.74 +
1.75 + return ETrue;
1.76 + }
1.77 +
1.78 +/**
1.79 + * Reads contents of a file into aBuf, reallocating if needed
1.80 + * Afterwards aBuf may own memory even in case of failure - up to calling code to clean it up
1.81 + * @return KErrNone on success, KErrCorrupt if invalid file size, otherwise other system-wide error code
1.82 + */
1.83 +static TInt ReadFeatureFileToBuf(RFs &aFs, const TDesC& aFileName, RBuf8& aBuf)
1.84 + {
1.85 + RFile inFile;
1.86 + TInt result = inFile.Open(aFs, aFileName, EFileRead|EFileShareReadersOnly|EFileStream);
1.87 + if (result != KErrNone)
1.88 + {
1.89 + return result;
1.90 + }
1.91 + TInt fileSize;
1.92 + result = inFile.Size(fileSize);
1.93 + if ((fileSize < sizeof(TFeatureHeader)) || (fileSize > RProperty::KMaxLargePropertySize))
1.94 + {
1.95 + result = KErrCorrupt;
1.96 + }
1.97 + if (result == KErrNone)
1.98 + {
1.99 + result = aBuf.ReAlloc(fileSize);
1.100 + }
1.101 + if (result == KErrNone)
1.102 + {
1.103 + result = inFile.Read(aBuf);
1.104 + }
1.105 + inFile.Close();
1.106 + if (result == KErrNone && !IsFeatureDataValid(aBuf))
1.107 + {
1.108 + result = KErrCorrupt;
1.109 + }
1.110 + return result;
1.111 + }
1.112 +
1.113 +static TInt CompareFeatureEntry(const TFeatureEntry& aEntry1,const TFeatureEntry& aEntry2)
1.114 + {
1.115 + return (aEntry1.iUid-aEntry2.iUid);
1.116 + }
1.117 +
1.118 +static TInt CompareFeatureRange(const TFeatureRange& aEntry1,const TFeatureRange& aEntry2)
1.119 + {
1.120 + //the comparison when both default supported range are the same
1.121 + if (aEntry1.iLowUid==aEntry2.iLowUid && aEntry1.iHighUid==aEntry2.iHighUid)
1.122 + {
1.123 + return 0;
1.124 + }
1.125 + return (aEntry1.iLowUid<aEntry2.iLowUid?-1:1);
1.126 + }
1.127 +
1.128 +static void ResetRBufArray(RArray<RBuf8>& aRBuf8Array)
1.129 + {
1.130 + TInt count=aRBuf8Array.Count();
1.131 + for (TInt i=0;i<count;i++)
1.132 + {
1.133 + aRBuf8Array[i].Close();
1.134 + }
1.135 + aRBuf8Array.Reset();
1.136 + aRBuf8Array.Close();
1.137 + }
1.138 +
1.139 +/**
1.140 +This function will try to find and open all the "featreg.cfg" files from the path specified
1.141 +process them in the order of increasing rom image id before copying the aggregate content
1.142 +into the buffer aBuf. Validation of each of the file is also performed inside this function.
1.143 +@param aFs an opened file server session
1.144 +@param aPath the path to look for the featreg files
1.145 +@param aBuf the buffer to contain the aggregated file content
1.146 +@return KErrNoMemory if no memory, KErrCorrupt if any of the featreg.cfg files it found in the path
1.147 + is corrupt.
1.148 +*/
1.149 +GLDEF_C TInt ReadMultipleFeatureFileToBuf(RFs& aFs,const TDesC& aPath,RBuf8& aBuf)
1.150 + {
1.151 + CDir* featregList=NULL;
1.152 + HBufC* matchPattern=HBufC::New(aPath.Length()+KFeatregMatchPattern().Length());
1.153 + if (!matchPattern)
1.154 + {
1.155 + return KErrNoMemory;
1.156 + }
1.157 + TPtr matchPatternPtr(matchPattern->Des());
1.158 + matchPatternPtr.Append(aPath);
1.159 + matchPatternPtr.Append(KFeatregMatchPattern);
1.160 + TInt ret=aFs.GetDir(*matchPattern,KEntryAttReadOnly | KEntryAttHidden | KEntryAttSystem | KEntryAttArchive,ESortByName,featregList);
1.161 + delete matchPattern;
1.162 + if (ret!=KErrNone)
1.163 + {
1.164 + return ret;
1.165 + }
1.166 + TInt fileCount=featregList->Count();
1.167 + //if only one file we do not need the array
1.168 + if (fileCount==1)
1.169 + {
1.170 + TFileName fullName(aPath);
1.171 + fullName.Append((*featregList)[0].iName);
1.172 + delete featregList;
1.173 + return ReadFeatureFileToBuf(aFs,fullName,aBuf);
1.174 + }
1.175 +
1.176 + //else if there are more than one file we need to open and validate each file
1.177 + //before appending each file content to the buffer array
1.178 + RArray<RBuf8> featregFileBufArray;
1.179 + for (TInt i=0;i<fileCount;i++)
1.180 + {
1.181 + TFileName fullName(aPath);
1.182 + fullName.Append((*featregList)[i].iName);
1.183 + RBuf8 fileBuffer;
1.184 + //first try to read the file into buffer and if successful append to the array
1.185 + if ((ret=ReadFeatureFileToBuf(aFs,fullName,fileBuffer))!=KErrNone || (ret=featregFileBufArray.Append(fileBuffer))!=KErrNone)
1.186 + {
1.187 + //something wrong here reset the buffer and return the error code
1.188 + fileBuffer.Close();
1.189 + delete featregList;
1.190 + ResetRBufArray(featregFileBufArray);
1.191 + return ret;
1.192 + }
1.193 + }
1.194 + //the list of files no longer needed we can delete now
1.195 + delete featregList;
1.196 +
1.197 + //at this stage we are sure all the featreg files are not corrupt
1.198 + //we need to read the single feature entries and the default
1.199 + //supported range before reconstructing the output buffer
1.200 + RArray<TFeatureEntry> singleArray;
1.201 + RArray<TFeatureRange> rangeArray;
1.202 + //process it in the reverse order as we read it as rom image with higher id will be mounted first
1.203 + for (TInt idx=fileCount-1;idx>=0;idx--)
1.204 + {
1.205 + const TFeatureHeader* header = reinterpret_cast<const TFeatureHeader*>(featregFileBufArray[idx].Ptr());
1.206 + const TFeatureEntry* entry=reinterpret_cast<const TFeatureEntry*>(header+1);
1.207 + const TFeatureRange* range=reinterpret_cast<const TFeatureRange*>(entry+header->iFeatureEntryCount);
1.208 + for (TInt s=0;s<header->iFeatureEntryCount;s++)
1.209 + {
1.210 + ret=singleArray.InsertInOrder(*(reinterpret_cast<const TFeatureEntry*>(entry+s)),TLinearOrder<TFeatureEntry>(CompareFeatureEntry));
1.211 + //ignore KErrAlreadyExists as we purposely do not want duplicate entries
1.212 + if (ret!=KErrNone && ret!=KErrAlreadyExists)
1.213 + {
1.214 + singleArray.Close();
1.215 + rangeArray.Close();
1.216 + ResetRBufArray(featregFileBufArray);
1.217 + return ret;
1.218 + }
1.219 + }
1.220 + //for range, we just insert them but ignore duplicate
1.221 + for (TInt r=0;r<header->iFeatureRangeCount;r++)
1.222 + {
1.223 + ret=rangeArray.InsertInOrder(*(reinterpret_cast<const TFeatureRange*>(range+r)),TLinearOrder<TFeatureRange>(CompareFeatureRange));
1.224 + if (ret!=KErrNone && ret!=KErrAlreadyExists)
1.225 + {
1.226 + singleArray.Close();
1.227 + rangeArray.Close();
1.228 + ResetRBufArray(featregFileBufArray);
1.229 + return ret;
1.230 + }
1.231 + }
1.232 + }
1.233 + //now the final step is to construct the aggregate RBuf
1.234 + RBuf8 buf8;
1.235 + TInt singleCount=singleArray.Count();
1.236 + TInt rangeCount=rangeArray.Count();
1.237 + ret=buf8.Create(sizeof(TFeatureHeader)+singleCount*sizeof(TFeatureEntry)+rangeCount*sizeof(TFeatureRange));
1.238 + if (ret==KErrNone)
1.239 + {
1.240 + TFeatureHeader header={validTypePrefix,0,singleCount,rangeCount};
1.241 + buf8.Append(reinterpret_cast<const TUint8*>(&header),sizeof(TFeatureHeader));
1.242 + for (TInt s=0;s<singleCount;s++)
1.243 + {
1.244 + buf8.Append(reinterpret_cast<const TUint8*>(&(singleArray[s])),sizeof(TFeatureEntry));
1.245 + }
1.246 + for (TInt r=0;r<rangeCount;r++)
1.247 + {
1.248 + buf8.Append(reinterpret_cast<const TUint8*>(&(rangeArray[r])),sizeof(TFeatureRange));
1.249 + }
1.250 + //transfer ownership now
1.251 + aBuf.Assign(buf8);
1.252 + }
1.253 + //perform cleanup
1.254 + singleArray.Close();
1.255 + rangeArray.Close();
1.256 + ResetRBufArray(featregFileBufArray);
1.257 + return ret;
1.258 + }
1.259 +
1.260 +
1.261 +/**
1.262 + * @return KErrNone (0) if successful, KErrNoMemory or KErrCorrupt if file read failed,
1.263 + * otherwise error result from calling RProperty::Define/Set
1.264 + */
1.265 +#ifndef FEATREGSETUPTEST
1.266 +TInt E32Main()
1.267 + {
1.268 + __UHEAP_MARK;
1.269 + CTrapCleanup* trapCleanup=CTrapCleanup::New();
1.270 + if (!trapCleanup)
1.271 + {
1.272 + return KErrNoMemory;
1.273 + }
1.274 +
1.275 + // if the following RProperty is defined, look for config file on the C: private
1.276 + // data cage instead of the normal Z:. Used for testing only.
1.277 + TInt testPropertyValue;
1.278 + TInt testResult = RProperty::Get(KFeaturePropCat, KFeatRegConfigTestKey, testPropertyValue);
1.279 + const TBool useCDataCage = testResult != KErrNotFound;
1.280 +
1.281 + RBuf8 featureBuf;
1.282 + RFs fs;
1.283 + TInt readResult = KErrNone;
1.284 + TInt publishResult = KErrNone;
1.285 + readResult = fs.Connect();
1.286 + if (readResult == KErrNone)
1.287 + {
1.288 + if (useCDataCage)
1.289 + {
1.290 + TConfigFileName filename;
1.291 + GetSystemDrivePath(filename);
1.292 + readResult = ReadFeatureFileToBuf(fs, filename, featureBuf);
1.293 + }
1.294 + else
1.295 + {
1.296 + readResult=ReadMultipleFeatureFileToBuf(fs,KFeatregRomPrivatePath,featureBuf);
1.297 + }
1.298 + fs.Close();
1.299 + }
1.300 +
1.301 + // lack of memory may be temporary, so end rather than publishing invalid property now
1.302 + if (readResult != KErrNoMemory)
1.303 + {
1.304 + RProcess thisProcess;
1.305 + // sanity check that feature property category in common header equals SID of this process
1.306 + ASSERT(KFeaturePropCat == thisProcess.SecureId());
1.307 + TSecurityPolicy readPolicy(TSecurityPolicy::EAlwaysPass);
1.308 + TSecurityPolicy writePolicy(thisProcess.SecureId());
1.309 + publishResult = RProperty::Define(KFeaturePropKey, RProperty::ELargeByteArray, readPolicy, writePolicy);
1.310 +
1.311 + if ((publishResult == KErrNone) || (publishResult == KErrAlreadyExists))
1.312 + {
1.313 + if (readResult == KErrNone)
1.314 + {
1.315 + publishResult = RProperty::Set(KFeaturePropCat, KFeaturePropKey, featureBuf);
1.316 + }
1.317 + else
1.318 + {
1.319 + // bad config file: set up invalid property with number of features/ranges not consistent
1.320 + // with size of property, so Feature Registry API always returns KErrCorrupt
1.321 + TFeatureHeader corruptHeader;
1.322 + corruptHeader.SetInvalid();
1.323 + TPckg<TFeatureHeader> corruptFeaturePckg(corruptHeader);
1.324 + publishResult = RProperty::Set(KFeaturePropCat, KFeaturePropKey, corruptFeaturePckg);
1.325 + }
1.326 + }
1.327 +
1.328 + if (readResult != KErrNone)
1.329 + {
1.330 + readResult = KErrCorrupt;
1.331 + // panic in debug mode alerts system integrators that config file is missing,
1.332 + // unreadable or invalid in this OS configuration: a serious problem
1.333 + __ASSERT_DEBUG(EFalse, Panic(EFeatRegBadConfig));
1.334 + }
1.335 + }
1.336 +
1.337 + featureBuf.Close();
1.338 + delete trapCleanup;
1.339 + __UHEAP_MARKEND;
1.340 + return (readResult != KErrNone) ? readResult : publishResult;
1.341 + }
1.342 +#endif