Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

735 lines
20 KiB

/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
asr_dlg.cpp
Abstract:
Top level code to backup and restore information about the volumes on
a system. This module handles the main application dialogue, including
parsing the command-line, and updating the progress bar and UI status
text.
Authors:
Steve DeVos (Veritas) (v-stevde) 15-May-1998
Guhan Suriyanarayanan (guhans) 21-Aug-1999
Environment:
User-mode only.
Revision History:
15-May-1998 v-stevde Initial creation
21-Aug-1999 guhans Cleaned up and re-wrote this module.
--*/
#include "stdafx.h"
#include "asr_fmt.h"
#include "asr_dlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
BOOLEAN g_bQuickFormat = FALSE;
/////////////////////////////////////////////////////////////////////////////
// CAsr_fmtDlg dialog
CAsr_fmtDlg::CAsr_fmtDlg(CWnd* pParent /*=NULL*/)
: CDialog(CAsr_fmtDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CAsr_fmtDlg)
//}}AFX_DATA_INIT
}
void CAsr_fmtDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAsr_fmtDlg)
DDX_Control(pDX, IDC_PROGRESS, m_Progress);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAsr_fmtDlg, CDialog)
//{{AFX_MSG_MAP(CAsr_fmtDlg)
//}}AFX_MSG_MAP
// manually added message handlers (for user-defined messages) should be added OUTSIDE
// the AFX_MSG_MAP part above
ON_MESSAGE(WM_WORKER_THREAD_DONE, OnWorkerThreadDone)
ON_MESSAGE(WM_UPDATE_STATUS_TEXT, OnUpdateStatusText)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CAsr_fmtDlg message handlers
// ON_BN_CLICKED(IDOK, OnWorkerThreadDone)
BOOL CAsr_fmtDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// initialize the progress range and start posiiton
m_Progress.SetRange(0, 100);
m_Progress.SetPos(0);
m_ProgressPosition = 0;
// Launch the worker thread.
CreateThread(NULL, // no sid
0, // no initial stack size
(LPTHREAD_START_ROUTINE) CAsr_fmtDlg::DoWork,
this, // parameter
0, // no flags
NULL // no thread ID
);
return TRUE; // return TRUE unless you set the focus to a control
}
LRESULT
CAsr_fmtDlg::OnWorkerThreadDone(
WPARAM wparam,
LPARAM lparam
)
{
EndDialog(m_dwEndStatus);
return 0;
}
LRESULT
CAsr_fmtDlg::OnUpdateStatusText(
WPARAM wparam,
LPARAM lparam
)
{
SetDlgItemText(IDC_STATUS_TEXT, m_strStatusText);
m_Progress.SetPos(m_ProgressPosition);
return 0;
}
/**
Name: DoWork()
Description: This function runs as a thread launched form the Init
of the dialog. This function determines what needs to be done, then
calls the appropraite function to do the work.
Modified: 8/31/1998
Returns: TRUE
Notes: If an error occurs EndDialog will be called with the
exit status.
Declaration:
**/
long
CAsr_fmtDlg::DoWork(
CAsr_fmtDlg *_this
)
{
ASRFMT_CMD_OPTION cmdOption = cmdUndefined;
cmdOption = _this->ParseCommandLine();
((CAsr_fmtDlg *)_this)->m_AsrState = NULL;
_this->m_dwEndStatus = ERROR_SUCCESS;
switch (cmdOption) {
case cmdBackup: {
if (!(_this->BackupState())) {
_this->m_dwEndStatus = GetLastError();
}
break;
}
case cmdRestore: {
if (!(_this->RestoreState())) {
_this->m_dwEndStatus = GetLastError();
}
break;
}
case cmdDisplayHelp: {
_this->m_dwEndStatus = ERROR_INVALID_FUNCTION; // display help ...
break;
}
}
if (ERROR_INVALID_FUNCTION != _this->m_dwEndStatus) { // display help ...
_this->PostMessage(WM_WORKER_THREAD_DONE, 0, 0);
}
return 0;
}
/**
Name: BackupState()
Description: This function reads the current state file to get
the current data for the sections to modify. It then updates
[VOLUMES], [REMOVABLEMEDIA] and [COMMANDS] sections.
Notes: If an error occurs an Error message popup is provided to
the user.
Declaration:
**/
BOOL
CAsr_fmtDlg::BackupState()
{
BOOL result = FALSE;
HANDLE hHeap = GetProcessHeap();
int i = 0;
CString strPleaseWait;
strPleaseWait.LoadString(IDS_PLEASE_WAIT_BACKUP);
SetDlgItemText(IDC_PROGRESS_TEXT, strPleaseWait);
m_AsrState = (PASRFMT_STATE_INFO) HeapAlloc(
hHeap,
HEAP_ZERO_MEMORY,
sizeof (ASRFMT_STATE_INFO)
);
//
// The only purpose of the for loops below are to slow down the
// UI and make the progress bar proceed smoothly, so that the user
// can read the dialogue box on screen.
//
m_strStatusText.LoadString(IDS_QUERY_SYS_FOR_INFO);
for (i = 3; i < 15; i++) {
m_ProgressPosition = i;
PostMessage(WM_UPDATE_STATUS_TEXT);
Sleep(50);
}
if (m_AsrState) {
result = BuildStateInfo(m_AsrState);
}
if (!result) {
goto EXIT;
}
//
// The only purpose of the for loops below are to slow down the
// UI and make the progress bar proceed smoothly, so that the user
// can read the dialogue box on screen.
//
m_strStatusText.LoadString(IDS_QUERY_SYS_FOR_INFO);
for (i = 15; i < 45; i++) {
m_ProgressPosition = i;
PostMessage(WM_UPDATE_STATUS_TEXT);
Sleep(50);
}
//
// Pretend we're doing something else (change UI text)
//
m_strStatusText.LoadString(IDS_BUILDING_VOL_LIST);
for (i = 45; i < 80; i++) {
m_ProgressPosition = i;
PostMessage(WM_UPDATE_STATUS_TEXT);
Sleep(50);
}
m_strStatusText.LoadString(IDS_WRITING_TO_SIF);
for (i = 80; i < 90; i++) {
m_ProgressPosition = i;
PostMessage(WM_UPDATE_STATUS_TEXT);
Sleep(50);
}
result = WriteStateInfo(m_dwpAsrContext, m_AsrState);
if (!result) {
goto EXIT;
}
m_strStatusText.LoadString(IDS_WRITING_TO_SIF);
for (i = 90; i < 101; i++) {
m_ProgressPosition = i;
PostMessage(WM_UPDATE_STATUS_TEXT);
Sleep(50);
}
EXIT:
FreeStateInfo(&m_AsrState);
return result;
}
/**
Name: RestoreState()
Description: This function restores the state found in the [VOLUMES]
section of the asr.sif file. The state restored includs:
the drive letter.
If drive is inaccessible it is formated.
the volume label.
Notes: If an error occurs an Error message popup is provided to
the user.
**/
BOOL
CAsr_fmtDlg::RestoreState()
{
BOOL bErrorsEncountered = FALSE,
result = TRUE;
CString strPleaseWait;
strPleaseWait.LoadString(IDS_PLEASE_WAIT_RESTORE);
SetDlgItemText(IDC_PROGRESS_TEXT, strPleaseWait);
m_ProgressPosition = 0;
m_strStatusText.LoadString(IDS_READING_SIF);
PostMessage(WM_UPDATE_STATUS_TEXT);
AsrfmtpInitialiseErrorFile(); // in case we need to log error messages
//
// 1. Read the state file
//
result = ReadStateInfo( (LPCTSTR)m_strSifPath, &m_AsrState);
if (!result || !m_AsrState) {
DWORD status = GetLastError();
CString strErrorTitle;
CString strErrorMessage;
CString strErrorFormat;
strErrorTitle.LoadString(IDS_ERROR_TITLE);
strErrorFormat.LoadString(IDS_ERROR_NO_DRSTATE);
strErrorMessage.Format(strErrorFormat, (LPCTSTR)m_strSifPath, status);
AsrfmtpLogErrorMessage(_SeverityWarning, (LPCTSTR)strErrorMessage);
AsrfmtpCloseErrorFile();
return FALSE;
}
//
// 2. Loop through all the volumes listed in the state file.
//
PASRFMT_VOLUME_INFO pVolume = m_AsrState->pVolume;
PASRFMT_REMOVABLE_MEDIA_INFO pMedia = m_AsrState->pRemovableMedia;
UINT driveType = DRIVE_UNKNOWN;
PWSTR lpDrive = NULL; // Display string, of the form \DosDevices\C: or \??\Volume{Guid}
DWORD cchVolumeGuid = 0;
WCHAR szVolumeGuid[MAX_PATH + 1];
int sizeIncrement = 0, i = 0;
BOOL first = TRUE, isIntact = FALSE, isLabelIntact = TRUE;
//
// We need to first set all the guids a volume has, then try setting the drive
// letters. Also, we need to go through the guid loop twice, to handle this case:
//
// Consider a sif where we had the entries
// ... \vol1, \vol2
// ... \vol1, \x:
// ... \vol1, \vol3
//
// where vol1, vol2 and vol3 are volume guids (\??\Volume{Guid}),
// and x: is the drive letter (\DosDevices\X:)
//
// Now, our list will contain three nodes:
// -->(vol1, vol3)-->(vol1, x:)-->(vol1, vol2)-->/
//
// The problem is, the partition could currently have the guid vol2. (since
// it is free to have any one of the three guids).
//
// If we only went through the loop once, we'll try to map vol1 to vol3, or
// vice-versa if vol1 doesn't exist. Since neither exist yet, we would've
// complained to the user.
//
// The advantage to doing it twice is this: the first time, since neither vol1
// nor vol3 exist yet, we'll skip that node. Then we'll skip the drive letter for
// now (since we're only doing guids), and eventually we'll map vol2 to vol1.
//
// The second time, we'll find vol1 exists (mapped to vol2), and we'll be
// able to map vol1 to vol3. In a later loop, vol1 will also get the drive
// letter X, and all's well.
//
// By the way, we could optimise this by creating a better data structure,
// but it's too late in the game now for that. If the performance is
// really bad, we could come back to this.
//
if (m_AsrState->countVolume > 1) {
sizeIncrement = 50 / (m_AsrState->countVolume - 1);
}
else {
sizeIncrement = 100;
}
m_ProgressPosition = 0;
for (i = 0; i < 2; i++) {
pVolume = m_AsrState->pVolume;
while (pVolume) {
m_ProgressPosition += sizeIncrement;
m_strStatusText.Format(IDS_REST_SYM_LINKS, pVolume->szGuid);
PostMessage(WM_UPDATE_STATUS_TEXT);
if ((!pVolume->IsDosPathAssigned) &&
ASRFMT_LOOKS_LIKE_VOLUME_GUID(pVolume->szDosPath, (wcslen(pVolume->szDosPath) * sizeof(WCHAR)))
) {
pVolume->IsDosPathAssigned = SetDosName(pVolume->szGuid, pVolume->szDosPath);
if (!pVolume->IsDosPathAssigned) {
pVolume->IsDosPathAssigned = SetDosName(pVolume->szDosPath, pVolume->szGuid);
}
}
pVolume = pVolume->pNext;
}
}
pVolume = m_AsrState->pVolume;
FormatInitialise();
while (pVolume) {
lpDrive = ((wcslen(pVolume->szDosPath) > 0) ? pVolume->szDosPath : pVolume->szGuid);
//
// Check if the drive is accessible. If not, we log an error message
// and continue. GetDriveType requires the name in the DOS name space, so we
// convert our GUID (NT name space) to the required format first
//
cchVolumeGuid = wcslen(pVolume->szGuid);
if (cchVolumeGuid >= MAX_PATH) {
cchVolumeGuid = MAX_PATH - 1;
}
wcsncpy(szVolumeGuid, pVolume->szGuid, cchVolumeGuid);
szVolumeGuid[1] = L'\\';
szVolumeGuid[cchVolumeGuid] = L'\\'; // Trailing back-slash
szVolumeGuid[cchVolumeGuid+1] = L'\0';
driveType = GetDriveType(szVolumeGuid);
if (DRIVE_NO_ROOT_DIR == driveType) {
CString strErrorTitle;
CString strErrorMessage;
CString strErrorFormat;
strErrorTitle.LoadString(IDS_ERROR_TITLE);
strErrorFormat.LoadString(IDS_ERROR_MISSING_VOL);
strErrorMessage.Format(strErrorFormat, (PWSTR) pVolume->szGuid);
AsrfmtpLogErrorMessage(_SeverityWarning, (LPCTSTR)strErrorMessage);
bErrorsEncountered = TRUE;
}
if (DRIVE_FIXED != driveType) {
//
// Strange. The volumes section should have only listed the drives that
// were fixed (At backup time). This could probably mean that a volume that
// used to be on a fixed drive is now on a removable drive?!
//
pVolume = pVolume->pNext;
continue;
}
//
// Set the drive letter of the volume
//
result = TRUE;
if (!pVolume->IsDosPathAssigned){
m_ProgressPosition = 0;
m_strStatusText.Format(IDS_REST_DRIVE_LETTER, lpDrive);
PostMessage(WM_UPDATE_STATUS_TEXT);
result = SetDosName(pVolume->szGuid, pVolume->szDosPath);
}
if (!result) {
CString strErrorTitle;
CString strErrorMessage;
CString strErrorFormat;
strErrorTitle.LoadString(IDS_ERROR_TITLE);
strErrorFormat.LoadString(IDS_ERROR_MOUNTING);
strErrorMessage.Format(strErrorFormat, (PWSTR) pVolume->szDosPath, (PWSTR) pVolume->szGuid);
AsrfmtpLogErrorMessage(_SeverityWarning, (LPCTSTR)strErrorMessage);
bErrorsEncountered = TRUE;
pVolume = pVolume->pNext;
continue;
}
//
// Check if the volume needs to be formatted
//
m_ProgressPosition = 0;
m_strStatusText.Format(IDS_CHECKING_VOLUME, lpDrive);
PostMessage(WM_UPDATE_STATUS_TEXT);
isIntact = IsFsTypeOkay(pVolume, &isLabelIntact);
if (isIntact) {
isIntact = IsVolumeIntact(pVolume);
}
//
// Format the volume if needed
//
if (!isIntact && FormatVolume(pVolume)) {
isLabelIntact = FALSE;
m_ProgressPosition = 0;
m_strStatusText.Format(IDS_FORMATTING_VOLUME, lpDrive);
PostMessage(WM_UPDATE_STATUS_TEXT);
//
// FormatVolume is asynchronous.
//
first = TRUE;
while (g_bFormatInProgress) {
if (g_iFormatPercentComplete >= 100) {
if (first) {
m_ProgressPosition = 100;
m_strStatusText.Format(IDS_CREATING_FS_STRUCT, lpDrive);
PostMessage(WM_UPDATE_STATUS_TEXT);
first = FALSE;
}
}
else {
m_Progress.SetPos(g_iFormatPercentComplete);
}
Sleep(100);
}
if (!g_bFormatSuccessful) {
CString strErrorTitle;
CString strErrorMessage;
CString strErrorFormat;
strErrorTitle.LoadString(IDS_ERROR_TITLE);
strErrorFormat.LoadString(IDS_ERROR_FORMATTING);
strErrorMessage.Format(strErrorFormat, (PWSTR) lpDrive);
AsrfmtpLogErrorMessage(_SeverityWarning, (LPCTSTR)strErrorMessage);
bErrorsEncountered = TRUE;
pVolume = pVolume->pNext;
continue;
}
//
// Force the file-system to be mounted
//
MountFileSystem(pVolume);
}
//
// Set the volume label if it isn't intact
//
if (!isLabelIntact) {
m_ProgressPosition = 0;
m_strStatusText.Format(IDS_REST_VOL_LABEL, lpDrive);
PostMessage(WM_UPDATE_STATUS_TEXT);
if ((wcslen(pVolume->szFsName) > 0) &&
!SetVolumeLabel(szVolumeGuid, pVolume->szLabel)) {
bErrorsEncountered = TRUE;
pVolume = pVolume->pNext;
continue;
}
}
pVolume = pVolume->pNext;
}
FormatCleanup();
while (pMedia) {
lpDrive = ((wcslen(pMedia->szDosPath) > 0) ? pMedia->szDosPath : pMedia->szVolumeGuid);
//
// set the drive letter
//
m_ProgressPosition = 0;
m_strStatusText.Format(IDS_REST_DRIVE_LETTER, lpDrive);
PostMessage(WM_UPDATE_STATUS_TEXT);
result = SetRemovableMediaGuid(pMedia->szDevicePath, pMedia->szVolumeGuid);
if (result) {
result = SetDosName(pMedia->szVolumeGuid, pMedia->szDosPath);
}
if (!result) {
CString strErrorTitle;
CString strErrorMessage;
CString strErrorFormat;
strErrorTitle.LoadString(IDS_ERROR_TITLE);
strErrorFormat.LoadString(IDS_ERROR_MOUNTING);
strErrorMessage.Format(IDS_ERROR_MOUNTING, (PWSTR) pMedia->szDosPath, (PWSTR) pMedia->szVolumeGuid);
AsrfmtpLogErrorMessage(_SeverityWarning, (LPCTSTR)strErrorMessage);
// ignore failures setting drive letter on CD.
// bErrorsEncountered = TRUE;
}
pMedia = pMedia->pNext;
}
AsrfmtpCloseErrorFile();
return (bErrorsEncountered ? FALSE : TRUE);
}
inline
BOOL
IsGuiModeAsr()
{
WCHAR szAsrFlag[20];
//
// If (and only if) this is GUI-mode ASR, the ASR_C_CONTEXT
// environment variable is set to "AsrInProgress"
//
return (GetEnvironmentVariable(L"ASR_C_CONTEXT", szAsrFlag, 20) &&
!wcscmp(szAsrFlag, L"AsrInProgress"));
}
/**
Name: ParseCommandLine()
Description: This function reads the comand line and looks for the
"backup" or "restore" options.
Modified: 8/31/1998
Returns: cmdBackup, cmdRestore, or cmdDisplayHelp.
Notes: If neither backup or restore are found, then the usage
is displayed in the error box.
Declaration:
**/
ASRFMT_CMD_OPTION
CAsr_fmtDlg::ParseCommandLine()
{
CString cmd;
m_dwpAsrContext = 0;
cmd = GetCommandLine();
cmd.MakeLower();
if (cmd.Find(TEXT("/backup")) != -1) {
int pos = cmd.Find(TEXT("/context="));
if (pos > -1) {
#ifdef _IA64_
_stscanf(cmd.Mid(pos, cmd.GetLength() - pos + 1), TEXT("/context=%I64u"), &m_dwpAsrContext);
#else
_stscanf(cmd.Mid(pos, cmd.GetLength() - pos + 1), TEXT("/context=%lu"), &m_dwpAsrContext);
#endif
return cmdBackup;
}
} else if (cmd.Find(TEXT("/restore")) != -1) {
if (cmd.Find(TEXT("/full")) != -1) {
g_bQuickFormat = FALSE;
}
else if (cmd.Find(TEXT("/quick")) != -1) {
g_bQuickFormat = TRUE;
}
else if (IsGuiModeAsr()) {
g_bQuickFormat = FALSE;
}
else {
g_bQuickFormat = TRUE;
}
int pos = cmd.Find(TEXT("/sifpath="));
if (pos > -1) {
_stscanf(cmd.Mid(pos, cmd.GetLength() - pos + 1), TEXT("/sifpath=%ws"), m_strSifPath.GetBuffer(1024));
m_strSifPath.ReleaseBuffer();
return cmdRestore;
}
}
CString strErrorTitle;
CString strErrorMessage;
INT space_offset;
strErrorTitle.LoadString(IDS_ERROR_TITLE);
strErrorMessage.LoadString(IDS_ERROR_USAGE);
space_offset = cmd.Find(' ');
if (space_offset >0) {
cmd = cmd.Left(cmd.Find(' '));
}
SetDlgItemText(IDC_PROGRESS_TEXT, strErrorMessage);
CWnd *pText = GetDlgItem(IDC_STATUS_TEXT);
pText->ShowWindow(SW_HIDE);
CButton *pButton = (CButton*)GetDlgItem(IDOK);
pButton->ShowWindow(SW_SHOW);
pButton->SetState(TRUE);
pButton->SetCheck(TRUE);
CWnd *pBar = GetDlgItem(IDC_PROGRESS);
pBar->ShowWindow(SW_HIDE);
return cmdDisplayHelp;
}