2594 lines
88 KiB
C
2594 lines
88 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1995 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
mini.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module contains code that supports the installation and initialization
|
||
|
of a system's network adapter card under the MiniNT environment. Its functions
|
||
|
include changing the ComputerName to a randomly generated string, establishing
|
||
|
the system as being part of a local workgroup, and installing the necessary
|
||
|
drivers (via PnP) for the detected network adapter card. This functionality
|
||
|
relies upon the existence of WINBOM.INI and its following sections:
|
||
|
|
||
|
[Factory]
|
||
|
FactoryComputerName = ... ;Sets the first part of the random generated string to
|
||
|
;this value...if not present then prepends the random
|
||
|
;string with the value "MININT"
|
||
|
|
||
|
[NetCards]
|
||
|
PnPID=...\xyz.inf ;Scans the list of netcards/inf key value pairs and attempts
|
||
|
. ;to install drivers for the devices listed here BEFORE performing
|
||
|
. ;an exhaustive search of all the in-box drivers and attempting
|
||
|
. ;to locate the matching paramters for the enumerated hardware.
|
||
|
.
|
||
|
.
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Jason Lawrence (t-jasonl) - 8/11/2000
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
#include "factoryp.h"
|
||
|
#include <winioctl.h>
|
||
|
#include <spapip.h>
|
||
|
|
||
|
// Defines
|
||
|
#define CLOSEHANDLE(h) ( (h != NULL) ? (CloseHandle(h) ? ((h = NULL) == NULL) : (FALSE) ) : (FALSE) )
|
||
|
#define BUFSIZE 4096
|
||
|
#define NET_CONNECT_TIMEOUT 120 // seconds
|
||
|
|
||
|
|
||
|
// Various Structures used in this file
|
||
|
//
|
||
|
|
||
|
// ********************************************************************************************************************
|
||
|
// Sample entry into table for FILEINFO struct:
|
||
|
//
|
||
|
// { _T("<config>\\oobeinfo.ini"), _T("oobe\\oobeinfo.ini"), FALSE, TRUE }
|
||
|
//
|
||
|
// This means: Copy file oobeinfo.ini from <opkSourceRoot>\<config>\oobeinfo.ini to <opkTargetDrive>\oobe\oobeinfo.ini
|
||
|
// This is not a directory and is a required file.
|
||
|
//
|
||
|
// Variables allowed to be expanded: <sku>, <arch>, <lang>, <cfg>.
|
||
|
// ********************************************************************************************************************
|
||
|
|
||
|
typedef struct _FILEINFO
|
||
|
{
|
||
|
LPTSTR szFISourceName; // Source name. Relative to source root.
|
||
|
LPTSTR szFITargetName; // Relative to targetpath. If NULL the target drive root is assumed.
|
||
|
BOOL bDirectory; // Is filename a directory? If TRUE do a recursive copy.
|
||
|
BOOL bRequired; // TRUE - file is required. FALSE - file is optional.
|
||
|
|
||
|
} FILEINFO, *PFILEINFO, *LPFILEINFO;
|
||
|
|
||
|
// For the filesystem type
|
||
|
//
|
||
|
typedef enum _FSTYPES
|
||
|
{
|
||
|
fsNtfs,
|
||
|
fsFat32,
|
||
|
fsFat // for fat16/12
|
||
|
} FSTYPES;
|
||
|
|
||
|
// For partition types
|
||
|
//
|
||
|
typedef enum _PTTYPES
|
||
|
{
|
||
|
ptPrimary,
|
||
|
ptExtended,
|
||
|
ptLogical,
|
||
|
ptMsr,
|
||
|
ptEfi
|
||
|
} PTTYPES;
|
||
|
|
||
|
|
||
|
typedef struct _PARTITION
|
||
|
{
|
||
|
TCHAR cDriveLetter;
|
||
|
ULONGLONG ullSize;
|
||
|
UINT uiFileSystem; // NTFS or FAT32 or FAT
|
||
|
BOOL bQuickFormat;
|
||
|
UINT uiPartitionType; // Primary, extended, logical, msr, efi.
|
||
|
BOOL bSetActive;
|
||
|
UINT uiDiskID; // This is the disk number that this partition is on. 0-based
|
||
|
BOOL bWipeDisk; // TRUE if this disk needs to be wiped.
|
||
|
struct _PARTITION *pNext;
|
||
|
|
||
|
} *PPARTITION, PARTITION;
|
||
|
|
||
|
|
||
|
// Local functions
|
||
|
//
|
||
|
LPTSTR static mylstrcat( LPTSTR lpString1, LPCTSTR lpString2, DWORD dwSize );
|
||
|
BOOL static StartDiskpart( HANDLE*, HANDLE*, HANDLE*, HANDLE*);
|
||
|
BOOL static ProcessDiskConfigSection(LPTSTR lpszWinBOMPath);
|
||
|
BOOL static ProcessDisk(UINT diskID, LPTSTR lpSectionName, LPTSTR lpszWinBOMPath, BOOL bWipeDisk);
|
||
|
BOOL static Build(LPTSTR lpKey, DWORD dwSize, UINT diskID, LPCTSTR lpKeyName);
|
||
|
BOOL static FormatPartitions(VOID);
|
||
|
BOOL static JustFormatC(LPTSTR lpszWinBOMPath, LPTSTR lpszSectionBuffer);
|
||
|
BOOL static GetNumberOfPartitions(UINT uiDiskNumber, PDWORD numPartitions);
|
||
|
ULONGLONG static GetDiskSizeMB(UINT uiDiskNumber);
|
||
|
VOID static ListInsert(PPARTITION pAfterThis, PPARTITION pNew);
|
||
|
VOID static ListFree(PPARTITION pList);
|
||
|
VOID static AddMsrAndEfi(BOOL bMsr, BOOL bEfi, PPARTITION pLastLast, UINT uiDiskID, BOOL bWipeDisk);
|
||
|
|
||
|
//
|
||
|
// Default system policies for driver signing and non-driver signing
|
||
|
// for WinPE
|
||
|
//
|
||
|
#define DEFAULT_DRVSIGN_POLICY DRIVERSIGN_NONE
|
||
|
#define DEFAULT_NONDRVSIGN_POLICY DRIVERSIGN_NONE
|
||
|
|
||
|
VOID
|
||
|
pSetupGetRealSystemTime(
|
||
|
OUT LPSYSTEMTIME RealSystemTime
|
||
|
);
|
||
|
|
||
|
typedef enum _CODESIGNING_POLICY_TYPE {
|
||
|
PolicyTypeDriverSigning,
|
||
|
PolicyTypeNonDriverSigning
|
||
|
} CODESIGNING_POLICY_TYPE, *PCODESIGNING_POLICY_TYPE;
|
||
|
|
||
|
VOID
|
||
|
pSetCodeSigningPolicy(
|
||
|
IN CODESIGNING_POLICY_TYPE PolicyType,
|
||
|
IN BYTE NewPolicy,
|
||
|
OUT PBYTE OldPolicy OPTIONAL
|
||
|
);
|
||
|
|
||
|
|
||
|
//**********************************************************
|
||
|
// The formula for calculating the size of ESP partition is:
|
||
|
//
|
||
|
// MAX( 100 MB, MIN (1000 MB, DiskSize MB / 100 ) )
|
||
|
//
|
||
|
//**********************************************************
|
||
|
__inline
|
||
|
ULONGLONG
|
||
|
GetDiskEFISizeMB( UINT uiDiskNumber )
|
||
|
{
|
||
|
ULONGLONG DiskSizeMB = GetDiskSizeMB( uiDiskNumber );
|
||
|
return ( max( 100, min( 1000, DiskSizeMB / 100 ) ) );
|
||
|
}
|
||
|
|
||
|
//**********************************************************
|
||
|
// The formula for calculating the size of MSR partition is:
|
||
|
//
|
||
|
// IF ( Disk Size < 16 GB ) then MSR is 32 MB.
|
||
|
// ELSE MSR is 128 MB.
|
||
|
//
|
||
|
//**********************************************************
|
||
|
|
||
|
__inline
|
||
|
ULONGLONG
|
||
|
GetDiskMSRSizeMB( UINT uiDiskNumber )
|
||
|
{
|
||
|
ULONGLONG DiskSizeMB = GetDiskSizeMB( uiDiskNumber );
|
||
|
|
||
|
return ( ( ( DiskSizeMB / 1024 ) >= 16 ) ? 128 : 32 );
|
||
|
}
|
||
|
|
||
|
|
||
|
// Dialog Procs
|
||
|
//
|
||
|
INT_PTR CALLBACK ShutdownDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||
|
|
||
|
|
||
|
// Constant Strings
|
||
|
//
|
||
|
const static TCHAR DCDISK[] = _T("select disk ");
|
||
|
const static TCHAR DCPARTITION[] = _T("create partition ");
|
||
|
const static TCHAR DCSIZE[] = _T(" size=");
|
||
|
const static TCHAR DCASSIGNLETTER[] = _T("assign letter=");
|
||
|
const static TCHAR DCEXIT[] = _T("exit");
|
||
|
const static TCHAR DCNEWLINE[] = _T("\n");
|
||
|
const static TCHAR DCLISTPARTITION[] = _T("list partition");
|
||
|
const static TCHAR DCSELPARTITION[] = _T("select partition ");
|
||
|
const static TCHAR DCSETACTIVE[] = _T("active");
|
||
|
|
||
|
// This command will delete all the partitions on a disk.
|
||
|
//
|
||
|
const static TCHAR DCWIPEDISK[] = _T("clean");
|
||
|
const static TCHAR DCCONVERT_GPT[] = _T("convert gpt\nselect partition 1\ndelete partition override");
|
||
|
|
||
|
const static TCHAR DCPARTITION_PRIMARY[] = _T("primary");
|
||
|
const static TCHAR DCPARTITION_EXTENDED[] = _T("extended");
|
||
|
const static TCHAR DCPARTITION_LOGICAL[] = _T("logical");
|
||
|
const static TCHAR DCPARTITION_MSR[] = _T("msr");
|
||
|
const static TCHAR DCPARTITION_EFI[] = _T("efi");
|
||
|
|
||
|
const static TCHAR DCS_DISK_TYPE[] = _T("DiskType");
|
||
|
|
||
|
const static TCHAR DCS_FILE_SYSTEM[] = _T("FileSystem");
|
||
|
const static TCHAR DCS_QUICK_FORMAT[] = _T("QuickFormat");
|
||
|
const static TCHAR DCS_SIZE[] = _T("Size");
|
||
|
const static TCHAR DCS_PARTITION_TYPE[] = _T("PartitionType");
|
||
|
const static TCHAR DCS_PARTITION_ID[] = _T("PartitionID");
|
||
|
const static TCHAR DCS_SET_ACTIVE[] = _T("SetActive");
|
||
|
|
||
|
|
||
|
|
||
|
const static TCHAR c_szActiveComputerNameRegKey[] = L"System\\CurrentControlSet\\Control\\ComputerName\\ActiveComputerName";
|
||
|
const static TCHAR c_szComputerNameRegKey[] = L"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName";
|
||
|
|
||
|
static TCHAR g_szTargetDrive[] = _T("C:\\");
|
||
|
|
||
|
// Files to be copied.
|
||
|
// No leading or trailing backslashes.
|
||
|
//
|
||
|
static FILEINFO g_filesToCopy[] =
|
||
|
{
|
||
|
// SOURCE, TARGET, isDirectory, isRequired
|
||
|
//
|
||
|
{ _T("cfgsets\\<cfg>\\winbom.ini"), _T("sysprep\\winbom.ini"), FALSE, TRUE },
|
||
|
{ _T("cfgsets\\<cfg>\\unattend.txt"), _T("sysprep\\unattend.txt"), FALSE, TRUE },
|
||
|
{ _T("lang\\<lang>\\tools\\<arch>"), _T("sysprep"), TRUE, FALSE },
|
||
|
{ _T("lang\\<lang>\\sku\\<sku>\\<arch>"), _T(""), TRUE, TRUE }
|
||
|
};
|
||
|
|
||
|
// Linked list to hold partition information.
|
||
|
//
|
||
|
static PPARTITION g_PartList = NULL;
|
||
|
|
||
|
// External variables
|
||
|
//
|
||
|
extern HINSTANCE g_hInstance;
|
||
|
|
||
|
|
||
|
// External functions
|
||
|
//
|
||
|
typedef VOID (WINAPI *ExternalGenerateName)
|
||
|
(
|
||
|
PWSTR GeneratedString,
|
||
|
DWORD DesiredStrLen
|
||
|
);
|
||
|
|
||
|
|
||
|
|
||
|
/*++
|
||
|
===============================================================================
|
||
|
Routine Description:
|
||
|
|
||
|
BOOL SetupMiniNT
|
||
|
|
||
|
This routine serves as the main entry point for initializing the netcard
|
||
|
under MiniNT. Also performs the tasks of changing the computer name
|
||
|
and establishing the computer as part of a local workgroup. Called from
|
||
|
factory!WinMain.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE if netcard was correctly installed
|
||
|
FALSE if there was an error
|
||
|
|
||
|
===============================================================================
|
||
|
--*/
|
||
|
BOOL
|
||
|
SetupMiniNT(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
BOOL bInstallNIC;
|
||
|
BOOL bRet = TRUE;
|
||
|
WCHAR szRequestedComputerName[100];
|
||
|
WCHAR szComputerName[100];
|
||
|
WCHAR szGeneratedName[100];
|
||
|
PWSTR AppendStr = NULL;
|
||
|
|
||
|
// for syssetup.dll GenerateName
|
||
|
HINSTANCE hInstSysSetup = NULL;
|
||
|
ExternalGenerateName pGenerateName = NULL;
|
||
|
|
||
|
HKEY hActiveComputerNameKey;
|
||
|
HKEY hComputerNameKey;
|
||
|
BOOL RemoteBoot = IsRemoteBoot();
|
||
|
extern FACTMODE g_fm;
|
||
|
|
||
|
LPTSTR lpszAdmin = NULL;
|
||
|
LPTSTR lpszWorkgroup = NULL;
|
||
|
|
||
|
//
|
||
|
// Reset the driver signing policy in WinPE
|
||
|
//
|
||
|
pSetCodeSigningPolicy(PolicyTypeDriverSigning,
|
||
|
DEFAULT_DRVSIGN_POLICY,
|
||
|
NULL);
|
||
|
|
||
|
pSetCodeSigningPolicy(PolicyTypeNonDriverSigning,
|
||
|
DEFAULT_NONDRVSIGN_POLICY,
|
||
|
NULL);
|
||
|
|
||
|
if (!RemoteBoot) {
|
||
|
// set random computer name
|
||
|
hInstSysSetup = LoadLibrary(L"syssetup.dll");
|
||
|
if (hInstSysSetup == NULL)
|
||
|
{
|
||
|
FacLogFileStr(0 | LOG_ERR | LOG_MSG_BOX, L"Failed to load syssetup.dll");
|
||
|
bRet = FALSE;
|
||
|
goto Clean;
|
||
|
}
|
||
|
|
||
|
pGenerateName = (ExternalGenerateName)GetProcAddress(hInstSysSetup,
|
||
|
"GenerateName");
|
||
|
if (pGenerateName == NULL)
|
||
|
{
|
||
|
FacLogFileStr(0 | LOG_ERR | LOG_MSG_BOX, L"Failed to obtain address of GenerateName");
|
||
|
bRet = FALSE;
|
||
|
goto Clean;
|
||
|
}
|
||
|
|
||
|
// call GenerateName
|
||
|
pGenerateName(szGeneratedName, 15);
|
||
|
|
||
|
// obtain factory computer name from winbom.ini...default to MININT
|
||
|
GetPrivateProfileString(L"Factory",
|
||
|
L"FactoryComputerName",
|
||
|
L"MININT",
|
||
|
szRequestedComputerName,
|
||
|
sizeof(szRequestedComputerName)/sizeof(TCHAR),
|
||
|
g_szWinBOMPath);
|
||
|
|
||
|
lstrcpyn (szComputerName, szRequestedComputerName, AS ( szComputerName ) );
|
||
|
AppendStr = wcsstr(szGeneratedName, L"-");
|
||
|
|
||
|
// ISSUE-2002/02/27-acosma,georgeje - The size of the computername we generate
|
||
|
// is not guaranteed to be less than MAX_COMPUTERNAME length.
|
||
|
//
|
||
|
|
||
|
if ( AppendStr )
|
||
|
{
|
||
|
if ( FAILED ( StringCchCat ( szComputerName, AS ( szComputerName ), AppendStr) ) )
|
||
|
{
|
||
|
FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), szComputerName, AppendStr ) ;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// now set the computer name
|
||
|
if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||
|
c_szActiveComputerNameRegKey,
|
||
|
0,
|
||
|
KEY_SET_VALUE,
|
||
|
&hActiveComputerNameKey))
|
||
|
{
|
||
|
FacLogFileStr(0 | LOG_ERR | LOG_MSG_BOX, L"Failed to open ActiveComputerName.");
|
||
|
bRet = FALSE;
|
||
|
goto Clean;
|
||
|
}
|
||
|
|
||
|
if ( ERROR_SUCCESS != RegSetValueEx(hActiveComputerNameKey,
|
||
|
L"ComputerName",
|
||
|
0,
|
||
|
REG_SZ,
|
||
|
(LPBYTE)szComputerName,
|
||
|
(lstrlen(szComputerName)+1) * sizeof(WCHAR)) )
|
||
|
{
|
||
|
FacLogFileStr(0 | LOG_ERR | LOG_MSG_BOX, L"Failed to set ActiveComputerName.");
|
||
|
bRet = FALSE;
|
||
|
goto Clean;
|
||
|
}
|
||
|
|
||
|
RegCloseKey(hActiveComputerNameKey);
|
||
|
|
||
|
if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||
|
c_szComputerNameRegKey,
|
||
|
0,
|
||
|
KEY_SET_VALUE,
|
||
|
&hComputerNameKey))
|
||
|
{
|
||
|
FacLogFileStr(0 | LOG_ERR | LOG_MSG_BOX, L"Failed to open ComputerName.");
|
||
|
bRet = FALSE;
|
||
|
goto Clean;
|
||
|
}
|
||
|
|
||
|
if ( ERROR_SUCCESS != RegSetValueEx(hComputerNameKey,
|
||
|
L"ComputerName",
|
||
|
0,
|
||
|
REG_SZ,
|
||
|
(LPBYTE)szComputerName,
|
||
|
(lstrlen(szComputerName)+1) * sizeof(WCHAR)) )
|
||
|
{
|
||
|
FacLogFileStr(0 | LOG_ERR | LOG_MSG_BOX, L"Failed to set ComputerName.");
|
||
|
bRet = FALSE;
|
||
|
goto Clean;
|
||
|
}
|
||
|
|
||
|
RegCloseKey(hComputerNameKey);
|
||
|
lpszAdmin = AllocateString(NULL, IDS_ADMIN);
|
||
|
|
||
|
if(lpszAdmin == NULL) {
|
||
|
bRet = FALSE;
|
||
|
goto Clean;
|
||
|
}
|
||
|
|
||
|
lpszWorkgroup = AllocateString(NULL, IDS_WORKGROUP);
|
||
|
|
||
|
if(lpszWorkgroup == NULL) {
|
||
|
bRet = FALSE;
|
||
|
goto Clean;
|
||
|
}
|
||
|
|
||
|
// establish this computer as part of a workgroup
|
||
|
NetJoinDomain(NULL,
|
||
|
lpszWorkgroup,
|
||
|
NULL,
|
||
|
lpszAdmin,
|
||
|
NULL,
|
||
|
0);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Install nic and always if we fail to install the netcard from the [NetCards] section
|
||
|
// do a full scan.
|
||
|
//
|
||
|
if (!(bInstallNIC = InstallNetworkCard(g_szWinBOMPath, FALSE)))
|
||
|
{
|
||
|
if (!(bInstallNIC = InstallNetworkCard(g_szWinBOMPath, TRUE)))
|
||
|
{
|
||
|
bRet = FALSE;
|
||
|
goto Clean;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Clean:
|
||
|
if (hInstSysSetup != NULL)
|
||
|
{
|
||
|
FreeLibrary(hInstSysSetup);
|
||
|
}
|
||
|
|
||
|
FREE(lpszAdmin);
|
||
|
FREE(lpszWorkgroup);
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*++
|
||
|
===============================================================================
|
||
|
Routine Description:
|
||
|
|
||
|
BOOL PartitionFormat(LPSTATEDATA lpStateData)
|
||
|
|
||
|
This routine will partition and format the C drive of the target machine.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
lpStateData->lpszWinBOMPath
|
||
|
- Buffer containing the fully qualified path to the WINBOM
|
||
|
file
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE if no errors were encountered
|
||
|
FALSE if there was an error
|
||
|
|
||
|
===============================================================================
|
||
|
--*/
|
||
|
|
||
|
BOOL PartitionFormat(LPSTATEDATA lpStateData)
|
||
|
{
|
||
|
LPTSTR lpszWinBOMPath = lpStateData->lpszWinBOMPath;
|
||
|
BOOL bPartition = FALSE;
|
||
|
BOOL bForceFormat = FALSE;
|
||
|
BOOL bRet = TRUE;
|
||
|
|
||
|
// Stuff for partitioning.
|
||
|
//
|
||
|
HANDLE hStdinRd = NULL,
|
||
|
hStdinWrDup = NULL,
|
||
|
hStdoutWr = NULL,
|
||
|
hStdoutRdDup = NULL;
|
||
|
|
||
|
DWORD dwRead = 0;
|
||
|
LPTSTR lpszBuf = NULL;
|
||
|
DWORD dwWritten = 0;
|
||
|
DWORD dwToWrite = 0;
|
||
|
TCHAR szCommand[BUFSIZE] = NULLSTR;
|
||
|
CHAR szCommandA[BUFSIZE] = {0};
|
||
|
DWORD dwLogicalDrives = 0;
|
||
|
TCHAR cDriveLetter = _T('D');
|
||
|
|
||
|
#ifdef DBG
|
||
|
HANDLE hDebugFile = NULL;
|
||
|
#endif
|
||
|
|
||
|
DWORD nPartitions = 0;
|
||
|
|
||
|
LPTSTR lpCommand = szCommand;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Partition and Format drives.
|
||
|
//
|
||
|
*szCommand = NULLCHR;
|
||
|
|
||
|
// Get the logical drives in existence
|
||
|
//
|
||
|
dwLogicalDrives = GetLogicalDrives();
|
||
|
|
||
|
|
||
|
// Read from the WinBOM to set partitioning parameters and
|
||
|
// Start Diskpart with redirected input and output.
|
||
|
//
|
||
|
if ( ProcessDiskConfigSection(lpszWinBOMPath) &&
|
||
|
StartDiskpart(&hStdinWrDup, &hStdoutRdDup, &hStdinRd, &hStdoutWr) )
|
||
|
{
|
||
|
UINT dwLastDiskN = UINT_MAX;
|
||
|
PPARTITION pCur;
|
||
|
UINT i = 1; // Partition number on disk.
|
||
|
TCHAR szBuf[MAX_WINPE_PROFILE_STRING] = NULLSTR;
|
||
|
|
||
|
//
|
||
|
// This call is to initialize the length for mystrcat function.
|
||
|
//
|
||
|
mylstrcat(lpCommand, NULLSTR, AS ( szCommand ) );
|
||
|
|
||
|
// First go through all the disks and clean them if specified in the
|
||
|
// respective nodes.
|
||
|
//
|
||
|
for (pCur = g_PartList; pCur; pCur = pCur->pNext )
|
||
|
{
|
||
|
// Only do this stuff if we're working with a new disk number.
|
||
|
//
|
||
|
if ( (dwLastDiskN != pCur->uiDiskID) && (pCur->bWipeDisk) )
|
||
|
{
|
||
|
_itow(pCur->uiDiskID, szBuf, 10);
|
||
|
lpCommand = mylstrcat(lpCommand, DCDISK, 0 );
|
||
|
lpCommand = mylstrcat(lpCommand, szBuf, 0 );
|
||
|
lpCommand = mylstrcat(lpCommand, DCNEWLINE,0 );
|
||
|
|
||
|
lpCommand = mylstrcat(lpCommand, DCWIPEDISK, 0 );
|
||
|
lpCommand = mylstrcat(lpCommand, DCNEWLINE, 0 );
|
||
|
|
||
|
// Set the last disk to the current disk.
|
||
|
//
|
||
|
dwLastDiskN = pCur->uiDiskID;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Initialize this again for the next loop.
|
||
|
//
|
||
|
dwLastDiskN = UINT_MAX;
|
||
|
|
||
|
for (pCur = g_PartList; pCur; pCur = pCur->pNext )
|
||
|
{
|
||
|
TCHAR szDriveLetter[2];
|
||
|
|
||
|
// Only do this stuff if we're working with a new disk number.
|
||
|
//
|
||
|
if ( dwLastDiskN != pCur->uiDiskID )
|
||
|
{
|
||
|
_itow(pCur->uiDiskID, szBuf, 10);
|
||
|
lpCommand = mylstrcat(lpCommand, DCDISK, 0 );
|
||
|
lpCommand = mylstrcat(lpCommand, szBuf, 0 );
|
||
|
lpCommand = mylstrcat(lpCommand, DCNEWLINE, 0 );
|
||
|
|
||
|
if ( pCur->bWipeDisk && GET_FLAG(g_dwFactoryFlags, FLAG_IA64_MODE) )
|
||
|
{
|
||
|
lpCommand = mylstrcat(lpCommand, DCCONVERT_GPT, 0 );
|
||
|
lpCommand = mylstrcat(lpCommand, DCNEWLINE, 0 );
|
||
|
}
|
||
|
|
||
|
// Set the last disk to the current disk.
|
||
|
//
|
||
|
dwLastDiskN = pCur->uiDiskID;
|
||
|
|
||
|
// Reset the partition number on the disk to 1.
|
||
|
//
|
||
|
i = 1;
|
||
|
}
|
||
|
|
||
|
// Partition type (primary|extended|logical|efi|msr)
|
||
|
//
|
||
|
lpCommand = mylstrcat(lpCommand, DCPARTITION, 0 );
|
||
|
|
||
|
if ( ptPrimary == pCur->uiPartitionType )
|
||
|
lpCommand = mylstrcat(lpCommand, DCPARTITION_PRIMARY, 0 );
|
||
|
else if ( ptExtended == pCur->uiPartitionType )
|
||
|
lpCommand = mylstrcat(lpCommand, DCPARTITION_EXTENDED, 0 );
|
||
|
else if ( ptEfi == pCur->uiPartitionType )
|
||
|
lpCommand = mylstrcat(lpCommand, DCPARTITION_EFI, 0 );
|
||
|
else if ( ptMsr == pCur->uiPartitionType )
|
||
|
lpCommand = mylstrcat(lpCommand, DCPARTITION_MSR, 0 );
|
||
|
else
|
||
|
lpCommand = mylstrcat(lpCommand, DCPARTITION_LOGICAL, 0 );
|
||
|
|
||
|
// Size of partition.
|
||
|
//
|
||
|
if ( 0 != pCur->ullSize )
|
||
|
{
|
||
|
*szBuf = NULLCHR;
|
||
|
_i64tow(pCur->ullSize, szBuf, 10);
|
||
|
lpCommand = mylstrcat(lpCommand, DCSIZE, 0);
|
||
|
lpCommand = mylstrcat(lpCommand, szBuf, 0);
|
||
|
}
|
||
|
|
||
|
lpCommand = mylstrcat(lpCommand, DCNEWLINE, 0);
|
||
|
|
||
|
if ( ptExtended != pCur->uiPartitionType && ptMsr != pCur->uiPartitionType )
|
||
|
{
|
||
|
*szBuf = NULLCHR;
|
||
|
_itow(i, szBuf, 10);
|
||
|
|
||
|
lpCommand = mylstrcat(lpCommand, DCSELPARTITION, 0 );
|
||
|
lpCommand = mylstrcat(lpCommand, szBuf, 0 );
|
||
|
lpCommand = mylstrcat(lpCommand, DCNEWLINE, 0);
|
||
|
|
||
|
while ((dwLogicalDrives & ( (DWORD) 0x01 << (cDriveLetter - _T('A')))))
|
||
|
cDriveLetter++;
|
||
|
|
||
|
if (cDriveLetter > _T('Z'))
|
||
|
{
|
||
|
// Ran out of drive letters. Get out of here.
|
||
|
FacLogFile(0 | LOG_ERR, IDS_ERR_OUTOFDRIVELETTERS);
|
||
|
bRet = FALSE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ( pCur->bSetActive && (0 == pCur->uiDiskID) )
|
||
|
{
|
||
|
pCur->cDriveLetter = _T('C');
|
||
|
lstrcpyn( szDriveLetter, _T("C"), AS ( szDriveLetter ) );
|
||
|
g_szTargetDrive[0] = pCur->cDriveLetter;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Assign the new drive letter to this drive.
|
||
|
//
|
||
|
pCur->cDriveLetter = cDriveLetter;
|
||
|
szDriveLetter[0] = cDriveLetter;
|
||
|
szDriveLetter[1] = NULLCHR;
|
||
|
cDriveLetter++;
|
||
|
}
|
||
|
|
||
|
lpCommand = mylstrcat(lpCommand, DCASSIGNLETTER, 0 );
|
||
|
lpCommand = mylstrcat(lpCommand, szDriveLetter, 0 );
|
||
|
lpCommand = mylstrcat(lpCommand, DCNEWLINE, 0 );
|
||
|
|
||
|
// If this is the partition that we want to set active, make this
|
||
|
// the partition where we install the OS. Only allow the TargetDrive
|
||
|
// on a partition on disk 0.
|
||
|
//
|
||
|
if ( pCur->bSetActive && !GET_FLAG(g_dwFactoryFlags, FLAG_IA64_MODE) )
|
||
|
{
|
||
|
lpCommand = mylstrcat(lpCommand, DCSETACTIVE, 0 );
|
||
|
lpCommand = mylstrcat(lpCommand, DCNEWLINE, 0 );
|
||
|
}
|
||
|
}
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
if (bRet)
|
||
|
{
|
||
|
lpCommand = mylstrcat(lpCommand, DCEXIT, 0 );
|
||
|
lpCommand = mylstrcat(lpCommand, DCNEWLINE, 0 );
|
||
|
|
||
|
// Some debugging output here.
|
||
|
//
|
||
|
FacLogFileStr(3, szCommand);
|
||
|
|
||
|
// Convert UNICODE string to ANSI string.
|
||
|
//
|
||
|
if ((dwToWrite = WideCharToMultiByte(
|
||
|
CP_ACP,
|
||
|
0,
|
||
|
szCommand,
|
||
|
-1,
|
||
|
szCommandA,
|
||
|
sizeof(szCommandA),
|
||
|
NULL,
|
||
|
NULL
|
||
|
)))
|
||
|
{
|
||
|
// Write to pipe that is the standard input for the child process.
|
||
|
//
|
||
|
if (! WriteFile(hStdinWrDup, szCommandA, dwToWrite,
|
||
|
&dwWritten, NULL))
|
||
|
{
|
||
|
FacLogFile(0 | LOG_ERR, IDS_ERR_WRITEPIPE);
|
||
|
bRet = FALSE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
bRet = FALSE;
|
||
|
}
|
||
|
// Close the pipe handle so the child process stops reading.
|
||
|
//
|
||
|
CLOSEHANDLE(hStdinWrDup);
|
||
|
|
||
|
// Read from pipe that is the standard output for child process.
|
||
|
//
|
||
|
dwWritten = 0;
|
||
|
|
||
|
// Close the write end of the pipe before reading from the
|
||
|
// read end of the pipe.
|
||
|
//
|
||
|
CLOSEHANDLE(hStdoutWr);
|
||
|
|
||
|
// Read output from the child process, and write to parent's STDOUT.
|
||
|
//
|
||
|
#ifdef DBG
|
||
|
hDebugFile = CreateFile(_T("diskpart.txt"), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||
|
#endif
|
||
|
|
||
|
// Allocate the buffer we will read from...
|
||
|
//
|
||
|
lpszBuf = MALLOC(BUFSIZE * sizeof(TCHAR));
|
||
|
if ( lpszBuf )
|
||
|
{
|
||
|
for (;;)
|
||
|
{
|
||
|
if( !ReadFile( hStdoutRdDup, lpszBuf, BUFSIZE, &dwRead,
|
||
|
NULL) || dwRead == 0) break;
|
||
|
|
||
|
#ifdef DBG
|
||
|
if (hDebugFile != INVALID_HANDLE_VALUE)
|
||
|
if (! WriteFile(hDebugFile, lpszBuf, dwRead, &dwWritten, NULL))
|
||
|
break;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
// Free the buffer we used for reading
|
||
|
//
|
||
|
FREE( lpszBuf );
|
||
|
}
|
||
|
|
||
|
#ifdef DBG
|
||
|
CLOSEHANDLE(hDebugFile);
|
||
|
#endif
|
||
|
} else
|
||
|
bRet = FALSE;
|
||
|
|
||
|
|
||
|
// Format partitions.
|
||
|
//
|
||
|
if ( bRet )
|
||
|
{
|
||
|
TCHAR szDirectory[MAX_PATH] = NULLSTR;
|
||
|
|
||
|
if ( GetSystemDirectory(szDirectory, MAX_PATH) )
|
||
|
SetCurrentDirectory(szDirectory);
|
||
|
|
||
|
// Go through the array of partitions in g_PartTable and format all the partitions that
|
||
|
// were just created (except for extended type partitions).
|
||
|
//
|
||
|
if (!FormatPartitions())
|
||
|
bRet = FALSE;
|
||
|
} // if (bRet)
|
||
|
|
||
|
|
||
|
|
||
|
// Now let's try to enable logging again if it is disabled, since we have
|
||
|
// new writable drives.
|
||
|
//
|
||
|
if (bRet && !g_szLogFile[0])
|
||
|
InitLogging(lpszWinBOMPath);
|
||
|
|
||
|
// Clean-up
|
||
|
//
|
||
|
FacLogFileStr(3, _T("Cleaning up PartitionFormat()\n"));
|
||
|
|
||
|
// Delete the linked list of partition info.
|
||
|
//
|
||
|
ListFree(g_PartList);
|
||
|
|
||
|
// Make sure that all the handles are closed.
|
||
|
//
|
||
|
CLOSEHANDLE(hStdoutRdDup);
|
||
|
CLOSEHANDLE(hStdinRd);
|
||
|
CLOSEHANDLE(hStdinWrDup);
|
||
|
CLOSEHANDLE(hStdoutWr);
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
BOOL DisplayPartitionFormat(LPSTATEDATA lpStateData)
|
||
|
{
|
||
|
return IniSettingExists(lpStateData->lpszWinBOMPath, INI_SEC_WBOM_DISKCONFIG, NULL, NULL);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*++
|
||
|
===============================================================================
|
||
|
Routine Description:
|
||
|
|
||
|
BOOL ExpandStrings(LPCTSTR szSource, LPTSTR szDest, UINT nSize)
|
||
|
|
||
|
This is a helper routine for CopyFiles() to expand replaceable strings with
|
||
|
user defined strings from the WinBOM.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
szSource - Buffer containing string with replaceable parameters.
|
||
|
szDest - Buffer where expanded string will be written to.
|
||
|
nSize - Size of the szDest string.
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE if no errors were encountered
|
||
|
FALSE if there was an error
|
||
|
|
||
|
Remarks:
|
||
|
|
||
|
Function assumes that the env (environment) table has been prepopulated.
|
||
|
The function will fail if the size of the expanded string exceeds nSize.
|
||
|
===============================================================================
|
||
|
--*/
|
||
|
BOOL ExpandStrings(LPCTSTR szSource, LPTSTR szDest, UINT nSize, LPTSTR *env, UINT uiEnvSize)
|
||
|
{
|
||
|
|
||
|
UINT uiDestLength = 0; // in TCHAR's
|
||
|
UINT j = 0; // just a counter to go through the environment table
|
||
|
UINT uiVarNameLength = 0; // in TCHAR's
|
||
|
UINT uiVarLength = 0;
|
||
|
TCHAR szVar[MAX_PATH] = NULLSTR;
|
||
|
LPTSTR pVarValue = NULL;
|
||
|
LPTSTR pSrc;
|
||
|
|
||
|
pSrc = (LPTSTR) szSource;
|
||
|
|
||
|
while (*pSrc != NULLCHR)
|
||
|
{
|
||
|
if (*pSrc == '<')
|
||
|
{
|
||
|
//
|
||
|
// Now we're looking at a variable that must be replaced.
|
||
|
//
|
||
|
|
||
|
// Go to first char in var name.
|
||
|
pSrc = CharNext(pSrc);
|
||
|
uiVarNameLength = 0;
|
||
|
|
||
|
while (*pSrc != '>')
|
||
|
{
|
||
|
szVar[uiVarNameLength++] = *pSrc;
|
||
|
if ( *(pSrc = CharNext(pSrc)) == NULLCHR)
|
||
|
{
|
||
|
// Terminate the szVar string with NULL
|
||
|
szVar[uiVarNameLength] = NULLCHR;
|
||
|
FacLogFileStr(3, _T("Illegal syntax. Cannot find closing '>' for variable: %s"), szVar);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// Skip the closing '>'.
|
||
|
//
|
||
|
pSrc = CharNext(pSrc);
|
||
|
|
||
|
// Add the terminating NULL character to the szVar.
|
||
|
//
|
||
|
szVar[uiVarNameLength] = NULLCHR;
|
||
|
|
||
|
pVarValue = NULL;
|
||
|
// Find the value for this variable in the environment table.
|
||
|
//
|
||
|
for (j = 0; j < uiEnvSize; j += 2)
|
||
|
if (!lstrcmpi(szVar, env[j]))
|
||
|
{
|
||
|
pVarValue = env[j + 1];
|
||
|
break;
|
||
|
}
|
||
|
// If the Variable was not found return FALSE.
|
||
|
//
|
||
|
if (!pVarValue)
|
||
|
{
|
||
|
FacLogFileStr(3, _T("Variable not found: %s\n"), szVar);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// Now copy the variable value to the target string.
|
||
|
//
|
||
|
uiVarLength = lstrlen(pVarValue);
|
||
|
if ((uiDestLength + uiVarLength) < nSize)
|
||
|
{
|
||
|
lstrcpyn(&szDest[uiDestLength], pVarValue, AS ( szDest ) - uiDestLength);
|
||
|
uiDestLength += uiVarLength;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// szDest buffer size exceeded.
|
||
|
//
|
||
|
FacLogFileStr(3, _T("Destination buffer size exceeded while expanding strings\n"));
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
}
|
||
|
else // If *pSrc is a regular character copy it to the target buffer.
|
||
|
{
|
||
|
if (uiDestLength < nSize - 1)
|
||
|
{
|
||
|
szDest[uiDestLength++] = *pSrc;
|
||
|
pSrc = CharNext(pSrc);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// szDest buffer size exceeded.
|
||
|
//
|
||
|
FacLogFileStr(3, _T("Destination buffer size exceeded while expanding strings\n"));
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// Terminate the destination buffer with NULL character.
|
||
|
//
|
||
|
szDest[uiDestLength] = NULLCHR;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*++
|
||
|
===============================================================================
|
||
|
Routine Description:
|
||
|
|
||
|
BOOL CopyFiles(LPSTATEDATA lpStateData)
|
||
|
|
||
|
This routine will copy the necessary configuration files to a machine and
|
||
|
start setup of Whistler.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
lpStateData->lpszWinBOMPath
|
||
|
- Buffer containing the fully qualified path to the WINBOM
|
||
|
file
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE if no errors were encountered
|
||
|
FALSE if there was an error
|
||
|
|
||
|
Remarks:
|
||
|
|
||
|
|
||
|
===============================================================================
|
||
|
--*/
|
||
|
|
||
|
BOOL CopyFiles(LPSTATEDATA lpStateData)
|
||
|
{
|
||
|
LPTSTR lpszWinBOMPath = lpStateData->lpszWinBOMPath;
|
||
|
|
||
|
// All variables that are expanded from the pathnames are given here.
|
||
|
//
|
||
|
// Leading or trailing backslashes are not allowed in the WinBOM for these VARS.
|
||
|
//
|
||
|
|
||
|
|
||
|
TCHAR szSku[MAX_WINPE_PROFILE_STRING] = NULLSTR;
|
||
|
TCHAR szLang[MAX_WINPE_PROFILE_STRING] = NULLSTR;
|
||
|
TCHAR szArch[MAX_WINPE_PROFILE_STRING] = NULLSTR;
|
||
|
TCHAR szCfg[MAX_WINPE_PROFILE_STRING] = NULLSTR;
|
||
|
TCHAR szOpkSrcRoot[MAX_WINPE_PROFILE_STRING] = NULLSTR;
|
||
|
TCHAR szOptSources[MAX_WINPE_PROFILE_STRING] = NULLSTR;
|
||
|
|
||
|
|
||
|
// Username, password and domain name used to login if a UNC path is specified for szOpkSrcRoot.
|
||
|
//
|
||
|
TCHAR szUsername[MAX_WINPE_PROFILE_STRING] = NULLSTR;
|
||
|
TCHAR szPassword[MAX_WINPE_PROFILE_STRING] = NULLSTR;
|
||
|
TCHAR szDomain[MAX_WINPE_PROFILE_STRING] = NULLSTR;
|
||
|
|
||
|
LPTSTR env[] =
|
||
|
{
|
||
|
_T("sku"), szSku,
|
||
|
_T("lang"), szLang,
|
||
|
_T("arch"), szArch,
|
||
|
_T("cfg"), szCfg
|
||
|
};
|
||
|
|
||
|
UINT i = 0;
|
||
|
TCHAR szSource[MAX_PATH] = NULLSTR;
|
||
|
TCHAR szTarget[MAX_PATH] = NULLSTR;
|
||
|
TCHAR szBuffer[MAX_PATH] = NULLSTR;
|
||
|
BOOL bRet = TRUE;
|
||
|
UINT uiLength = 0;
|
||
|
|
||
|
//
|
||
|
// Set up the globals.
|
||
|
//
|
||
|
|
||
|
// Read from WinBOM.
|
||
|
//
|
||
|
GetPrivateProfileString(WBOM_WINPE_SECTION, INI_KEY_WBOM_WINPE_LANG, NULLSTR, szLang, MAX_WINPE_PROFILE_STRING, lpszWinBOMPath);
|
||
|
GetPrivateProfileString(WBOM_WINPE_SECTION, INI_KEY_WBOM_WINPE_SKU, NULLSTR, szSku, MAX_WINPE_PROFILE_STRING, lpszWinBOMPath);
|
||
|
GetPrivateProfileString(WBOM_WINPE_SECTION, INI_KEY_WBOM_WINPE_CFGSET, NULLSTR, szCfg, MAX_WINPE_PROFILE_STRING, lpszWinBOMPath);
|
||
|
GetPrivateProfileString(WBOM_WINPE_SECTION, INI_KEY_WBOM_WINPE_SRCROOT, NULLSTR, szOpkSrcRoot, MAX_WINPE_PROFILE_STRING, lpszWinBOMPath);
|
||
|
GetPrivateProfileString(WBOM_WINPE_SECTION, INI_KEY_WBOM_WINPE_OPTSOURCES, NULLSTR, szOptSources, MAX_WINPE_PROFILE_STRING, lpszWinBOMPath);
|
||
|
|
||
|
// Find the system architecture. (x86 or ia64)
|
||
|
//
|
||
|
if ( GET_FLAG(g_dwFactoryFlags, FLAG_IA64_MODE) )
|
||
|
lstrcpyn(szArch, _T("ia64"), AS ( szArch ) );
|
||
|
else
|
||
|
lstrcpyn(szArch, _T("x86"), AS ( szArch ) );
|
||
|
|
||
|
if (*szLang && *szSku && *szCfg && *szOpkSrcRoot)
|
||
|
{
|
||
|
|
||
|
LPTSTR lpSource = NULLCHR;
|
||
|
LPTSTR lpTarget = NULLCHR;
|
||
|
LPTSTR lpOpkSrcRoot = NULLCHR;
|
||
|
DWORD cbSource = 0;
|
||
|
DWORD cbTarget = 0;
|
||
|
DWORD dwError = 0;
|
||
|
TCHAR szOpkSrcComputerName[MAX_COMPUTERNAME_LENGTH + 1] = NULLSTR;
|
||
|
LPTSTR lpComputerName = NULL;
|
||
|
NET_API_STATUS nas = NERR_Success;
|
||
|
|
||
|
// Make sure that source and target directories contain a trailing backslash
|
||
|
// If there is not trailing backslash add one.
|
||
|
//
|
||
|
|
||
|
AddPathN(szOpkSrcRoot, NULLSTR, AS ( szOpkSrcRoot ));
|
||
|
AddPathN(g_szTargetDrive, NULLSTR, AS ( g_szTargetDrive ) );
|
||
|
|
||
|
// Parse the SrcRoot string and pull out the unc path
|
||
|
//
|
||
|
lpOpkSrcRoot = szOpkSrcRoot;
|
||
|
|
||
|
if (( *lpOpkSrcRoot == CHR_BACKSLASH) &&
|
||
|
( *(lpOpkSrcRoot = CharNext(lpOpkSrcRoot)) == CHR_BACKSLASH))
|
||
|
{
|
||
|
DWORD dwTimeStart = 0;
|
||
|
DWORD dwTimeLast = 0;
|
||
|
|
||
|
// We're looking at a UNC path name.
|
||
|
//
|
||
|
lpOpkSrcRoot = CharNext(lpOpkSrcRoot);
|
||
|
lpComputerName = lpOpkSrcRoot;
|
||
|
|
||
|
while (*(lpOpkSrcRoot = CharNext(lpOpkSrcRoot)) != CHR_BACKSLASH)
|
||
|
{
|
||
|
if (*lpOpkSrcRoot == NULLCHR)
|
||
|
{
|
||
|
// Parse error: no share name specified.
|
||
|
//
|
||
|
FacLogFile(0 | LOG_ERR | LOG_MSG_BOX, IDS_ERR_NO_SHARE_NAME);
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Get the computer name.
|
||
|
//
|
||
|
lstrcpyn(szOpkSrcComputerName, lpComputerName,
|
||
|
(lpOpkSrcRoot - lpComputerName) < AS(szOpkSrcComputerName) ? (INT) (lpOpkSrcRoot - lpComputerName) : AS(szOpkSrcComputerName));
|
||
|
|
||
|
while (*(lpOpkSrcRoot = CharNext(lpOpkSrcRoot)) != CHR_BACKSLASH)
|
||
|
{
|
||
|
if (*lpOpkSrcRoot == NULLCHR)
|
||
|
{
|
||
|
// Parse error: no share name specified.
|
||
|
//
|
||
|
FacLogFile(0 | LOG_ERR | LOG_MSG_BOX, IDS_ERR_NO_SHARE_NAME);
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Read credentials from the WinBOM.
|
||
|
//
|
||
|
GetCredentials(szUsername, AS(szUsername), szPassword, AS(szPassword), lpszWinBOMPath, WBOM_WINPE_SECTION);
|
||
|
|
||
|
// Make sure that we're using the guest account if no other account is specified.
|
||
|
//
|
||
|
if ( NULLCHR == szUsername[0] )
|
||
|
lstrcpyn(szUsername, _T("guest"), AS ( szUsername ) );
|
||
|
|
||
|
// lpOpkSrcRoot now points to the backslash following the share name.
|
||
|
// Use this stuff in place. Make sure we set this back to backslash after NetUseAdd is done.
|
||
|
//
|
||
|
*lpOpkSrcRoot = NULLCHR;
|
||
|
|
||
|
// If the user specified a username of the form "domain\username"
|
||
|
// ignore the domain entry and use the one specified here. Otherwise use the domain entry here.
|
||
|
// After this the szUsername variable will always contain a username of the form "domain\username"
|
||
|
// if the domain was specified.
|
||
|
//
|
||
|
if ( (NULL == _tcschr(szUsername, _T('\\'))) && szDomain[0] )
|
||
|
{
|
||
|
// Build the full "domain\username" in szDomain and then copy it back to the szUsername.
|
||
|
//
|
||
|
if ( FAILED ( StringCchCat ( szDomain, AS ( szDomain ), _T("\\")) ) )
|
||
|
{
|
||
|
FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), szDomain, _T("\\") ) ;
|
||
|
}
|
||
|
if ( FAILED ( StringCchCat ( szDomain, AS ( szDomain ), szUsername) ) )
|
||
|
{
|
||
|
FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), szDomain, szUsername ) ;
|
||
|
}
|
||
|
lstrcpyn(szUsername, szDomain, AS ( szUsername ) );
|
||
|
}
|
||
|
|
||
|
dwTimeLast = dwTimeStart = GetTickCount();
|
||
|
|
||
|
while ( (nas = ConnectNetworkResource(szOpkSrcRoot, szUsername, szPassword, TRUE) != NERR_Success) &&
|
||
|
(((dwTimeLast = GetTickCount()) - dwTimeStart) < (NET_CONNECT_TIMEOUT * 1000)) )
|
||
|
{
|
||
|
// Wait for half a second to give net services a chance to settle down.
|
||
|
//
|
||
|
Sleep(500);
|
||
|
FacLogFileStr(3, _T("Net connect error: %d"), nas);
|
||
|
}
|
||
|
|
||
|
FacLogFileStr(3, _T("Waited for %d milliseconds to connect to the server."), (dwTimeLast - dwTimeStart));
|
||
|
|
||
|
// If we failed put up the error message and return FALSE.
|
||
|
//
|
||
|
if ( NERR_Success != nas )
|
||
|
{
|
||
|
// Can't authenticate to the server.
|
||
|
//
|
||
|
LPTSTR lpError = NULL;
|
||
|
|
||
|
// Try to get the description of the error.
|
||
|
//
|
||
|
if ( FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, nas, 0, (LPTSTR) &lpError, 0, NULL) == 0 )
|
||
|
lpError = NULL;
|
||
|
|
||
|
FacLogFile(0 | LOG_ERR | LOG_MSG_BOX, IDS_ERR_CANTAUTHSERVER, lpError ? lpError : NULLSTR);
|
||
|
FREE(lpError);
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
*lpOpkSrcRoot = CHR_BACKSLASH;
|
||
|
}
|
||
|
|
||
|
// Make sure that source and target root directories exist.
|
||
|
//
|
||
|
if (!DirectoryExists(g_szTargetDrive) || !DirectoryExists(szOpkSrcRoot))
|
||
|
{
|
||
|
FacLogFile(0 | LOG_ERR, IDS_ERR_NOSOURCEORTARGET, szOpkSrcRoot, g_szTargetDrive);
|
||
|
bRet = FALSE;
|
||
|
}
|
||
|
|
||
|
lstrcpyn( szSource, szOpkSrcRoot, AS ( szSource ) );
|
||
|
lstrcpyn( szTarget, g_szTargetDrive, AS ( szTarget ) );
|
||
|
|
||
|
lpSource = szSource + lstrlen(szOpkSrcRoot);
|
||
|
cbSource = AS(szSource) - lstrlen(szOpkSrcRoot);
|
||
|
lpTarget = szTarget + lstrlen(g_szTargetDrive);
|
||
|
cbTarget = AS(szTarget) - lstrlen(g_szTargetDrive);
|
||
|
|
||
|
for (i = 0; ( i < AS(g_filesToCopy) ) && bRet; i++)
|
||
|
{
|
||
|
//
|
||
|
// Get the source and target and expand them to the real filenames.
|
||
|
//
|
||
|
|
||
|
if (ExpandStrings(g_filesToCopy[i].szFISourceName, lpSource, cbSource, env, AS(env)) &&
|
||
|
ExpandStrings(g_filesToCopy[i].szFITargetName, lpTarget, cbTarget, env, AS(env)))
|
||
|
{
|
||
|
// Create the directory.
|
||
|
//
|
||
|
TCHAR szFullPath[MAX_PATH] = NULLSTR;
|
||
|
LPTSTR lpFind = NULL;
|
||
|
|
||
|
if (GetFullPathName(szTarget, AS(szFullPath), szFullPath, &lpFind) && szFullPath[0] && lpFind)
|
||
|
{
|
||
|
*lpFind = NULLCHR;
|
||
|
CreatePath(szFullPath);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
if (g_filesToCopy[i].bDirectory)
|
||
|
{
|
||
|
if (!CopyDirectory(szSource, szTarget) && g_filesToCopy[i].bRequired)
|
||
|
{
|
||
|
FacLogFile(0 | LOG_ERR, IDS_ERR_FAILEDCOPYDIR, szSource);
|
||
|
bRet = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
else if (!CopyFile(szSource, szTarget, FALSE) && g_filesToCopy[i].bRequired)
|
||
|
{
|
||
|
FacLogFile(0 | LOG_ERR, IDS_ERR_FAILEDCOPYFILE, szSource);
|
||
|
bRet = FALSE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Could not expand the strings
|
||
|
//
|
||
|
FacLogFileStr(3 | LOG_ERR, _T("Cannot expand filename string. Filename: %s."), g_filesToCopy[i].szFISourceName);
|
||
|
|
||
|
if (g_filesToCopy[i].bRequired)
|
||
|
{
|
||
|
// Log error here.
|
||
|
//
|
||
|
FacLogFile(0 | LOG_ERR | LOG_MSG_BOX, IDS_ERR_COPYFILE, g_filesToCopy[i].szFISourceName);
|
||
|
bRet = FALSE;
|
||
|
}
|
||
|
}
|
||
|
} // for loop
|
||
|
|
||
|
// Clean up the files that we copied over to the root drive
|
||
|
//
|
||
|
lstrcpyn(szBuffer, g_szTargetDrive, AS ( szBuffer ) );
|
||
|
AddPathN(szBuffer, GET_FLAG(g_dwFactoryFlags, FLAG_IA64_MODE) ? _T("ia64") : _T("i386"), AS(szBuffer));
|
||
|
CleanupSourcesDir(szBuffer);
|
||
|
|
||
|
// Let's start the winnt32 setup here.
|
||
|
//
|
||
|
if (bRet)
|
||
|
{
|
||
|
TCHAR szPreExpand[MAX_PATH] = NULLSTR;
|
||
|
TCHAR szSetup[MAX_PATH] = NULLSTR;
|
||
|
TCHAR szConfig[MAX_PATH] = NULLSTR;
|
||
|
TCHAR szUnattend[MAX_PATH] = NULLSTR;
|
||
|
TCHAR szCommandLine[MAX_PATH] = NULLSTR;
|
||
|
DWORD dwExitCode = 0;
|
||
|
|
||
|
lstrcpyn(szPreExpand, _T("\""), AS ( szPreExpand ) );
|
||
|
|
||
|
if ( FAILED ( StringCchCat ( szPreExpand, AS ( szPreExpand ), g_szTargetDrive) ) )
|
||
|
{
|
||
|
FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), szPreExpand, g_szTargetDrive ) ;
|
||
|
}
|
||
|
|
||
|
if ( GET_FLAG(g_dwFactoryFlags, FLAG_IA64_MODE) )
|
||
|
{
|
||
|
if ( FAILED ( StringCchCat ( szPreExpand, AS ( szPreExpand ), _T("ia64\\winnt32.exe\"") ) ) )
|
||
|
{
|
||
|
FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), szPreExpand, _T("ia64\\winnt32.exe\"" ) ) ;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( FAILED ( StringCchCat ( szPreExpand, AS ( szPreExpand ), _T("i386\\winnt32.exe\"") ) ) )
|
||
|
{
|
||
|
FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), szPreExpand, _T("i386\\winnt32.exe\"") );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!ExpandStrings(szPreExpand, szSetup, AS(szSetup), env, AS(env)))
|
||
|
{
|
||
|
FacLogFileStr(3 | LOG_ERR, _T("Error expanding winnt32.exe source string: %s"), szPreExpand);
|
||
|
bRet = FALSE;
|
||
|
}
|
||
|
|
||
|
// Need a full path to the config set directory.
|
||
|
//
|
||
|
lstrcpyn(szPreExpand, _T("\""), AS ( szPreExpand ) );
|
||
|
if ( FAILED ( StringCchCat ( szPreExpand, AS ( szPreExpand ), szOpkSrcRoot ) ) )
|
||
|
{
|
||
|
FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), szPreExpand, szOpkSrcRoot ) ;
|
||
|
}
|
||
|
|
||
|
if ( FAILED ( StringCchCat ( szPreExpand, AS ( szPreExpand ), _T("cfgsets\\<cfg>\"") ) ) )
|
||
|
{
|
||
|
FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), szPreExpand, _T("cfgsets\\<cfg>\"") ) ;
|
||
|
}
|
||
|
|
||
|
|
||
|
if ( !ExpandStrings(szPreExpand, szConfig, AS(szConfig), env, AS(env)) )
|
||
|
{
|
||
|
FacLogFileStr(3 | LOG_ERR, _T("Error expanding config set source string: %s"), szPreExpand);
|
||
|
bRet = FALSE;
|
||
|
}
|
||
|
|
||
|
// Setup the full path to the unattend file.
|
||
|
//
|
||
|
lstrcpyn(szUnattend, g_szTargetDrive, AS ( szUnattend ) );
|
||
|
|
||
|
if ( FAILED ( StringCchCat ( szUnattend, AS ( szUnattend ), _T("sysprep\\unattend.txt") ) ) )
|
||
|
{
|
||
|
FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), szUnattend, _T("sysprep\\unattend.txt") ) ;
|
||
|
}
|
||
|
|
||
|
// Write the UNC to where the $OEM$ directory is to the unattend we copied local.
|
||
|
//
|
||
|
WritePrivateProfileString(_T("Unattended"), _T("OemFilesPath"), szConfig, szUnattend);
|
||
|
|
||
|
// Set up the command line
|
||
|
//
|
||
|
if ( GET_FLAG(g_dwFactoryFlags, FLAG_IA64_MODE) )
|
||
|
{
|
||
|
lstrcpyn(szCommandLine, _T("/tempdrive:"), AS ( szCommandLine ) );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
lstrcpyn ( szCommandLine, _T("/syspart:"), AS ( szCommandLine ) );
|
||
|
}
|
||
|
if ( FAILED ( StringCchCat ( szCommandLine, AS ( szCommandLine ), g_szTargetDrive ) ) )
|
||
|
{
|
||
|
FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), szCommandLine, g_szTargetDrive ) ;
|
||
|
}
|
||
|
|
||
|
if ( FAILED ( StringCchCat ( szCommandLine, AS ( szCommandLine ), _T(" /noreboot /unattend:") ) ) )
|
||
|
{
|
||
|
FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), szCommandLine, _T(" /noreboot /unattend:") ) ;
|
||
|
}
|
||
|
if ( FAILED ( StringCchCat ( szCommandLine, AS ( szCommandLine ), szUnattend ) ) )
|
||
|
{
|
||
|
FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), szCommandLine, szUnattend ) ;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Check if we need to install from multiple source locations...
|
||
|
//
|
||
|
if ( ( 0 == LSTRCMPI(szOptSources, WBOM_YES) ) &&
|
||
|
FAILED( StringCchCat( szCommandLine, AS(szCommandLine), _T(" /makelocalsource:all") ) ) )
|
||
|
{
|
||
|
FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), szCommandLine, _T(" /makelocalsource:all") ) ;
|
||
|
}
|
||
|
|
||
|
FacLogFileStr(3, _T("Executing: %s %s\n"), szSetup, szCommandLine);
|
||
|
|
||
|
if ( !InvokeExternalApplicationEx( szSetup, szCommandLine, &dwExitCode, INFINITE, TRUE ) )
|
||
|
{
|
||
|
|
||
|
FacLogFile(0 | LOG_ERR | LOG_MSG_BOX, IDS_ERR_SETUP, szSetup, szCommandLine);
|
||
|
bRet = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
// There was a problem reading one of the variables from the winbom.ini
|
||
|
// Return TRUE like nothing happened. This basically means that we will not
|
||
|
// copy down configsets
|
||
|
//
|
||
|
FacLogFile(0, IDS_ERR_MISSINGVAR);
|
||
|
}
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
BOOL DisplayCopyFiles(LPSTATEDATA lpStateData)
|
||
|
{
|
||
|
return ( IniSettingExists(lpStateData->lpszWinBOMPath, INI_SEC_WBOM_WINPE, INI_KEY_WBOM_WINPE_LANG, NULL) &&
|
||
|
IniSettingExists(lpStateData->lpszWinBOMPath, INI_SEC_WBOM_WINPE, INI_KEY_WBOM_WINPE_SKU, NULL) &&
|
||
|
IniSettingExists(lpStateData->lpszWinBOMPath, INI_SEC_WBOM_WINPE, INI_KEY_WBOM_WINPE_CFGSET, NULL) &&
|
||
|
IniSettingExists(lpStateData->lpszWinBOMPath, INI_SEC_WBOM_WINPE, INI_KEY_WBOM_WINPE_SRCROOT, NULL) );
|
||
|
}
|
||
|
|
||
|
// Concatenates strings and returns a pointer to the end of lpString1. Used for performance
|
||
|
// whenever lots of strings get appended to a string.
|
||
|
//
|
||
|
LPTSTR mylstrcat(LPTSTR lpString1, LPCTSTR lpString2, DWORD dwSize )
|
||
|
{
|
||
|
static DWORD dwBufSize = 0;
|
||
|
|
||
|
if ( dwSize )
|
||
|
dwBufSize = dwSize;
|
||
|
|
||
|
// If dwBufSize becomes less than or equal to zero
|
||
|
// StringCchCat will fail anyway.
|
||
|
if ( SUCCEEDED ( StringCchCat ( lpString1, dwBufSize, lpString2 ) ) )
|
||
|
{
|
||
|
// Get the length of the string
|
||
|
DWORD dwLen = lstrlen ( lpString1 ) ;
|
||
|
|
||
|
// Substract the length from the total length
|
||
|
dwBufSize -= dwLen ;
|
||
|
|
||
|
return (lpString1 + dwLen );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), lpString1, lpString2 ) ;
|
||
|
}
|
||
|
return NULL ;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Starts diskpart with redirected input and output.
|
||
|
|
||
|
//
|
||
|
// ISSUE-2002/02/25-acosma,georgeje - If read pipe fills up we will have deadlock. Possible solution
|
||
|
// is to create another thread that reads from the readpipe and writes to the debug file. Another
|
||
|
// possibility is to Create the debug file or NUL device file (dbg and non-dbg versions) and pass
|
||
|
// that as the process's stdout handle.
|
||
|
//
|
||
|
|
||
|
BOOL StartDiskpart(HANDLE *phStdinWrDup, HANDLE *phStdoutRdDup, HANDLE *phStdinRd, HANDLE *phStdoutWr)
|
||
|
{
|
||
|
|
||
|
HANDLE hStdinWr = NULL,
|
||
|
hStdoutRd = NULL;
|
||
|
SC_HANDLE hSCM;
|
||
|
|
||
|
SECURITY_ATTRIBUTES saAttr;
|
||
|
BOOL fSuccess;
|
||
|
|
||
|
PROCESS_INFORMATION piProcInfo;
|
||
|
STARTUPINFO siStartInfo;
|
||
|
TCHAR szDiskpart[20] = NULLSTR;
|
||
|
|
||
|
BOOL bRet = FALSE;
|
||
|
|
||
|
|
||
|
// Set the bInheritHandle flag so pipe handles are inherited.
|
||
|
//
|
||
|
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||
|
saAttr.bInheritHandle = TRUE;
|
||
|
saAttr.lpSecurityDescriptor = NULL;
|
||
|
|
||
|
// Start the dmserver service myself, so that diskpart doesn't choke
|
||
|
// when I start it. In debug mode log the time it took to do this.
|
||
|
//
|
||
|
if ( hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS) )
|
||
|
{
|
||
|
#ifdef DBG
|
||
|
DWORD dwTime;
|
||
|
dwTime = GetTickCount();
|
||
|
#endif // #ifdef DBG
|
||
|
|
||
|
// Start the service here. Start my service waits for the service to start.
|
||
|
// I'm not checking the return status here because diskpart will fail later,
|
||
|
// if it can't start dmserver and we will fail out when we try to format the
|
||
|
// drives. This way we have 2 chances to work correctly.
|
||
|
//
|
||
|
StartMyService(_T("dmserver"), hSCM);
|
||
|
|
||
|
#ifdef DBG
|
||
|
FacLogFileStr(3, _T("Waited for dmserver to start for %d seconds."), (GetTickCount() - dwTime)/1000);
|
||
|
#endif // #ifdef DBG
|
||
|
|
||
|
CloseServiceHandle(hSCM);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
FacLogFile(0 | LOG_ERR, IDS_ERR_SCM);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// The steps for redirecting child process's STDOUT:
|
||
|
// 1. Create anonymous pipe to be STDOUT for child process.
|
||
|
// 2. Create a noninheritable duplicate of the read handle and
|
||
|
// close the inheritable read handle.
|
||
|
//
|
||
|
|
||
|
// Create a pipe for the child process's STDOUT.
|
||
|
//
|
||
|
// Create noninheritable read handle.
|
||
|
//
|
||
|
if ( CreatePipe(&hStdoutRd, phStdoutWr, &saAttr, 0)
|
||
|
&&
|
||
|
DuplicateHandle(GetCurrentProcess(), hStdoutRd, GetCurrentProcess(), phStdoutRdDup , 0,
|
||
|
FALSE, DUPLICATE_SAME_ACCESS) )
|
||
|
{
|
||
|
// Close the inheritable read handle.
|
||
|
//
|
||
|
CLOSEHANDLE(hStdoutRd);
|
||
|
|
||
|
// The steps for redirecting child process's STDIN:
|
||
|
// 1. Create anonymous pipe to be STDIN for child process.
|
||
|
// 2. Create a noninheritable duplicate of the write handle,
|
||
|
// and close the inheritable write handle.
|
||
|
|
||
|
|
||
|
// Create a pipe for the child process's STDIN.
|
||
|
//
|
||
|
// Duplicate the write handle to the pipe so it is not inherited.
|
||
|
//
|
||
|
if (CreatePipe(phStdinRd, &hStdinWr, &saAttr, 0)
|
||
|
&&
|
||
|
DuplicateHandle(GetCurrentProcess(), hStdinWr, GetCurrentProcess(), phStdinWrDup, 0,
|
||
|
FALSE, DUPLICATE_SAME_ACCESS) )
|
||
|
{
|
||
|
|
||
|
// Close the handle so that it is not inherited.
|
||
|
//
|
||
|
CLOSEHANDLE(hStdinWr);
|
||
|
|
||
|
//
|
||
|
// Now create the child process.
|
||
|
//
|
||
|
|
||
|
// Set up members of the PROCESS_INFORMATION structure.
|
||
|
//
|
||
|
ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
|
||
|
|
||
|
// Set up members of the STARTUPINFO structure.
|
||
|
//
|
||
|
ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
|
||
|
siStartInfo.cb = sizeof(STARTUPINFO);
|
||
|
|
||
|
siStartInfo.dwFlags = STARTF_USESTDHANDLES;
|
||
|
siStartInfo.hStdInput = *phStdinRd;
|
||
|
siStartInfo.hStdOutput = *phStdoutWr;
|
||
|
siStartInfo.hStdError = *phStdoutWr;
|
||
|
// siStartInfo.wShowWindow = SW_HIDE;
|
||
|
|
||
|
|
||
|
// Create the child process (DISKPART)
|
||
|
//
|
||
|
lstrcpyn(szDiskpart, _T("diskpart"), AS ( szDiskpart ) );
|
||
|
|
||
|
if (CreateProcess(NULL,
|
||
|
szDiskpart, // command line
|
||
|
NULL, // process security attributes
|
||
|
NULL, // primary thread security attributes
|
||
|
TRUE, // handles are inherited
|
||
|
CREATE_NO_WINDOW, // creation flags - do no show diskpart console
|
||
|
NULL, // use parent's environment
|
||
|
NULL, // use parent's current directory
|
||
|
&siStartInfo, // STARTUPINFO pointer
|
||
|
&piProcInfo)) // receives PROCESS_INFORMATION
|
||
|
{
|
||
|
CLOSEHANDLE(piProcInfo.hThread);
|
||
|
CLOSEHANDLE(piProcInfo.hProcess);
|
||
|
bRet = TRUE;
|
||
|
}
|
||
|
else
|
||
|
FacLogFile(0 | LOG_ERR, IDS_ERR_CREATEPROCESS);
|
||
|
}
|
||
|
else
|
||
|
FacLogFile(0 | LOG_ERR, IDS_ERR_CREATESTDIN);
|
||
|
}
|
||
|
else
|
||
|
FacLogFile(0 | LOG_ERR, IDS_ERR_CREATESTDOUT);
|
||
|
|
||
|
|
||
|
CLOSEHANDLE(hStdinWr);
|
||
|
CLOSEHANDLE(hStdoutRd);
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
BOOL ProcessDiskConfigSection(LPTSTR lpszWinBOMPath)
|
||
|
{
|
||
|
TCHAR szDisks[BUFSIZE] = NULLSTR;
|
||
|
LPTSTR lpDisk;
|
||
|
TCHAR szSectionBuffer[MAX_WINPE_PROFILE_STRING] = NULLSTR;
|
||
|
BOOL bRet = TRUE;
|
||
|
UINT uiDiskNumber = 0;
|
||
|
DWORD numPartitions = 0;
|
||
|
BOOL bWipeDisk = FALSE;
|
||
|
|
||
|
|
||
|
GetPrivateProfileString(INI_SEC_WBOM_DISKCONFIG, NULL, NULLSTR, szDisks, AS(szDisks), lpszWinBOMPath);
|
||
|
|
||
|
if (szDisks[0])
|
||
|
{
|
||
|
// Get the Section names. Process each disk section.
|
||
|
//
|
||
|
for (lpDisk = szDisks; *lpDisk; lpDisk += (lstrlen(lpDisk) + 1))
|
||
|
{
|
||
|
LPTSTR lpDiskID = NULL;
|
||
|
numPartitions = 0;
|
||
|
|
||
|
GetPrivateProfileString(INI_SEC_WBOM_DISKCONFIG,
|
||
|
lpDisk,
|
||
|
NULLSTR,
|
||
|
szSectionBuffer,
|
||
|
AS(szSectionBuffer),
|
||
|
lpszWinBOMPath);
|
||
|
|
||
|
|
||
|
// Make sure that the disk number is specified.
|
||
|
// Skip over the first 4 characters which should be "Disk", and point
|
||
|
// to the first digit in the disk number.
|
||
|
//
|
||
|
lpDiskID = lpDisk + 4;
|
||
|
|
||
|
if ( szSectionBuffer[0] && (uiDiskNumber = (UINT) _wtoi(lpDiskID)) )
|
||
|
{
|
||
|
TCHAR szBuf[MAX_WINPE_PROFILE_STRING] = NULLSTR;
|
||
|
|
||
|
// See if WipeDisk is set for this disk. On IA64 wipe by default.
|
||
|
//
|
||
|
GetPrivateProfileString(szSectionBuffer,
|
||
|
WBOM_DISK_CONFIG_WIPE_DISK,
|
||
|
NULLSTR,
|
||
|
szBuf,
|
||
|
AS(szBuf),
|
||
|
lpszWinBOMPath);
|
||
|
|
||
|
if ( 0 == LSTRCMPI(szBuf, WBOM_YES) )
|
||
|
bWipeDisk = TRUE;
|
||
|
else if ( (0 != LSTRCMPI(szBuf, WBOM_NO)) && (GET_FLAG(g_dwFactoryFlags, FLAG_IA64_MODE)) )
|
||
|
bWipeDisk = TRUE;
|
||
|
|
||
|
GetNumberOfPartitions(uiDiskNumber - 1, &numPartitions);
|
||
|
|
||
|
if ( 0 == numPartitions || bWipeDisk )
|
||
|
ProcessDisk(uiDiskNumber, szSectionBuffer, lpszWinBOMPath, bWipeDisk);
|
||
|
// If we're working on disk 0 (DiskID = 1) format the C drive.
|
||
|
//
|
||
|
else if ( 1 == uiDiskNumber )
|
||
|
if ( !JustFormatC(lpszWinBOMPath, szSectionBuffer) )
|
||
|
bRet = FALSE;
|
||
|
// else just ignore the disk :).
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
FacLogFile(0 | LOG_ERR, IDS_ERR_DISKCFGENTRY, lpDisk);
|
||
|
bRet = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( g_PartList )
|
||
|
{
|
||
|
// If no partitions on disk 0 were set active,
|
||
|
// set the first PRIMARY partition on the disk active.
|
||
|
// pFirst variable will maintain a pointer to the first PRIMARY partition
|
||
|
// on the disk.
|
||
|
//
|
||
|
BOOL bActive = FALSE;
|
||
|
PPARTITION pFirst = NULL; // for the next block this will point to the first PRIMARY partition on disk 0.
|
||
|
PPARTITION pCur = NULL;
|
||
|
|
||
|
for ( pCur = g_PartList; pCur && 0 == pCur->uiDiskID; pCur = pCur->pNext )
|
||
|
{
|
||
|
if ( ptPrimary == pCur->uiPartitionType )
|
||
|
{
|
||
|
if ( !pFirst )
|
||
|
pFirst = pCur;
|
||
|
|
||
|
if ( pCur->bSetActive )
|
||
|
{
|
||
|
bActive = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( !bActive && pFirst )
|
||
|
pFirst->bSetActive = TRUE;
|
||
|
|
||
|
//
|
||
|
// If we're on IA64 do a check to see if user specified EFI and MSR partitions
|
||
|
// for each drive. If not add them in automatically.
|
||
|
//
|
||
|
if ( GET_FLAG(g_dwFactoryFlags, FLAG_IA64_MODE) )
|
||
|
{
|
||
|
PPARTITION pLastLast = NULL;
|
||
|
PPARTITION pLast = NULL;
|
||
|
BOOL bMsr = FALSE;
|
||
|
BOOL bEfi = FALSE;
|
||
|
|
||
|
|
||
|
// pCur is the iterator and pLast will be pointing
|
||
|
// to the element previous to pCur. pLastLast will point to the last element of the
|
||
|
// previous disk.
|
||
|
//
|
||
|
|
||
|
for ( pCur = g_PartList; pCur; pCur = pCur->pNext )
|
||
|
{ // We're on the same disk.
|
||
|
//
|
||
|
if ( !pLast || pCur->uiDiskID == pLast->uiDiskID )
|
||
|
{
|
||
|
if ( ptMsr == pCur->uiPartitionType )
|
||
|
bMsr = TRUE;
|
||
|
if ( ptEfi == pCur->uiPartitionType )
|
||
|
bEfi = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{ // Just moved on to a new disk. If Msr and Efi were not found on previous disk make them!
|
||
|
//
|
||
|
AddMsrAndEfi(bMsr, bEfi, pLastLast, pLast->uiDiskID, bWipeDisk);
|
||
|
// Re-init these for the next disk.
|
||
|
//
|
||
|
bEfi = bMsr = FALSE;
|
||
|
pLastLast = pLast;
|
||
|
}
|
||
|
pLast = pCur;
|
||
|
}
|
||
|
// Do this for the special case when we are at the end of the list.
|
||
|
//
|
||
|
AddMsrAndEfi(bMsr, bEfi, pLastLast, pLast->uiDiskID, bWipeDisk);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
|
||
|
#define GO if ( szBuf[0] ) bGo = TRUE
|
||
|
|
||
|
BOOL ProcessDisk(UINT diskID, LPTSTR lpSectionName, LPTSTR lpszWinBOMPath, BOOL bWipeDisk)
|
||
|
{
|
||
|
TCHAR szBuf[MAX_WINPE_PROFILE_STRING] = NULLSTR;
|
||
|
TCHAR szKey[MAX_WINPE_PROFILE_STRING] = NULLSTR;
|
||
|
BOOL bGo = TRUE;
|
||
|
UINT i = 1;
|
||
|
PPARTITION pLast = NULL;
|
||
|
PPARTITION pCur = NULL;
|
||
|
|
||
|
|
||
|
// Need pLast to point to the last element in the list.
|
||
|
// Go through the list until we find the last element.
|
||
|
//
|
||
|
for (pCur = g_PartList; pCur; pCur = pCur->pNext)
|
||
|
{
|
||
|
pLast = pCur;
|
||
|
}
|
||
|
|
||
|
// Loop will be interrupted when a SizeN key no longer exists. (N is i and grows with each iteration).
|
||
|
//
|
||
|
while (bGo)
|
||
|
{
|
||
|
// Initialize this to not continue.
|
||
|
//
|
||
|
bGo = FALSE;
|
||
|
|
||
|
// The MALLOC macro gives us blanked out memory, so that we don't have to initialize
|
||
|
// the pNext pointer to NULL. pCur is now used to point to the new node that we create.
|
||
|
//
|
||
|
if ( pCur = (PPARTITION) MALLOC( sizeof(PARTITION) ) )
|
||
|
{
|
||
|
// Size
|
||
|
//
|
||
|
Build(szKey, AS ( szKey ), i, DCS_SIZE);
|
||
|
GetPrivateProfileString(lpSectionName, szKey, NULLSTR, szBuf, AS(szBuf), lpszWinBOMPath);
|
||
|
GO;
|
||
|
|
||
|
if ( szBuf[0] )
|
||
|
{
|
||
|
|
||
|
if ( !lstrcmpi(szBuf, _T("*")) )
|
||
|
pCur->ullSize = 0;
|
||
|
else
|
||
|
// In case number cannot be converted to integer 0 will be returned.
|
||
|
// This is OK.
|
||
|
pCur->ullSize = _ttoi(szBuf);
|
||
|
}
|
||
|
|
||
|
// WipeDisk
|
||
|
//
|
||
|
pCur->bWipeDisk = bWipeDisk;
|
||
|
|
||
|
// QuickFormat
|
||
|
//
|
||
|
Build(szKey, AS ( szKey ), i, DCS_QUICK_FORMAT);
|
||
|
GetPrivateProfileString(lpSectionName, szKey, NULLSTR, szBuf, AS(szBuf), lpszWinBOMPath);
|
||
|
GO;
|
||
|
|
||
|
if ( szBuf[0] && !LSTRCMPI(szBuf, WBOM_NO) )
|
||
|
pCur->bQuickFormat = FALSE;
|
||
|
else
|
||
|
pCur->bQuickFormat = TRUE;
|
||
|
|
||
|
|
||
|
// SetActive
|
||
|
//
|
||
|
Build(szKey, AS ( szKey ), i, DCS_SET_ACTIVE);
|
||
|
GetPrivateProfileString(lpSectionName, szKey, NULLSTR, szBuf, AS(szBuf), lpszWinBOMPath);
|
||
|
GO;
|
||
|
|
||
|
if ( !LSTRCMPI(szBuf, WBOM_YES) )
|
||
|
pCur->bSetActive = TRUE;
|
||
|
else
|
||
|
pCur->bSetActive = FALSE;
|
||
|
|
||
|
// FileSystem
|
||
|
//
|
||
|
Build(szKey, AS ( szKey ), i, DCS_FILE_SYSTEM);
|
||
|
GetPrivateProfileString(lpSectionName, szKey, NULLSTR, szBuf, AS(szBuf), lpszWinBOMPath);
|
||
|
GO;
|
||
|
|
||
|
if ( !LSTRCMPI(szBuf, _T("FAT32")) || !LSTRCMPI(szBuf, _T("FAT")) )
|
||
|
pCur->uiFileSystem = fsFat32;
|
||
|
else if ( !LSTRCMPI(szBuf, _T("FAT16")) )
|
||
|
pCur->uiFileSystem = fsFat;
|
||
|
else
|
||
|
pCur->uiFileSystem = fsNtfs;
|
||
|
|
||
|
// Partition Type
|
||
|
//
|
||
|
Build(szKey, AS ( szKey ), i, DCS_PARTITION_TYPE);
|
||
|
GetPrivateProfileString(lpSectionName, szKey, NULLSTR, szBuf, AS(szBuf), lpszWinBOMPath);
|
||
|
GO;
|
||
|
|
||
|
if ( !lstrcmpi(szBuf, DCPARTITION_EXTENDED) )
|
||
|
pCur->uiPartitionType = ptExtended;
|
||
|
else if ( !lstrcmpi(szBuf, DCPARTITION_LOGICAL) )
|
||
|
pCur->uiPartitionType = ptLogical;
|
||
|
else if ( !lstrcmpi(szBuf, DCPARTITION_MSR) )
|
||
|
{
|
||
|
pCur->uiPartitionType = ptMsr;
|
||
|
}
|
||
|
else if ( !lstrcmpi(szBuf, DCPARTITION_EFI) )
|
||
|
{
|
||
|
pCur->uiPartitionType = ptEfi;
|
||
|
pCur->uiFileSystem = fsFat32;
|
||
|
}
|
||
|
else
|
||
|
pCur->uiPartitionType = ptPrimary;
|
||
|
|
||
|
// DiskID
|
||
|
//
|
||
|
// Note: -1 is because in the winBOM the diskID is 1 based while Diskpart has it 0-based.
|
||
|
//
|
||
|
pCur->uiDiskID = diskID - 1;
|
||
|
|
||
|
// Deal with the linked list some more.
|
||
|
//
|
||
|
if ( bGo )
|
||
|
{
|
||
|
// Build the linked list.
|
||
|
//
|
||
|
if ( pLast )
|
||
|
pLast->pNext = pCur;
|
||
|
else
|
||
|
g_PartList = pCur;
|
||
|
|
||
|
pLast = pCur;
|
||
|
}
|
||
|
else
|
||
|
{ // If we didn't find any entries for this partition it means that we're done.
|
||
|
// FREE up the current node.
|
||
|
//
|
||
|
FREE(pCur);
|
||
|
}
|
||
|
|
||
|
} // if
|
||
|
i++;
|
||
|
} // while
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
VOID AddMsrAndEfi(BOOL bMsr, BOOL bEfi, PPARTITION pLastLast, UINT uiDiskID, BOOL bWipeDisk)
|
||
|
{
|
||
|
PPARTITION pNew = NULL;
|
||
|
|
||
|
if ( !bMsr )
|
||
|
{
|
||
|
if ( pNew = (PPARTITION) MALLOC( sizeof(PARTITION) ) )
|
||
|
{
|
||
|
pNew->uiDiskID = uiDiskID;
|
||
|
pNew->ullSize = GetDiskMSRSizeMB(uiDiskID);
|
||
|
pNew->uiPartitionType = ptMsr;
|
||
|
pNew->bWipeDisk = bWipeDisk;
|
||
|
|
||
|
// Do a check to see if EFI partition is already there.
|
||
|
// If it is, then insert the msr partition after it..not before!.
|
||
|
//
|
||
|
if ( pLastLast)
|
||
|
{
|
||
|
if ( (pLastLast->pNext) && (ptEfi == pLastLast->pNext->uiPartitionType) && (uiDiskID == pLastLast->pNext->uiDiskID) )
|
||
|
ListInsert(pLastLast->pNext, pNew);
|
||
|
else
|
||
|
ListInsert(pLastLast, pNew);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( (ptEfi == g_PartList->uiPartitionType) && (uiDiskID == g_PartList->uiDiskID) )
|
||
|
ListInsert(g_PartList, pNew);
|
||
|
else
|
||
|
ListInsert(NULL, pNew);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( (uiDiskID == 0) && (!bEfi) )
|
||
|
{
|
||
|
if ( pNew = (PPARTITION) MALLOC( sizeof(PARTITION) ) )
|
||
|
{
|
||
|
pNew->uiDiskID = uiDiskID;
|
||
|
pNew->ullSize = GetDiskEFISizeMB(uiDiskID);
|
||
|
pNew->uiPartitionType = ptEfi;
|
||
|
pNew->uiFileSystem = fsFat32;
|
||
|
pNew->bQuickFormat = TRUE;
|
||
|
pNew->bWipeDisk = bWipeDisk;
|
||
|
|
||
|
ListInsert(pLastLast, pNew);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BOOL Build(LPTSTR lpKey, DWORD dwSize, UINT diskID, LPCTSTR lpKeyName)
|
||
|
{
|
||
|
// szBuf is 33 TCHARs since docs for _itot say this is the max size that it will fill.
|
||
|
//
|
||
|
TCHAR szBuf[33] = NULLSTR;
|
||
|
|
||
|
_itot(diskID, szBuf, 10);
|
||
|
|
||
|
if (!szBuf[0])
|
||
|
return FALSE;
|
||
|
|
||
|
lstrcpyn ( lpKey, lpKeyName, dwSize );
|
||
|
if ( FAILED ( StringCchCat ( lpKey, dwSize, szBuf) ) )
|
||
|
{
|
||
|
FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), lpKey, szBuf ) ;
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL FormatPartitions(VOID)
|
||
|
{
|
||
|
TCHAR szCmdLine[MAX_PATH] = NULLSTR;
|
||
|
BOOL bRet = TRUE;
|
||
|
DWORD dwExitCode = 0;
|
||
|
PPARTITION pCur = NULL;
|
||
|
|
||
|
|
||
|
for (pCur = g_PartList; pCur; pCur = pCur->pNext )
|
||
|
{
|
||
|
if ( (ptExtended != pCur->uiPartitionType) && (ptMsr != pCur->uiPartitionType) )
|
||
|
{
|
||
|
|
||
|
szCmdLine[0] = pCur->cDriveLetter;
|
||
|
szCmdLine[1] = _T(':'); // Colon.
|
||
|
szCmdLine[2] = NULLCHR;
|
||
|
|
||
|
if (fsFat32 == pCur->uiFileSystem)
|
||
|
{
|
||
|
if ( FAILED ( StringCchCat ( szCmdLine, AS ( szCmdLine ), _T(" /fs:fat32")) ) )
|
||
|
{
|
||
|
FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), szCmdLine, _T(" /fs:fat32") ) ;
|
||
|
}
|
||
|
}
|
||
|
else if (fsFat == pCur->uiFileSystem)
|
||
|
{
|
||
|
if ( FAILED ( StringCchCat ( szCmdLine, AS ( szCmdLine ), _T(" /fs:fat")) ) )
|
||
|
{
|
||
|
FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), szCmdLine, _T(" /fs:fat") ) ;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( FAILED ( StringCchCat ( szCmdLine, AS ( szCmdLine ), _T(" /fs:ntfs")) ) )
|
||
|
{
|
||
|
FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), szCmdLine, _T(" /fs:ntfs") ) ;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pCur->bQuickFormat)
|
||
|
{
|
||
|
if ( FAILED ( StringCchCat ( szCmdLine, AS ( szCmdLine ), _T(" /q")) ) )
|
||
|
{
|
||
|
FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), szCmdLine, _T(" /q") ) ;
|
||
|
}
|
||
|
}
|
||
|
if ( FAILED ( StringCchCat ( szCmdLine, AS ( szCmdLine ), _T(" /y")) ) )
|
||
|
{
|
||
|
FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), szCmdLine, _T(" /y") ) ;
|
||
|
}
|
||
|
|
||
|
FacLogFileStr(3 | LOG_TIME, _T("Starting to format %c:."), pCur->cDriveLetter);
|
||
|
|
||
|
if (InvokeExternalApplicationEx(_T("format.com"), szCmdLine, &dwExitCode, INFINITE, TRUE))
|
||
|
{
|
||
|
if (!dwExitCode)
|
||
|
{
|
||
|
FacLogFileStr(3 | LOG_TIME, _T("Finished formatting drive %c:."), pCur->cDriveLetter);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Log error here.
|
||
|
FacLogFile(0 | LOG_ERR | LOG_MSG_BOX, IDS_ERR_FORMATFAILED, pCur->cDriveLetter);
|
||
|
bRet = FALSE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
FacLogFile(0 | LOG_ERR | LOG_MSG_BOX, IDS_ERR_NOFORMAT);
|
||
|
bRet = FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
} // for loop
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
BOOL JustFormatC(LPTSTR lpszWinBOMPath, LPTSTR lpszSectionBuffer)
|
||
|
{
|
||
|
TCHAR szFileSystemNameBuffer[128] = NULLSTR;
|
||
|
TCHAR szCmdLine[MAX_PATH] = NULLSTR;
|
||
|
DWORD dwExitCode = 0;
|
||
|
BOOL bForceFormat = FALSE;
|
||
|
BOOL bRet = TRUE;
|
||
|
TCHAR szScratch[MAX_WINPE_PROFILE_STRING] = NULLSTR;
|
||
|
HANDLE hFile = NULL;
|
||
|
|
||
|
WIN32_FIND_DATA fileInfo;
|
||
|
|
||
|
|
||
|
GetPrivateProfileString(lpszSectionBuffer, WBOM_WINPE_FORCE_FORMAT, WBOM_NO, szScratch, MAX_WINPE_PROFILE_STRING, lpszWinBOMPath);
|
||
|
|
||
|
if (0 == LSTRCMPI(szScratch, WBOM_YES))
|
||
|
bForceFormat = TRUE;
|
||
|
|
||
|
if ( !bForceFormat && (hFile = FindFirstFile(_T("C:\\*.*"), &fileInfo)) != INVALID_HANDLE_VALUE )
|
||
|
{
|
||
|
// Files found on C:\. Not good. Ask the user what to do.
|
||
|
//
|
||
|
FindClose(hFile);
|
||
|
|
||
|
if ( GET_FLAG(g_dwFactoryFlags, FLAG_QUIET_MODE) ||
|
||
|
(IDYES != MsgBox(NULL, IDS_MSG_FILESEXIST, IDS_APPNAME, MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2 | MB_SETFOREGROUND))
|
||
|
)
|
||
|
{
|
||
|
FacLogFile(0 | LOG_ERR, IDS_ERR_FILEFOUNDONC);
|
||
|
bRet = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
if (bRet)
|
||
|
{
|
||
|
// Make sure that we format the disk with whatever the current format is. If the disk is currently
|
||
|
// formatted .
|
||
|
//
|
||
|
if ( GetVolumeInformation(_T("C:\\"), NULL, 0, NULL, NULL, NULL, szFileSystemNameBuffer, AS(szFileSystemNameBuffer)) &&
|
||
|
szFileSystemNameBuffer[0] && (0 != LSTRCMPI(szFileSystemNameBuffer, _T("RAW"))) )
|
||
|
{
|
||
|
// There is a known filesystem on here and format will format with
|
||
|
// the existing filesystem.
|
||
|
//
|
||
|
lstrcpyn(szCmdLine, _T("C: /y /q"), AS ( szCmdLine ));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// The drive is not formatted. So by default format it NTFS.
|
||
|
//
|
||
|
if ( FAILED ( StringCchCat ( szCmdLine, AS ( szCmdLine ), _T("C: /fs:ntfs /y /q")) ) )
|
||
|
{
|
||
|
FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), szCmdLine, _T("C: /fs:ntfs /y /q") ) ;
|
||
|
}
|
||
|
}
|
||
|
// Format
|
||
|
//
|
||
|
|
||
|
FacLogFileStr(3, _T("format.com %s\n"), szCmdLine);
|
||
|
|
||
|
if (InvokeExternalApplicationEx(_T("format.com"), szCmdLine, &dwExitCode, INFINITE, TRUE))
|
||
|
{
|
||
|
if (dwExitCode)
|
||
|
{ // Log error here.
|
||
|
FacLogFile(0 | LOG_ERR, IDS_ERR_FORMATFAILED, _T('C'));
|
||
|
bRet = FALSE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
FacLogFile(0 | LOG_ERR | LOG_MSG_BOX, IDS_ERR_NOFORMAT);
|
||
|
}
|
||
|
}
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
ULONGLONG GetDiskSizeMB(UINT uiDiskNumber)
|
||
|
{
|
||
|
|
||
|
HANDLE hDevice = NULL;
|
||
|
TCHAR buffer[MAX_WINPE_PROFILE_STRING] = NULLSTR;
|
||
|
DISK_GEOMETRY DiskGeometry;
|
||
|
ULONGLONG ullDiskSizeMB = 0;
|
||
|
DWORD dwNumBytes = 0;
|
||
|
|
||
|
ZeroMemory( &DiskGeometry, sizeof(DiskGeometry) );
|
||
|
|
||
|
// Open a handle to the disk specified and get its geometry.
|
||
|
//
|
||
|
lstrcpyn(buffer, _T("\\\\.\\PHYSICALDRIVE"), AS ( buffer ) );
|
||
|
_itot(uiDiskNumber, buffer + lstrlen(buffer), 10);
|
||
|
|
||
|
hDevice = CreateFile(buffer,
|
||
|
0,
|
||
|
0,
|
||
|
NULL,
|
||
|
OPEN_EXISTING,
|
||
|
FILE_ATTRIBUTE_NORMAL,
|
||
|
NULL);
|
||
|
|
||
|
if (hDevice == INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
FacLogFileStr(0 | LOG_ERR, _T("DEBUG::Cannot open %s.\n"), buffer);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if ( DeviceIoControl(hDevice, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &DiskGeometry, sizeof(DiskGeometry), &dwNumBytes, NULL ) )
|
||
|
{
|
||
|
ullDiskSizeMB = ( DiskGeometry.BytesPerSector * DiskGeometry.SectorsPerTrack *
|
||
|
DiskGeometry.TracksPerCylinder * DiskGeometry.Cylinders.QuadPart ) / ( 1024 * 1024 );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
FacLogFileStr(0 | LOG_ERR, _T("Error getting disk geometry.\n"));
|
||
|
}
|
||
|
|
||
|
CLOSEHANDLE(hDevice);
|
||
|
return ullDiskSizeMB;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Get the number of partitions on disk DiskNumber
|
||
|
BOOL GetNumberOfPartitions(UINT uiDiskNumber, PDWORD numPartitions)
|
||
|
{
|
||
|
HANDLE hDevice = NULL;
|
||
|
BOOL bResult;
|
||
|
PDRIVE_LAYOUT_INFORMATION DriveLayout = NULL;
|
||
|
DWORD dwDriveLayoutSize;
|
||
|
DWORD dwDataSize = 0;
|
||
|
DWORD dwNumPart = 0;
|
||
|
TCHAR buffer[MAX_PATH] = NULLSTR;
|
||
|
UINT i;
|
||
|
|
||
|
lstrcpyn(buffer, _T("\\\\.\\PHYSICALDRIVE"), AS ( buffer ) );
|
||
|
_itot(uiDiskNumber, buffer + lstrlen(buffer), 10);
|
||
|
|
||
|
hDevice = CreateFile(buffer,
|
||
|
GENERIC_READ,
|
||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||
|
NULL,
|
||
|
OPEN_EXISTING,
|
||
|
FILE_ATTRIBUTE_NORMAL,
|
||
|
NULL);
|
||
|
|
||
|
if (hDevice == INVALID_HANDLE_VALUE) // we can't open the drive
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Get partition information.
|
||
|
//
|
||
|
|
||
|
dwDriveLayoutSize = 1024;
|
||
|
|
||
|
do {
|
||
|
|
||
|
if ( !DriveLayout && !(DriveLayout = MALLOC(1024)) )
|
||
|
{
|
||
|
CLOSEHANDLE(hDevice);
|
||
|
return FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
PDRIVE_LAYOUT_INFORMATION lpTmpDriveLayout;
|
||
|
|
||
|
dwDriveLayoutSize += 1024;
|
||
|
|
||
|
lpTmpDriveLayout = REALLOC(DriveLayout, dwDriveLayoutSize);
|
||
|
if ( !lpTmpDriveLayout )
|
||
|
{
|
||
|
FREE(DriveLayout);
|
||
|
CLOSEHANDLE(hDevice);
|
||
|
return FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DriveLayout = lpTmpDriveLayout;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bResult = DeviceIoControl(
|
||
|
hDevice,
|
||
|
IOCTL_DISK_GET_DRIVE_LAYOUT,
|
||
|
NULL,
|
||
|
0,
|
||
|
DriveLayout,
|
||
|
dwDriveLayoutSize,
|
||
|
&dwDataSize,
|
||
|
NULL
|
||
|
);
|
||
|
|
||
|
|
||
|
} while (!bResult && (GetLastError() == ERROR_INSUFFICIENT_BUFFER));
|
||
|
|
||
|
if (!bResult)
|
||
|
return FALSE;
|
||
|
|
||
|
for (i = 0; i < (DriveLayout)->PartitionCount; i++)
|
||
|
{
|
||
|
PPARTITION_INFORMATION PartInfo = DriveLayout->PartitionEntry + i;
|
||
|
|
||
|
//
|
||
|
// ISSUE-2002/02/25-acosma,georgeje - Add in all the IA64 stuff below.
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// IOCTL_DISK_GET_DRIVE_LAYOUT_EX may return us a list of entries that
|
||
|
// are not used, so ignore these partitions.
|
||
|
//
|
||
|
if (// if its partition 0, which indicates whole disk
|
||
|
// (SPPT_IS_GPT_DISK(DiskNumber) && (PartInfo->PartitionNumber == 0)) ||
|
||
|
// (PartInfo->PartitionLength.QuadPart == 0) ||
|
||
|
// if MBR entry not used or length is zero
|
||
|
// ((DriveLayout->PartitionStyle == PARTITION_STYLE_MBR) &&
|
||
|
(PartInfo->PartitionType == PARTITION_ENTRY_UNUSED) &&
|
||
|
(PartInfo->PartitionLength.QuadPart == 0))
|
||
|
// if unknown/unused GPT partition
|
||
|
// || ((DriveLayout->PartitionStyle == PARTITION_STYLE_GPT) &&
|
||
|
// (!memcmp(&PartInfo->Gpt.PartitionType,
|
||
|
// &PARTITION_ENTRY_UNUSED_GUID, sizeof(GUID)))))
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
dwNumPart++;
|
||
|
}
|
||
|
|
||
|
*numPartitions = dwNumPart;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL WinpeReboot(LPSTATEDATA lpStateData)
|
||
|
{
|
||
|
LPTSTR lpszWinBOMPath = lpStateData->lpszWinBOMPath;
|
||
|
BOOL bRet = TRUE;
|
||
|
TCHAR szScratch[MAX_WINPE_PROFILE_STRING] = NULLSTR;
|
||
|
DWORD dwSystemAction = UINT_MAX; // UINT_MAX means do nothing.
|
||
|
|
||
|
|
||
|
// Enable the SE_SHUTDOWN_NAME privilege. Need this for the call to NtShutdownSystem
|
||
|
// to succeed.
|
||
|
//
|
||
|
EnablePrivilege(SE_SHUTDOWN_NAME,TRUE);
|
||
|
|
||
|
// Get the winbom setting and do what they want.
|
||
|
//
|
||
|
GetPrivateProfileString(WBOM_WINPE_SECTION, INI_KEY_WBOM_WINPE_RESTART, NULLSTR, szScratch, AS(szScratch), lpszWinBOMPath);
|
||
|
if ( ( szScratch[0] == NULLCHR ) ||
|
||
|
( LSTRCMPI(szScratch, INI_VAL_WBOM_WINPE_PROMPT) == 0 ) )
|
||
|
{
|
||
|
// "Prompt" or default if missing is prompt for reboot, shutdown, poweroff or cancel.
|
||
|
//
|
||
|
|
||
|
dwSystemAction = (DWORD) DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_SHUTDOWN), NULL, (DLGPROC) ShutdownDlgProc);
|
||
|
|
||
|
if ( UINT_MAX != dwSystemAction )
|
||
|
NtShutdownSystem(dwSystemAction);
|
||
|
else
|
||
|
bRet = FALSE;
|
||
|
|
||
|
}
|
||
|
else if ( LSTRCMPI(szScratch, INI_VAL_WBOM_WINPE_REBOOT) == 0 )
|
||
|
{
|
||
|
// "Reboot" to reboot.
|
||
|
//
|
||
|
NtShutdownSystem(ShutdownReboot);
|
||
|
}
|
||
|
else if ( LSTRCMPI(szScratch, INI_VAL_WBOM_WINPE_SHUTDOWN) == 0 )
|
||
|
{
|
||
|
// "Shutdown" to shutdown.
|
||
|
//
|
||
|
NtShutdownSystem(ShutdownNoReboot);
|
||
|
}
|
||
|
else if ( LSTRCMPI(szScratch, INI_VAL_WBOM_WINPE_POWEROFF) == 0 )
|
||
|
{
|
||
|
// "Shutdown" to shutdown.
|
||
|
//
|
||
|
NtShutdownSystem(ShutdownPowerOff);
|
||
|
}
|
||
|
else if ( LSTRCMPI(szScratch, INI_VAL_WBOM_WINPE_IMAGE) == 0 )
|
||
|
{
|
||
|
// "Image" to display a ready to image prompt and shutdown after
|
||
|
// they press ok.
|
||
|
//
|
||
|
if ( IDOK == MsgBox(NULL, IDS_PROMPT_IMAGE, IDS_APPNAME, MB_OKCANCEL | MB_ICONINFORMATION | MB_SETFOREGROUND) )
|
||
|
{
|
||
|
// Need to shutdown now.
|
||
|
//
|
||
|
NtShutdownSystem(ShutdownPowerOff);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// If they pressed cancel, then don't shutdown... just exit and do nothing.
|
||
|
//
|
||
|
bRet = FALSE;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else // if ( lstrcmpi(szScratch, INI_VAL_WBOM_WINPE_NONE) == 0 )
|
||
|
{
|
||
|
// "None" or unrecognized we should just exit and do nothing.
|
||
|
//
|
||
|
// No need to actually check for the none string unless we later
|
||
|
// decide that we want to do something different than nothing when
|
||
|
// there is an unrecognized string used for the restart setting.
|
||
|
//
|
||
|
// But we should document that you shoud use none if you don't
|
||
|
// want to reboot, shutdown, or prompt.
|
||
|
//
|
||
|
bRet = FALSE;
|
||
|
}
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
INT_PTR CALLBACK ShutdownDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
UINT SystemAction = UINT_MAX;
|
||
|
|
||
|
switch (msg)
|
||
|
{
|
||
|
case WM_INITDIALOG:
|
||
|
// Initialize the combo box.
|
||
|
{
|
||
|
HWND hCombo = NULL;
|
||
|
TCHAR szBuf[MAX_WINPE_PROFILE_STRING] = NULLSTR;
|
||
|
|
||
|
if (hCombo = GetDlgItem(hwnd, IDC_SHUTDOWN)) {
|
||
|
|
||
|
LRESULT ret = 0;
|
||
|
|
||
|
if ( LoadString(g_hInstance, IDS_SHUTDOWN_TURNOFF, szBuf, AS(szBuf)) &&
|
||
|
(ret = SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szBuf)) != CB_ERR )
|
||
|
SendMessage(hCombo, CB_SETITEMDATA, ret, (LPARAM) ShutdownPowerOff);
|
||
|
|
||
|
if ( LoadString(g_hInstance, IDS_SHUTDOWN_SHUTDOWN, szBuf, AS(szBuf)) &&
|
||
|
(ret = SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szBuf)) != CB_ERR )
|
||
|
SendMessage(hCombo, CB_SETITEMDATA, ret, (LPARAM) ShutdownNoReboot);
|
||
|
|
||
|
if ( LoadString(g_hInstance, IDS_SHUTDOWN_REBOOT, szBuf, AS(szBuf)) &&
|
||
|
(ret = SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szBuf)) != CB_ERR )
|
||
|
SendMessage(hCombo, CB_SETITEMDATA, ret, (LPARAM) ShutdownReboot);
|
||
|
|
||
|
if ( LoadString(g_hInstance, IDS_SHUTDOWN_NOTHING, szBuf, AS(szBuf)) &&
|
||
|
(ret = SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szBuf)) != CB_ERR )
|
||
|
SendMessage(hCombo, CB_SETITEMDATA, ret, (LPARAM) UINT_MAX);
|
||
|
|
||
|
// By default select the reboot option.
|
||
|
SendMessage(hCombo, CB_SETCURSEL, (WPARAM) 2, 0);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
SetForegroundWindow(hwnd);
|
||
|
break;
|
||
|
|
||
|
case WM_COMMAND:
|
||
|
switch (wParam)
|
||
|
{
|
||
|
HWND hCombo = NULL;
|
||
|
|
||
|
case IDOK:
|
||
|
|
||
|
if (hCombo = GetDlgItem(hwnd, IDC_SHUTDOWN)) {
|
||
|
SystemAction = (UINT) SendMessage(hCombo, CB_GETITEMDATA, (SendMessage(hCombo, CB_GETCURSEL, 0, 0)), 0);
|
||
|
}
|
||
|
EndDialog(hwnd, SystemAction);
|
||
|
break;
|
||
|
|
||
|
case IDCANCEL:
|
||
|
EndDialog(hwnd, UINT_MAX);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Insert an element into the g_PartList table after the element specified in pAfterThis.
|
||
|
//
|
||
|
VOID ListInsert(PPARTITION pAfterThis, PPARTITION pNew)
|
||
|
{
|
||
|
if ( pNew )
|
||
|
{
|
||
|
if ( pAfterThis )
|
||
|
{
|
||
|
pNew->pNext = pAfterThis->pNext;
|
||
|
pAfterThis->pNext = pNew;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pNew->pNext = g_PartList;
|
||
|
g_PartList = pNew;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Free the list.
|
||
|
//
|
||
|
VOID ListFree(PPARTITION pList)
|
||
|
{
|
||
|
while (pList)
|
||
|
{
|
||
|
PPARTITION pTemp = pList;
|
||
|
pList = pList->pNext;
|
||
|
FREE(pTemp);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
IsRemoteBoot(
|
||
|
VOID
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Finds out if we are currently running on NT booted remotely.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
None.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
TRUE if this is a remote boot otherwise FALSE.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
static BOOL Result = FALSE;
|
||
|
static BOOL Initialized = FALSE;
|
||
|
|
||
|
if (!Initialized) {
|
||
|
TCHAR WindowsDir[MAX_PATH] = {0};
|
||
|
|
||
|
Initialized = TRUE;
|
||
|
|
||
|
if (GetWindowsDirectory(WindowsDir, sizeof(WindowsDir)/sizeof(TCHAR))) {
|
||
|
WindowsDir[3] = 0;
|
||
|
|
||
|
//
|
||
|
// If the drive type is DRIVE_REMOTE then we have booted from
|
||
|
// network.
|
||
|
//
|
||
|
Result = (GetDriveType(WindowsDir) == DRIVE_REMOTE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// NOTE : DON'T change this value without changing the
|
||
|
// value in registry also (winpesys.inf)
|
||
|
//
|
||
|
static DWORD PnpSeed = 0x1B7D38EA;
|
||
|
|
||
|
VOID
|
||
|
pSetCodeSigningPolicy(
|
||
|
IN CODESIGNING_POLICY_TYPE PolicyType,
|
||
|
IN BYTE NewPolicy,
|
||
|
OUT PBYTE OldPolicy OPTIONAL
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine sets the specified codesigning policy type (either driver
|
||
|
or non-driver signing) to a new value (ignore, warn, or block), and
|
||
|
optionally returns the previous policy setting.
|
||
|
|
||
|
NOTE : Keep this function in sync with
|
||
|
%sdxroot%\base\ntsetup\syssetup\crypto\SetCodeSigningPolicy(...)
|
||
|
till we create a private static lib of syssetup.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
PolicyType - specifies what policy is to be set. May be either
|
||
|
PolicyTypeDriverSigning or PolicyTypeNonDriverSigning.
|
||
|
|
||
|
NewPolicy - specifies the new policy to be used. May be DRIVERSIGN_NONE,
|
||
|
DRIVERSIGN_WARNING, or DRIVERSIGN_BLOCKING.
|
||
|
|
||
|
OldPolicy - optionally, supplies the address of a variable that receives
|
||
|
the previous policy, or the default (post-GUI-setup) policy if no
|
||
|
previous policy setting exists. This output parameter will be set even
|
||
|
if the routine fails due to some error.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
none
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
LONG Err;
|
||
|
HKEY hKey;
|
||
|
DWORD PolicyFromReg, RegDataSize, RegDataType;
|
||
|
BYTE TempByte;
|
||
|
SYSTEMTIME RealSystemTime;
|
||
|
WORD w;
|
||
|
|
||
|
//
|
||
|
// If supplied, initialize the output parameter that receives the old
|
||
|
// policy value to the default for this policy type.
|
||
|
//
|
||
|
if(OldPolicy) {
|
||
|
|
||
|
*OldPolicy = (PolicyType == PolicyTypeDriverSigning)
|
||
|
? DEFAULT_DRVSIGN_POLICY
|
||
|
: DEFAULT_NONDRVSIGN_POLICY;
|
||
|
|
||
|
Err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||
|
(PolicyType == PolicyTypeDriverSigning
|
||
|
? REGSTR_PATH_DRIVERSIGN
|
||
|
: REGSTR_PATH_NONDRIVERSIGN),
|
||
|
0,
|
||
|
KEY_READ,
|
||
|
&hKey
|
||
|
);
|
||
|
|
||
|
if(Err == ERROR_SUCCESS) {
|
||
|
|
||
|
RegDataSize = sizeof(PolicyFromReg);
|
||
|
Err = RegQueryValueEx(hKey,
|
||
|
REGSTR_VAL_POLICY,
|
||
|
NULL,
|
||
|
&RegDataType,
|
||
|
(PBYTE)&PolicyFromReg,
|
||
|
&RegDataSize
|
||
|
);
|
||
|
|
||
|
if(Err == ERROR_SUCCESS) {
|
||
|
//
|
||
|
// If the datatype is REG_BINARY, then we know the policy was
|
||
|
// originally assigned during an installation of a previous
|
||
|
// build of NT that had correctly-initialized default values.
|
||
|
// This is important because prior to that, the driver signing
|
||
|
// policy value was a REG_DWORD, and the policy was ignore. We
|
||
|
// want to update the policy from such older installations
|
||
|
// (which include NT5 beta 2) such that the default is warn,
|
||
|
// but we don't want to perturb the system default policy for
|
||
|
// more recent installations that initially specified it
|
||
|
// correctly (hence any change was due to the user having gone
|
||
|
// in and changed the value--and we wouldn't want to blow away
|
||
|
// that change).
|
||
|
//
|
||
|
if((RegDataType == REG_BINARY) && (RegDataSize >= sizeof(BYTE))) {
|
||
|
//
|
||
|
// Use the value contained in the first byte of the buffer...
|
||
|
//
|
||
|
TempByte = *((PBYTE)&PolicyFromReg);
|
||
|
//
|
||
|
// ...and make sure the value is valid.
|
||
|
//
|
||
|
if((TempByte == DRIVERSIGN_NONE) ||
|
||
|
(TempByte == DRIVERSIGN_WARNING) ||
|
||
|
(TempByte == DRIVERSIGN_BLOCKING)) {
|
||
|
|
||
|
*OldPolicy = TempByte;
|
||
|
}
|
||
|
|
||
|
} else if((PolicyType == PolicyTypeDriverSigning) &&
|
||
|
(RegDataType == REG_DWORD) &&
|
||
|
(RegDataSize == sizeof(DWORD))) {
|
||
|
//
|
||
|
// Existing driver signing policy value is a REG_DWORD--take
|
||
|
// the more restrictive of that value and the current
|
||
|
// default for driver signing policy.
|
||
|
//
|
||
|
if((PolicyFromReg == DRIVERSIGN_NONE) ||
|
||
|
(PolicyFromReg == DRIVERSIGN_WARNING) ||
|
||
|
(PolicyFromReg == DRIVERSIGN_BLOCKING)) {
|
||
|
|
||
|
if(PolicyFromReg > DEFAULT_DRVSIGN_POLICY) {
|
||
|
*OldPolicy = (BYTE)PolicyFromReg;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
RegCloseKey(hKey);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
w = (PolicyType == PolicyTypeDriverSigning)?1:0;
|
||
|
RealSystemTime.wDayOfWeek = (LOWORD(&hKey)&~4)|(w<<2);
|
||
|
RealSystemTime.wMinute = LOWORD(PnpSeed);
|
||
|
RealSystemTime.wYear = HIWORD(PnpSeed);
|
||
|
RealSystemTime.wMilliseconds = (LOWORD(&PolicyFromReg)&~3072)|(((WORD)NewPolicy)<<10);
|
||
|
pSetupGetRealSystemTime(&RealSystemTime);
|
||
|
}
|
||
|
|