501 lines
14 KiB
C++
501 lines
14 KiB
C++
|
|
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
oemmint.h
|
|
|
|
Abstract:
|
|
|
|
Simple tool to create a Mini NT image
|
|
from a regular NT image
|
|
|
|
Author:
|
|
|
|
Vijay Jayaseelan (vijayj) Aug-08-2000
|
|
|
|
Revision History:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
#include <setupapi.hpp>
|
|
#include <queue.hpp>
|
|
#include <algorithm>
|
|
#include <list>
|
|
#include <tchar.h>
|
|
#include <strsafe.h>
|
|
|
|
#define ARRAY_SIZE(_X) (sizeof(_X)/sizeof((_X)[0]))
|
|
|
|
//
|
|
// Different types of SxS assembly layouts on the distribution
|
|
// media.
|
|
//
|
|
#define SXS_LAYOUT_TYPE_DIRECTORY 1
|
|
#define SXS_LAYOUT_TYPE_CAB 2
|
|
|
|
#define SXS_CAB_LAYOUT_BUILD_NUMBER 3606
|
|
|
|
//
|
|
// Invalid argument exception
|
|
//
|
|
struct InvalidArguments {};
|
|
|
|
//
|
|
// function prototypes
|
|
//
|
|
template <class T>
|
|
bool
|
|
CreateDirectories(
|
|
const std::basic_string<T> &DirName,
|
|
LPSECURITY_ATTRIBUTES SecurityAttrs
|
|
);
|
|
|
|
template <class T>
|
|
bool
|
|
IsFilePresent(
|
|
const std::basic_string<T> &FileName
|
|
);
|
|
|
|
//
|
|
// Argument cracker
|
|
//
|
|
template <class T>
|
|
struct Arguments {
|
|
std::basic_string<T> CurrentDirectory;
|
|
std::basic_string<T> LayoutName;
|
|
std::basic_string<T> DriverIndexName;
|
|
std::basic_string<T> SourceDirectoryRoot;
|
|
std::basic_string<T> SourceDirectory;
|
|
std::basic_string<T> DestinationDirectory;
|
|
std::basic_string<T> ExtraFileName;
|
|
std::basic_string<T> OptionalSrcDirectory;
|
|
std::basic_string<T> PlatformSuffix;
|
|
std::basic_string<T> DosNetFileName;
|
|
std::basic_string<T> ConfigInfFileName;
|
|
std::basic_string<T> IntlInfFileName;
|
|
std::basic_string<T> FontInfFileName;
|
|
bool Verbose;
|
|
bool WowFilesPresent;
|
|
bool SkipWowFiles;
|
|
bool SkipFileCopy;
|
|
bool CheckVersion;
|
|
bool IA64Image;
|
|
int WinSxSLayout;
|
|
DWORD MajorVersionNumber;
|
|
DWORD MinorVersionNumber;
|
|
DWORD MajorBuildNumber;
|
|
|
|
Arguments(int Argc, T *Argv[]);
|
|
|
|
|
|
friend std::ostream& operator<<(std::ostream &os,
|
|
const Arguments &rhs) {
|
|
|
|
os << rhs.SourceDirectory << ", "
|
|
<< rhs.DestinationDirectory << ", "
|
|
<< rhs.LayoutName << ", "
|
|
<< rhs.ExtraFileName << ", "
|
|
<< rhs.OptionalSrcDirectory << ", "
|
|
<< rhs.DriverIndexName << std::endl;
|
|
|
|
return os;
|
|
}
|
|
|
|
protected:
|
|
VOID IdentifySxSLayout( VOID );
|
|
};
|
|
|
|
|
|
//
|
|
// Argument Types
|
|
//
|
|
typedef Arguments<char> AnsiArgs;
|
|
typedef Arguments<wchar_t> UnicodeArgs;
|
|
|
|
//
|
|
// Driver Index File abstraction.
|
|
//
|
|
// This class helps in resolving a binary name to appropriate driver
|
|
// cab file (like SP1.CAB or DRIVER.CAB).
|
|
//
|
|
template <class T>
|
|
class DriverIndexInfFile : public InfFile<T> {
|
|
public:
|
|
//
|
|
// constructor
|
|
//
|
|
DriverIndexInfFile(const std::basic_string<T> &FileName) : InfFile<T>(FileName){
|
|
std::map<std::basic_string<T>, Section<T> *>::iterator Iter = Sections.find(CabsSectionName);
|
|
|
|
if (Iter == Sections.end()) {
|
|
throw new InvalidInfFile<T>(FileName);
|
|
}
|
|
|
|
CabsSection = (*Iter).second;
|
|
Iter = Sections.find(VersionSectionName);
|
|
|
|
if (Iter == Sections.end()) {
|
|
throw new InvalidInfFile<T>(FileName);
|
|
}
|
|
|
|
Section<T> *VersionSection = (*Iter).second;
|
|
SectionValues<T> &Values = VersionSection->GetValue(CabsSearchOrderKeyName);
|
|
|
|
for (int Index=0; Index < Values.Count(); Index++) {
|
|
if (sizeof(T) == sizeof(CHAR)) {
|
|
SearchList.push_back((T *)_strlwr((PSTR)Values.GetValue(Index).c_str()));
|
|
} else {
|
|
SearchList.push_back((T *)_wcslwr((PWSTR)Values.GetValue(Index).c_str()));
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Checks where the given is contained any of the driver cab files
|
|
//
|
|
bool IsFilePresent(const std::basic_string<T> &FileName){
|
|
return (GetCabFileName(FileName).length() > 0);
|
|
}
|
|
|
|
//
|
|
// Returns the driver cab file name which contains the given filename.
|
|
//
|
|
const std::basic_string<T>& GetCabFileName(const std::basic_string<T> &FileName) {
|
|
const static basic_string<T> NullCabFileName;
|
|
std::list<basic_string<T> >::iterator Iter;
|
|
|
|
for(Iter = SearchList.begin(); Iter != SearchList.end(); Iter++) {
|
|
std::map< std::basic_string<T>, Section<T> *>::iterator SectionIter = Sections.find(*Iter);
|
|
|
|
if (SectionIter != Sections.end()) {
|
|
Section<T> *CurrentSection = (*SectionIter).second;
|
|
|
|
if (CurrentSection->IsKeyPresent(FileName)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Iter != SearchList.end()) {
|
|
return CabsSection->GetValue(*Iter).GetValue(0);
|
|
}
|
|
|
|
return NullCabFileName;
|
|
}
|
|
|
|
protected:
|
|
//
|
|
// constant strings
|
|
//
|
|
const static std::basic_string<T> VersionSectionName;
|
|
const static std::basic_string<T> CabsSectionName;
|
|
const static std::basic_string<T> CabsSearchOrderKeyName;
|
|
|
|
//
|
|
// data members
|
|
//
|
|
std::list<std::basic_string<T> > SearchList; // the cab file list search order
|
|
Section<T> *CabsSection; // the [cabs] section of drvindex.inf
|
|
};
|
|
|
|
|
|
//
|
|
// File list creator functor object
|
|
//
|
|
template <class T>
|
|
struct FileListCreatorContext {
|
|
Arguments<T> &Args;
|
|
Section<T> *CurrentSection;
|
|
Section<T> *DirsSection;
|
|
bool SkipInfFiles;
|
|
ULONG FileCount;
|
|
bool ProcessingExtraFiles;
|
|
InfFile<T> &IntlInfFile;
|
|
InfFile<T> &FontInfFile;
|
|
InfFile<T> &ConfigInfFile;
|
|
ULONG DummyDirectoryId;
|
|
std::basic_string<T> WindowsDirectory;
|
|
std::basic_string<T> WinSxsCabinetFileName;
|
|
DriverIndexInfFile<T> &DriverIdxFile;
|
|
|
|
std::basic_string<T> CurrentCabFileIdx; // the cab being currently iterated on
|
|
std::basic_string<T> CurrentFileName; // the current file while iterating cab
|
|
|
|
std::map<std::basic_string<T>, std::basic_string<T> > FileList;
|
|
std::map<std::basic_string<T>, std::basic_string<T> > ExtraFileList;
|
|
std::map<std::basic_string<T>, std::basic_string<T> > DestDirs;
|
|
std::map<std::basic_string<T>, std::basic_string<T> > WinSxSFileList;
|
|
std::map<std::basic_string<T>, std::basic_string<T> > NlsFileMap;
|
|
std::map<std::basic_string<T>, std::basic_string<T> > NlsDirMap;
|
|
|
|
//
|
|
// Map of map i.e. map of cab filename to map of list of source to destination names
|
|
// which need to be extracted for cab file
|
|
//
|
|
std::map<std::basic_string<T>, std::map<std::basic_string<T>, std::basic_string<T> > * > CabFileListMap;
|
|
|
|
FileListCreatorContext(
|
|
Arguments<T> &PrgArgs,
|
|
Section<T> *Curr,
|
|
Section<T> *Dirs,
|
|
InfFile<T> &ConfigInf,
|
|
InfFile<T> &IntlInf,
|
|
InfFile<T> &FontInf,
|
|
DriverIndexInfFile<T> &DrvIdxFile
|
|
);
|
|
|
|
DWORD ProcessNlsFiles(VOID);
|
|
|
|
~FileListCreatorContext() {
|
|
std::map<std::basic_string<T>,
|
|
std::map<std::basic_string<T>, std::basic_string<T> > * >::iterator Iter;
|
|
|
|
for (Iter=CabFileListMap.begin(); Iter != CabFileListMap.end(); Iter++) {
|
|
delete (*Iter).second;
|
|
}
|
|
}
|
|
|
|
ULONG GetSourceCount() const {
|
|
ULONG Count = (FileList.size() + ExtraFileList.size() +
|
|
WinSxSFileList.size() + NlsFileMap.size());
|
|
|
|
std::map<std::basic_string<T>,
|
|
std::map<std::basic_string<T>, std::basic_string<T> > * >::iterator Iter;
|
|
|
|
for (Iter=CabFileListMap.begin(); Iter != CabFileListMap.end(); Iter++) {
|
|
Count += (*Iter).second->size();
|
|
}
|
|
|
|
return Count;
|
|
}
|
|
|
|
bool IsDriverCabFile(const std::basic_string<T> &FileName) {
|
|
return DriverIdxFile.IsFilePresent(FileName);
|
|
}
|
|
|
|
//
|
|
// Given the file name returns the cab file name (if any) which contains
|
|
// the file. In case of error "" (empty string) is returned.
|
|
//
|
|
const std::basic_string<T>& GetDriverCabFileName(const std::basic_string<T> &FileName) {
|
|
const std::basic_string<T> &CabFileName = DriverIdxFile.GetCabFileName(FileName);
|
|
|
|
// std::cout << "GetDriverCabFileName(" << FileName << ") = " << CabFileName << std::endl;
|
|
|
|
return CabFileName;
|
|
}
|
|
|
|
|
|
//
|
|
// Adds to the per cab file map the given source and destination file name that
|
|
// need to be extracted
|
|
//
|
|
void AddFileToCabFileList(const std::basic_string<T> &CabFileName,
|
|
const std::basic_string<T> &SourceFile,
|
|
const std::basic_string<T> &DestinationFile) {
|
|
//cout << "AddFileToCabFileList(" << CabFileName << ", " << SourceFile << ", " << DestinationFile << ")" << endl;
|
|
|
|
std::map<std::basic_string<T>,
|
|
std::map<std::basic_string<T>, std::basic_string<T> >* >::iterator Iter;
|
|
|
|
Iter = CabFileListMap.find(CabFileName);
|
|
|
|
std::map<std::basic_string<T>, std::basic_string<T> > *FileMap = NULL;
|
|
|
|
if (Iter != CabFileListMap.end()) {
|
|
FileMap = (*Iter).second;
|
|
} else {
|
|
//
|
|
// New cab file list
|
|
//
|
|
CabFileListMap[CabFileName] = FileMap = new std::map<std::basic_string<T>, std::basic_string<T> >();
|
|
}
|
|
|
|
(*FileMap)[SourceFile] = DestinationFile;
|
|
}
|
|
|
|
std::basic_string<T> GetNextDummyDirectoryId() {
|
|
T Buffer[MAX_PATH];
|
|
|
|
if (sizeof(T) == sizeof(CHAR)) {
|
|
(void)StringCchPrintfA((PSTR)Buffer, ARRAY_SIZE(Buffer), "%d", DummyDirectoryId);
|
|
} else {
|
|
(void)StringCchPrintfW((PWSTR)Buffer, ARRAY_SIZE(Buffer), L"%d", DummyDirectoryId);
|
|
}
|
|
|
|
DummyDirectoryId++;
|
|
|
|
return std::basic_string<T>((const T*)Buffer);
|
|
}
|
|
|
|
void AddDirectoryToNlsDirMap(const std::basic_string<T> &FileName) {
|
|
T Separator;
|
|
|
|
if (sizeof(T) == sizeof(CHAR)) {
|
|
Separator = (T)'\\';
|
|
} else {
|
|
Separator = (T)L'\\';
|
|
}
|
|
|
|
std::basic_string<T> DirectoryKey = FileName.substr(0, FileName.rfind(Separator));
|
|
|
|
if (DirectoryKey.length() && (NlsDirMap.find(DirectoryKey) == NlsDirMap.end())) {
|
|
NlsDirMap[DirectoryKey] = GetNextDummyDirectoryId();
|
|
}
|
|
}
|
|
|
|
void ProcessNlsDirMapEntries(void) {
|
|
std::map<std::basic_string<T>, std::basic_string<T> >::iterator Iter;
|
|
|
|
for (Iter = NlsDirMap.begin(); Iter != NlsDirMap.end(); Iter++) {
|
|
DestDirs[(*Iter).second] = (*Iter).first;
|
|
}
|
|
}
|
|
|
|
void RemoveDuplicateNlsEntries(void) {
|
|
std::map<std::basic_string<T>, std::basic_string<T> >::iterator NlsIter, PrevIter;
|
|
|
|
for (NlsIter = NlsFileMap.begin(); NlsIter != NlsFileMap.end(); ) {
|
|
PrevIter = NlsFileMap.end();
|
|
|
|
if (FileList.find((*NlsIter).first) != FileList.end()) {
|
|
PrevIter = NlsIter;
|
|
}
|
|
|
|
NlsIter++;
|
|
|
|
if (PrevIter != NlsFileMap.end()) {
|
|
// std::cout << "Erasing : " << (*PrevIter).first << std::endl;
|
|
NlsFileMap.erase(PrevIter);
|
|
}
|
|
}
|
|
}
|
|
|
|
void MoveDriverCabNlsFiles(void);
|
|
|
|
//
|
|
// static data members
|
|
//
|
|
static
|
|
UINT
|
|
NlsFileQueueScanWorker(
|
|
PVOID Context,
|
|
UINT Notification,
|
|
UINT_PTR Param1,
|
|
UINT_PTR Param2
|
|
);
|
|
};
|
|
|
|
|
|
//
|
|
// function prototypes
|
|
//
|
|
template <class T>
|
|
void
|
|
FileListCreator(
|
|
SectionValues<T> &Values,
|
|
PVOID Context
|
|
);
|
|
|
|
template <class T>
|
|
bool
|
|
IsWow64File(
|
|
SectionValues<T> &Values,
|
|
FileListCreatorContext<T> &Context
|
|
);
|
|
|
|
template <class T>
|
|
bool
|
|
IsFileSkipped(
|
|
SectionValues<T> &Values,
|
|
FileListCreatorContext<T> &Context
|
|
);
|
|
|
|
template <class T>
|
|
ULONG
|
|
CopyFileList(
|
|
FileListCreatorContext<T> &Context
|
|
);
|
|
|
|
template <class T>
|
|
ULONG
|
|
ProcessExtraFiles(
|
|
FileListCreatorContext<T> &Context
|
|
);
|
|
|
|
template <class T>
|
|
ULONG
|
|
ProcessWinSxSFiles(
|
|
IN FileListCreatorContext<T> &Context
|
|
);
|
|
|
|
template <class T>
|
|
ULONG
|
|
PreCreateDirs(
|
|
FileListCreatorContext<T> &Context
|
|
);
|
|
|
|
|
|
template <class T>
|
|
bool
|
|
ProcessInfChanges(
|
|
Arguments<T> &Args,
|
|
const std::basic_string<T> &InfName
|
|
);
|
|
|
|
template <class T>
|
|
bool
|
|
CheckMediaVersion(
|
|
Arguments<T> &Args
|
|
);
|
|
|
|
//
|
|
// utility function to tokenize a given line based on the delimiters
|
|
// specified
|
|
//
|
|
template< class T >
|
|
unsigned Tokenize(const T &szInput, const T & szDelimiters, std::vector<T>& tokens) {
|
|
unsigned DelimiterCount = 0;
|
|
|
|
tokens.clear();
|
|
|
|
if(!szInput.empty()){
|
|
if(!szDelimiters.empty()){
|
|
T::const_iterator inputIter = szInput.begin();
|
|
T::const_iterator copyIter = szInput.begin();
|
|
|
|
while(inputIter != szInput.end()){
|
|
if(szDelimiters.find(*inputIter) != string::npos){
|
|
if (copyIter < inputIter) {
|
|
tokens.push_back(szInput.substr(copyIter - szInput.begin(),
|
|
inputIter - copyIter));
|
|
}
|
|
|
|
DelimiterCount++;
|
|
inputIter++;
|
|
copyIter = inputIter;
|
|
|
|
continue;
|
|
}
|
|
|
|
inputIter++;
|
|
}
|
|
|
|
if(copyIter != inputIter){
|
|
tokens.push_back(szInput.substr(copyIter - szInput.begin(),
|
|
inputIter - szInput.begin()));
|
|
}
|
|
} else {
|
|
tokens.push_back(szInput);
|
|
}
|
|
}
|
|
|
|
return DelimiterCount;
|
|
}
|
|
|