2294 lines
66 KiB
C
2294 lines
66 KiB
C
/*++
|
||
|
||
Copyright (c) 1997-1999 Microsoft Corporation
|
||
|
||
Module Name:
|
||
frs.c
|
||
|
||
Abstract:
|
||
This module is a development tool. It exercises the dcpromo and poke
|
||
APIs.
|
||
|
||
Author:
|
||
Billy J. Fuller 12-Dec-1997
|
||
|
||
Environment
|
||
User mode winnt
|
||
|
||
--*/
|
||
#include <ntreppch.h>
|
||
#pragma hdrstop
|
||
#include <frs.h>
|
||
#include <ntfrsapi.h>
|
||
|
||
#define FREE(_x_) { if (_x_) LocalFree(_x_); _x_ = NULL; }
|
||
|
||
|
||
VOID
|
||
Win32ToMsg (
|
||
IN PWCHAR Prefix,
|
||
IN DWORD WStatus
|
||
)
|
||
|
||
/*++
|
||
Routine Description:
|
||
Translate a error code into a error message using FormatMessage()
|
||
and print to stderr. If no message is available, the error code
|
||
is printed in decimal and hex.
|
||
|
||
Arguments:
|
||
Prefix - prefix to error message
|
||
WStatus - Standard win32 error code.
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
DWORD NumChar;
|
||
PWCHAR Buffer;
|
||
|
||
if (WIN_SUCCESS(WStatus)) {
|
||
return;
|
||
}
|
||
|
||
// Use the system formatter for standard error codes
|
||
NumChar = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
|
||
FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
||
NULL,
|
||
WStatus,
|
||
0,
|
||
(PWCHAR)&Buffer,
|
||
0,
|
||
NULL);
|
||
if (NumChar) {
|
||
fprintf(stderr, "%ws %ws\n", Prefix, Buffer);
|
||
} else {
|
||
fprintf(stderr, "%ws Status %d (0x%08x)\n", Prefix, WStatus, WStatus);
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
Usage(
|
||
IN DWORD ExitStatus
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Print usage and exit
|
||
|
||
Arguments:
|
||
ExitStatus - exits with this status
|
||
|
||
Return Value:
|
||
Exit(ExitStatus)
|
||
--*/
|
||
{
|
||
printf("frs restore | backup [/all /auth /nonauth /primary /system /ds /normal /key /restart] [dir nonauth|primary|auth ....]\n");
|
||
printf("\t = excercise the backup/restore api\n");
|
||
printf("\t WARNING - deletes database\n");
|
||
printf("\trestore = excercise restore\n");
|
||
printf("\tbackup = excercise backup\n");
|
||
printf("\t/all = set all flag (all dirs)\n");
|
||
printf("\t/auth = set auth flag\n");
|
||
printf("\t/nonauth = set nonauth flag\n");
|
||
printf("\t/primary = set primary flag\n");
|
||
printf("\t/system = set system flag\n");
|
||
printf("\t/ds = set active directory flag\n");
|
||
printf("\t/normal = set normal flag\n");
|
||
printf("\t/key = expect keypath-when-done\n");
|
||
printf("\t/restart = set restart-service-when-done\n");
|
||
printf("\tSUPPORTED = restore /system /all /nonauth /restart\n");
|
||
printf("\tSUPPORTED = restore /system /all /primary /restart\n");
|
||
printf("\tSUPPORTED = restore /system /all /nonauth /key \n");
|
||
printf("\tSUPPORTED = restore /system /all /primary /key \n");
|
||
printf("\tSUPPORTED = restore /ds /all /nonauth /restart\n");
|
||
printf("\tSUPPORTED = restore /ds /all /primary /restart\n");
|
||
printf("\tSUPPORTED = restore /ds /all /nonauth /key \n");
|
||
printf("\tSUPPORTED = restore /ds /all /primary /key \n");
|
||
printf("\tSUPPORTED = restore /ds /all /nonauth /restart dir primary|nonauth ...\n");
|
||
printf("\tSUPPORTED = restore /ds /all /primary /restart dir primary|nonauth ...\n");
|
||
printf("\tSUPPORTED = restore /ds /all /nonauth /key dir primary|nonauth ...\n");
|
||
printf("\tSUPPORTED = restore /ds /all /primary /key dir primary|nonauth ...\n");
|
||
printf("\tSUPPORTED = restore /ds /nonauth /restart dir primary|nonauth ...\n");
|
||
printf("\tSUPPORTED = restore /ds /primary /restart dir primary|nonauth ...\n");
|
||
printf("\tSUPPORTED = restore /ds /nonauth /key dir primary|nonauth ...\n");
|
||
printf("\tSUPPORTED = restore /ds /primary /key dir primary|nonauth ...\n");
|
||
printf("\tSUPPORTED = restore /normal /all /auth\n");
|
||
printf("\tSUPPORTED = backup /normal\n");
|
||
printf("\n");
|
||
printf("frs install stagepath [targetpath]\n");
|
||
printf("\t = install the staging file\n");
|
||
printf("\tstagepath = path of staging file.\n");
|
||
printf("\ttargetpath= path of target file to OVERWRITE!.\n");
|
||
printf("\n");
|
||
printf("frs [idtable|inlog|outlog] [computer]\n");
|
||
printf("\t = enumerate the service's idtable/inlog/outlog \n");
|
||
printf("\tcomputer = talk to the NtFrs service on this machine.\n");
|
||
printf("\n");
|
||
printf("frs [memory|threads|stage] [computer]\n");
|
||
printf("\t = list the service's memory usage\n");
|
||
printf("\tcomputer = talk to the NtFrs service on this machine.\n");
|
||
printf("\n");
|
||
printf("frs ds [computer]\n");
|
||
printf("\t = list the service's view of the DS\n");
|
||
printf("\tcomputer = talk to the NtFrs service on this machine.\n");
|
||
printf("\n");
|
||
printf("frs sets [computer]\n");
|
||
printf("\t = list the active replica sets\n");
|
||
printf("\tcomputer = talk to the NtFrs service on this machine.\n");
|
||
printf("\n");
|
||
printf("frs version [computer]\n");
|
||
printf("\t = list the api and service versions\n");
|
||
printf("\tcomputer = talk to the NtFrs service on this machine.\n");
|
||
printf("\n");
|
||
printf("frs poll [/quickly[=[N]]] [/slowly[=[N]]] [/now] [computer]\n");
|
||
printf("\t = list the current polling intervals.\n");
|
||
printf("\tnow = Poll now.\n");
|
||
printf("\tquickly = Poll quickly until stable configuration retrieved.\n");
|
||
printf("\tquickly= = Poll quickly every default minutes.\n");
|
||
printf("\tquickly=N = Poll quickly every N minutes.\n");
|
||
printf("\tslowly = Poll slowly until stable configuration retrieved.\n");
|
||
printf("\tslowly= = Poll slowly every default minutes.\n");
|
||
printf("\tslowly=N = Poll slowly every N minutes.\n");
|
||
printf("\tcomputer = talk to the NtFrs service on this machine.\n");
|
||
printf("\n");
|
||
printf("frs promote Parent Account Password Set Type Primary Stage Root\n");
|
||
printf("\tParent = RPC bindable name of parent DC.\n");
|
||
printf("\tAccount = Account on Parent.\n");
|
||
printf("\tPassword = Password for Account on Parent.\n");
|
||
printf("\tSet = Name of replica set.\n");
|
||
printf("\tType = Type of replica set (Enterprise or Domain).\n");
|
||
printf("\tPrimary = Is this the primary member? (1=yes or 0=no)\n");
|
||
printf("\tStage = Staging path.\n");
|
||
printf("\tRoot = Root path.\n");
|
||
printf("\n");
|
||
printf("frs demote Set\n");
|
||
printf("\tSet = Name of replica set.\n");
|
||
printf("\n");
|
||
printf("frs promotesysvols Parent Account Password PrimaryEnterprise PrimaryDomain Stage RootEnterprise RootDomain\n");
|
||
printf("\tParent = RPC bindable name of parent DC.\n");
|
||
printf("\tAccount = Account on Parent.\n");
|
||
printf("\tPassword = Password for Account on Parent.\n");
|
||
printf("\tPrimaryEnterprise = Is this the primary member? (1=yes or 0=no)\n");
|
||
printf("\tPrimaryDomain = Is this the primary member? (1=yes or 0=no)\n");
|
||
printf("\tStage = Staging path.\n");
|
||
printf("\tRootEnterprise = Root path.\n");
|
||
printf("\tRootDomain = Root path.\n");
|
||
printf("\n");
|
||
printf("frs demotesysvols\n");
|
||
|
||
exit(ExitStatus);
|
||
}
|
||
|
||
|
||
PWCHAR *
|
||
ConvertArgv(
|
||
DWORD argc,
|
||
PCHAR *argv
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Convert short char argv into wide char argv
|
||
|
||
Arguments:
|
||
argc - From main
|
||
argv - From main
|
||
|
||
Return Value:
|
||
Address of the new argv
|
||
--*/
|
||
{
|
||
PWCHAR *wideargv;
|
||
|
||
wideargv = LocalAlloc(LMEM_FIXED, (argc + 1) * sizeof(PWCHAR));
|
||
if (wideargv == NULL) {
|
||
fprintf(stderr, "Can't get memory; Win32 Status %d\n",
|
||
GetLastError());
|
||
exit(1);
|
||
}
|
||
wideargv[argc] = NULL;
|
||
|
||
while (argc-- >= 1) {
|
||
wideargv[argc] = LocalAlloc(LMEM_FIXED,
|
||
(strlen(argv[argc]) + 1) * sizeof(WCHAR));
|
||
if (wideargv[argc] == NULL) {
|
||
fprintf(stderr, "Can't get memory; Win32 Status %d\n",
|
||
GetLastError());
|
||
exit(1);
|
||
}
|
||
wsprintf(wideargv[argc], L"%hs", argv[argc]);
|
||
FRS_WCSLWR(wideargv[argc]);
|
||
}
|
||
return wideargv;
|
||
}
|
||
|
||
|
||
DWORD
|
||
Display(
|
||
IN PWCHAR StrW
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Display the string
|
||
|
||
Arguments:
|
||
StrW
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
printf("DISPLAY %ws\n", StrW);
|
||
return ERROR_SUCCESS;
|
||
}
|
||
|
||
|
||
DWORD
|
||
FrsErrorCallBack(
|
||
IN PWCHAR Msg,
|
||
IN DWORD WStatus
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
--*/
|
||
{
|
||
fprintf(stderr, "%ws (%d)\n", Msg, WStatus);
|
||
return ERROR_SUCCESS;
|
||
}
|
||
|
||
|
||
VOID
|
||
ProcessPromote(
|
||
IN DWORD argc,
|
||
IN PWCHAR *Argv
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Process the command line for the subcommand promote.
|
||
|
||
Arguments:
|
||
argc
|
||
Argv
|
||
|
||
Return Value:
|
||
Exits with 0 if everything went okay. Otherwise, 1.
|
||
--*/
|
||
{
|
||
DWORD WStatus;
|
||
PWCHAR Parent;
|
||
PWCHAR Account;
|
||
PWCHAR Password;
|
||
PWCHAR Set;
|
||
PWCHAR Type;
|
||
PWCHAR Primary;
|
||
PWCHAR Stage;
|
||
PWCHAR Root;
|
||
DWORD IsPrimary;
|
||
|
||
if (argc != 10) {
|
||
Usage(1);
|
||
}
|
||
|
||
Parent = Argv[2];
|
||
Account = Argv[3];
|
||
Password = Argv[4];
|
||
Set = Argv[5];
|
||
Type = Argv[6];
|
||
Primary = Argv[7];
|
||
Stage = Argv[8];
|
||
Root = Argv[9];
|
||
|
||
//
|
||
// No account; use impersonation
|
||
//
|
||
if (Account && !*Account) {
|
||
Account = NULL;
|
||
Password = NULL;
|
||
}
|
||
|
||
printf("%ws %ws %ws ... %ws\n",
|
||
Argv[0], Argv[1], Parent, Root);
|
||
|
||
printf("PROMOTE WITH COMMIT\n");
|
||
|
||
//
|
||
// Check params
|
||
//
|
||
if (_wcsicmp(Primary, L"0") && _wcsicmp(Primary, L"1")) {
|
||
printf("Primary must be 0 or 1; not %ws\n", Primary);
|
||
Usage(1);
|
||
}
|
||
if (_wcsicmp(Type, NTFRSAPI_REPLICA_SET_TYPE_ENTERPRISE) &&
|
||
_wcsicmp(Type, NTFRSAPI_REPLICA_SET_TYPE_DOMAIN)) {
|
||
printf("Type must be Enterprise or Domain; not %ws\n", Type);
|
||
Usage(1);
|
||
}
|
||
IsPrimary = wcstoul(Primary, NULL, 10);
|
||
|
||
//
|
||
// Prepare
|
||
//
|
||
WStatus = NtFrsApi_PrepareForPromotionW( FrsErrorCallBack );
|
||
if (WStatus == ERROR_SUCCESS) {
|
||
printf("success prepare\n");
|
||
} else {
|
||
printf("failure prepare %08x\n", WStatus);
|
||
Win32ToMsg (L"Promote:", WStatus);
|
||
}
|
||
|
||
//
|
||
// Start
|
||
//
|
||
WStatus = NtFrsApi_StartPromotionW(Parent,
|
||
Account,
|
||
Password,
|
||
Display,
|
||
FrsErrorCallBack,
|
||
Set,
|
||
Type,
|
||
IsPrimary,
|
||
Stage,
|
||
Root);
|
||
if (WStatus == ERROR_SUCCESS) {
|
||
printf("success start\n");
|
||
} else {
|
||
printf("failure start %08x\n", WStatus);
|
||
Win32ToMsg (L"Promote:", WStatus);
|
||
}
|
||
|
||
//
|
||
// Wait
|
||
//
|
||
printf("Waiting on promotion\n");
|
||
WStatus = NtFrsApi_WaitForPromotionW(30 * 60 * 1000, FrsErrorCallBack);
|
||
if (WStatus == ERROR_SUCCESS) {
|
||
printf("Wait succeeded\n");
|
||
Win32ToMsg (L"Promote:", WStatus);
|
||
} else {
|
||
printf("failure wait %08x\n", WStatus);
|
||
Win32ToMsg (L"Promote:", WStatus);
|
||
}
|
||
|
||
//
|
||
// Commit (or Abort)
|
||
//
|
||
// WStatus = NtFrsApi_AbortPromotionW();
|
||
WStatus = NtFrsApi_CommitPromotionW(0, FrsErrorCallBack);
|
||
if (WStatus == ERROR_SUCCESS) {
|
||
printf("success commit\n");
|
||
} else {
|
||
printf("failure commit %08x\n", WStatus);
|
||
Win32ToMsg (L"Promote:", WStatus);
|
||
}
|
||
exit(0);
|
||
}
|
||
|
||
|
||
VOID
|
||
ProcessPromoteSysVols(
|
||
IN DWORD argc,
|
||
IN PWCHAR *Argv
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Process the command line for the subcommand promotesysvols.
|
||
|
||
Arguments:
|
||
argc
|
||
Argv
|
||
|
||
Return Value:
|
||
Exits with 0 if everything went okay. Otherwise, 1.
|
||
--*/
|
||
{
|
||
DWORD WStatus;
|
||
PWCHAR Parent;
|
||
PWCHAR Account;
|
||
PWCHAR Password;
|
||
PWCHAR PrimaryEnterprise;
|
||
PWCHAR PrimaryDomain;
|
||
PWCHAR Stage;
|
||
PWCHAR RootEnterprise;
|
||
PWCHAR RootDomain;
|
||
DWORD IsPrimaryEnterprise;
|
||
DWORD IsPrimaryDomain;
|
||
DWORD WaitStatus;
|
||
|
||
if (argc != 10) {
|
||
Usage(1);
|
||
}
|
||
|
||
Parent = Argv[2];
|
||
Account = Argv[3];
|
||
Password = Argv[4];
|
||
PrimaryEnterprise = Argv[5];
|
||
PrimaryDomain = Argv[6];
|
||
Stage = Argv[7];
|
||
RootEnterprise = Argv[8];
|
||
RootDomain = Argv[9];
|
||
|
||
printf("%ws %ws %ws %ws %ws %ws %ws %ws %ws %ws\n",
|
||
Argv[0], Argv[1],
|
||
Parent,
|
||
Account,
|
||
Password,
|
||
PrimaryEnterprise,
|
||
PrimaryDomain,
|
||
Stage,
|
||
RootEnterprise,
|
||
RootDomain);
|
||
|
||
printf("PROMOTE SYSVOLS WITH COMMIT\n");
|
||
|
||
//
|
||
// Check params
|
||
//
|
||
if (_wcsicmp(PrimaryEnterprise, L"0") &&
|
||
_wcsicmp(PrimaryEnterprise, L"1")) {
|
||
printf("Primary Enterprise must be 0 or 1; not %ws\n",
|
||
PrimaryEnterprise);
|
||
Usage(1);
|
||
}
|
||
if (_wcsicmp(PrimaryDomain, L"0") &&
|
||
_wcsicmp(PrimaryDomain, L"1")) {
|
||
printf("Primary Domain must be 0 or 1; not %ws\n",
|
||
PrimaryDomain);
|
||
Usage(1);
|
||
}
|
||
IsPrimaryEnterprise = wcstoul(PrimaryEnterprise, NULL, 10);
|
||
IsPrimaryDomain = wcstoul(PrimaryDomain, NULL, 10);
|
||
|
||
//
|
||
// Prepare
|
||
//
|
||
WStatus = NtFrsApi_PrepareForPromotionW(FrsErrorCallBack);
|
||
if (WStatus == ERROR_SUCCESS) {
|
||
printf("success sysvol prepare\n");
|
||
} else {
|
||
printf("ERROR sysvol prepare %d\n", WStatus);
|
||
}
|
||
|
||
//
|
||
// Start Enterprise
|
||
//
|
||
WStatus = NtFrsApi_StartPromotionW(Parent,
|
||
Account,
|
||
Password,
|
||
Display,
|
||
FrsErrorCallBack,
|
||
NTFRSAPI_REPLICA_SET_TYPE_ENTERPRISE,
|
||
NTFRSAPI_REPLICA_SET_TYPE_ENTERPRISE,
|
||
IsPrimaryEnterprise,
|
||
Stage,
|
||
RootEnterprise);
|
||
if (WStatus == ERROR_SUCCESS) {
|
||
printf("success sysvol enterprise start\n");
|
||
} else {
|
||
printf("ERROR sysvol enterprise start %d\n", WStatus);
|
||
}
|
||
|
||
//
|
||
// Start Domain
|
||
//
|
||
WStatus = NtFrsApi_StartPromotionW(Parent,
|
||
Account,
|
||
Password,
|
||
Display,
|
||
FrsErrorCallBack,
|
||
NTFRSAPI_REPLICA_SET_TYPE_DOMAIN,
|
||
NTFRSAPI_REPLICA_SET_TYPE_DOMAIN,
|
||
IsPrimaryDomain,
|
||
Stage,
|
||
RootDomain);
|
||
if (WStatus == ERROR_SUCCESS) {
|
||
printf("success sysvol domain start\n");
|
||
} else {
|
||
printf("ERROR sysvol domain start %d\n", WStatus);
|
||
}
|
||
|
||
//
|
||
// Wait
|
||
//
|
||
printf("Waiting on promotion\n");
|
||
WaitStatus = NtFrsApi_WaitForPromotionW(5 * 60 * 1000,FrsErrorCallBack);
|
||
if (WaitStatus == WAIT_TIMEOUT) {
|
||
printf("Wait timed out\n");
|
||
} else if (WaitStatus == WAIT_FAILED) {
|
||
WStatus = GetLastError();
|
||
printf("ERROR wait sysvols %d\n", WStatus);
|
||
} else {
|
||
printf("Wait sysvols succeeded\n");
|
||
}
|
||
|
||
//
|
||
// Commit (or Abort)
|
||
//
|
||
// WStatus = NtFrsApi_AbortPromotionW();
|
||
WStatus = NtFrsApi_CommitPromotionW(0,FrsErrorCallBack);
|
||
if (WStatus == ERROR_SUCCESS) {
|
||
printf("success sysvols commit\n");
|
||
} else {
|
||
printf("ERROR sysvols commit %d\n", WStatus);
|
||
}
|
||
exit(0);
|
||
}
|
||
|
||
|
||
VOID
|
||
ProcessPromoteAbort(
|
||
IN DWORD argc,
|
||
IN PWCHAR *Argv
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Process the command line for the subcommand promoteabort.
|
||
|
||
Arguments:
|
||
argc
|
||
Argv
|
||
|
||
Return Value:
|
||
Exits with 0 if everything went okay. Otherwise, 1.
|
||
--*/
|
||
{
|
||
DWORD WStatus;
|
||
PWCHAR Parent;
|
||
PWCHAR Account;
|
||
PWCHAR Password;
|
||
PWCHAR Set;
|
||
PWCHAR Type;
|
||
PWCHAR Primary;
|
||
PWCHAR Stage;
|
||
PWCHAR Root;
|
||
DWORD IsPrimary;
|
||
DWORD WaitStatus;
|
||
|
||
if (argc != 10) {
|
||
Usage(1);
|
||
}
|
||
|
||
Parent = Argv[2];
|
||
Account = Argv[3];
|
||
Password = Argv[4];
|
||
Set = Argv[5];
|
||
Type = Argv[6];
|
||
Primary = Argv[7];
|
||
Stage = Argv[8];
|
||
Root = Argv[9];
|
||
|
||
printf("%ws %ws %ws ... %ws\n",
|
||
Argv[0], Argv[1], Parent, Root);
|
||
|
||
printf("PROMOTE WITH ABORT\n");
|
||
|
||
//
|
||
// Check params
|
||
//
|
||
if (_wcsicmp(Primary, L"0") && _wcsicmp(Primary, L"1")) {
|
||
printf("Primary must be 0 or 1; not %ws\n", Primary);
|
||
Usage(1);
|
||
}
|
||
if (_wcsicmp(Type, NTFRSAPI_REPLICA_SET_TYPE_ENTERPRISE) &&
|
||
_wcsicmp(Type, NTFRSAPI_REPLICA_SET_TYPE_DOMAIN)) {
|
||
printf("Type must be Enterprise or Domain; not %ws\n", Type);
|
||
Usage(1);
|
||
}
|
||
IsPrimary = wcstoul(Primary, NULL, 10);
|
||
|
||
//
|
||
// Prepare
|
||
//
|
||
WStatus = NtFrsApi_PrepareForPromotionW(FrsErrorCallBack);
|
||
if (WStatus == ERROR_SUCCESS) {
|
||
printf("success prepare\n");
|
||
} else {
|
||
printf("failure prepare %d\n", WStatus);
|
||
}
|
||
|
||
//
|
||
// Start
|
||
//
|
||
WStatus = NtFrsApi_StartPromotionW(Parent,
|
||
Account,
|
||
Password,
|
||
NULL,
|
||
FrsErrorCallBack,
|
||
Set,
|
||
Type,
|
||
IsPrimary,
|
||
Stage,
|
||
Root);
|
||
if (WStatus == ERROR_SUCCESS) {
|
||
printf("success start\n");
|
||
} else {
|
||
printf("failure start %d\n", WStatus);
|
||
}
|
||
|
||
//
|
||
// Abort
|
||
//
|
||
WStatus = NtFrsApi_AbortPromotionW();
|
||
if (WStatus == ERROR_SUCCESS) {
|
||
printf("success abort\n");
|
||
} else {
|
||
printf("failure abort %d\n", WStatus);
|
||
}
|
||
exit(0);
|
||
}
|
||
|
||
|
||
VOID
|
||
ProcessDemote(
|
||
IN DWORD argc,
|
||
IN PWCHAR *Argv
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Process the command line for the subcommand demote.
|
||
|
||
Arguments:
|
||
argc
|
||
Argv
|
||
|
||
Return Value:
|
||
Exits with 0 if everything went okay. Otherwise, 1.
|
||
--*/
|
||
{
|
||
DWORD WStatus;
|
||
PWCHAR Set;
|
||
DWORD WaitStatus;
|
||
|
||
if (argc != 3) {
|
||
Usage(1);
|
||
}
|
||
|
||
Set = Argv[2];
|
||
printf("%ws %ws %ws\n", Argv[0], Argv[1], Set);
|
||
|
||
printf("***** DEMOTE WITH COMMIT\n");
|
||
|
||
//
|
||
// Prepare
|
||
//
|
||
WStatus = NtFrsApi_PrepareForDemotionW(FrsErrorCallBack);
|
||
if (WStatus == ERROR_SUCCESS) {
|
||
printf("success demote prepare\n");
|
||
} else {
|
||
printf("failure demote prepare %d\n", WStatus);
|
||
}
|
||
|
||
//
|
||
// Start
|
||
//
|
||
WStatus = NtFrsApi_StartDemotionW(Set,FrsErrorCallBack);
|
||
if (WStatus == ERROR_SUCCESS) {
|
||
printf("success demote start\n");
|
||
} else {
|
||
printf("failure demote start %d\n", WStatus);
|
||
}
|
||
|
||
//
|
||
// Wait
|
||
//
|
||
WStatus = NtFrsApi_WaitForDemotionW(5 * 60 * 1000,FrsErrorCallBack);
|
||
if (WStatus == ERROR_SUCCESS) {
|
||
printf("success demote wait\n");
|
||
} else {
|
||
printf("failure demote wait %d\n", WStatus);
|
||
}
|
||
//
|
||
// Wait
|
||
//
|
||
printf("Waiting on demotion\n");
|
||
WaitStatus = NtFrsApi_WaitForPromotionW(5 * 60 * 1000,FrsErrorCallBack);
|
||
if (WaitStatus == WAIT_TIMEOUT) {
|
||
printf("Wait timed out\n");
|
||
} else if (WaitStatus == WAIT_FAILED) {
|
||
WStatus = GetLastError();
|
||
printf("failure wait %d\n", WStatus);
|
||
} else {
|
||
printf("Wait succeeded\n");
|
||
}
|
||
|
||
//
|
||
// Commit (or Abort)
|
||
//
|
||
WStatus = NtFrsApi_CommitDemotionW(0,FrsErrorCallBack);
|
||
if (WStatus == ERROR_SUCCESS) {
|
||
printf("success demote commit\n");
|
||
} else {
|
||
printf("failure demote commit %d\n", WStatus);
|
||
}
|
||
exit(0);
|
||
}
|
||
|
||
|
||
VOID
|
||
ProcessDemoteSysVols(
|
||
IN DWORD argc,
|
||
IN PWCHAR *Argv
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Process the command line for the subcommand demotesysvols.
|
||
|
||
Arguments:
|
||
argc
|
||
Argv
|
||
|
||
Return Value:
|
||
Exits with 0 if everything went okay. Otherwise, 1.
|
||
--*/
|
||
{
|
||
DWORD WStatus;
|
||
DWORD WaitStatus;
|
||
|
||
if (argc != 2) {
|
||
Usage(1);
|
||
}
|
||
|
||
printf("%ws %ws\n", Argv[0], Argv[1]);
|
||
|
||
printf("***** DEMOTE SYSVOLS WITH COMMIT\n");
|
||
|
||
//
|
||
// Prepare
|
||
//
|
||
WStatus = NtFrsApi_PrepareForDemotionW(FrsErrorCallBack);
|
||
if (WStatus == ERROR_SUCCESS) {
|
||
printf("success demote sysvols prepare\n");
|
||
} else {
|
||
printf("ERROR demote sysvols prepare %d\n", WStatus);
|
||
}
|
||
|
||
//
|
||
// Start
|
||
//
|
||
WStatus = NtFrsApi_StartDemotionW(NTFRSAPI_REPLICA_SET_TYPE_ENTERPRISE,NULL);
|
||
if (WStatus == ERROR_SUCCESS) {
|
||
printf("success demote enterprise start\n");
|
||
} else {
|
||
printf("ERROR demote enterprise start %d\n", WStatus);
|
||
}
|
||
|
||
//
|
||
// Start
|
||
//
|
||
WStatus = NtFrsApi_StartDemotionW(NTFRSAPI_REPLICA_SET_TYPE_DOMAIN, FrsErrorCallBack);
|
||
if (WStatus == ERROR_SUCCESS) {
|
||
printf("success demote domain start\n");
|
||
} else {
|
||
printf("ERROR demote domain start %d\n", WStatus);
|
||
}
|
||
|
||
//
|
||
// Wait
|
||
//
|
||
WStatus = NtFrsApi_WaitForDemotionW(5 * 60 * 1000, FrsErrorCallBack);
|
||
if (WStatus == ERROR_SUCCESS) {
|
||
printf("success demote sysvols wait\n");
|
||
} else {
|
||
printf("ERROR demote sysvols wait %d\n", WStatus);
|
||
}
|
||
//
|
||
// Wait
|
||
//
|
||
printf("Waiting on demotion\n");
|
||
WaitStatus = NtFrsApi_WaitForPromotionW(5 * 60 * 1000, FrsErrorCallBack);
|
||
if (WaitStatus == WAIT_TIMEOUT) {
|
||
printf("Wait timed out\n");
|
||
} else if (WaitStatus == WAIT_FAILED) {
|
||
WStatus = GetLastError();
|
||
printf("ERROR wait %d\n", WStatus);
|
||
} else {
|
||
printf("Wait demote sysvols succeeded\n");
|
||
}
|
||
|
||
//
|
||
// Commit (or Abort)
|
||
//
|
||
WStatus = NtFrsApi_CommitDemotionW(0, FrsErrorCallBack);
|
||
if (WStatus == ERROR_SUCCESS) {
|
||
printf("success demote sysvols commit\n");
|
||
} else {
|
||
printf("ERROR demote sysvols commit %d\n", WStatus);
|
||
}
|
||
exit(0);
|
||
}
|
||
|
||
|
||
VOID
|
||
ProcessDemoteAbort(
|
||
IN DWORD argc,
|
||
IN PWCHAR *Argv
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Process the command line for the subcommand demoteabort.
|
||
|
||
Arguments:
|
||
argc
|
||
Argv
|
||
|
||
Return Value:
|
||
Exits with 0 if everything went okay. Otherwise, 1.
|
||
--*/
|
||
{
|
||
DWORD WStatus;
|
||
PWCHAR Set;
|
||
DWORD WaitStatus;
|
||
|
||
if (argc != 3) {
|
||
Usage(1);
|
||
}
|
||
|
||
Set = Argv[2];
|
||
printf("%ws %ws %ws\n", Argv[0], Argv[1], Set);
|
||
|
||
printf("***** DEMOTE WITH ABORT\n");
|
||
|
||
//
|
||
// Prepare
|
||
//
|
||
WStatus = NtFrsApi_PrepareForDemotionW(FrsErrorCallBack);
|
||
if (WStatus == ERROR_SUCCESS) {
|
||
printf("success demote prepare\n");
|
||
} else {
|
||
printf("failure demote prepare %d\n", WStatus);
|
||
}
|
||
|
||
//
|
||
// Start
|
||
//
|
||
WStatus = NtFrsApi_StartDemotionW(Set, FrsErrorCallBack);
|
||
if (WStatus == ERROR_SUCCESS) {
|
||
printf("success demote start\n");
|
||
} else {
|
||
printf("failure demote start %d\n", WStatus);
|
||
}
|
||
|
||
//
|
||
// Abort
|
||
//
|
||
WStatus = NtFrsApi_AbortDemotionW();
|
||
if (WStatus == ERROR_SUCCESS) {
|
||
printf("success demote abort\n");
|
||
} else {
|
||
printf("failure demote abort %d\n", WStatus);
|
||
}
|
||
exit(0);
|
||
}
|
||
|
||
|
||
VOID
|
||
ProcessPoll(
|
||
IN DWORD argc,
|
||
IN PWCHAR *Argv
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Process the command line for the subcommand poll.
|
||
|
||
Arguments:
|
||
argc
|
||
Argv
|
||
|
||
Return Value:
|
||
Exits with 0 if everything went okay. Otherwise, 1.
|
||
--*/
|
||
{
|
||
DWORD WStatus;
|
||
DWORD i;
|
||
ULONG LongInterval;
|
||
ULONG ShortInterval;
|
||
ULONG UseShortInterval;
|
||
ULONG Interval;
|
||
DWORD ComputerLen;
|
||
PWCHAR ComputerName;
|
||
BOOL SetInterval;
|
||
|
||
//
|
||
// Initialize the input parameters
|
||
//
|
||
LongInterval = 0;
|
||
ShortInterval = 0;
|
||
UseShortInterval = 0;
|
||
ComputerName = NULL;
|
||
SetInterval = FALSE;
|
||
|
||
for (i = 2; i < argc; ++i) {
|
||
//
|
||
// Process options for poll
|
||
//
|
||
|
||
//
|
||
// Not a parameter; must be the computer name
|
||
//
|
||
if (*Argv[i] != L'/' && *Argv[i] != L'-') {
|
||
if (ComputerName) {
|
||
fprintf(stderr, "Multiple computer names are not allowed\n");
|
||
Usage(1);
|
||
}
|
||
ComputerName = Argv[i];
|
||
//
|
||
// /?
|
||
//
|
||
} else if (wcsstr(Argv[i] + 1, L"?") == Argv[i] + 1) {
|
||
Usage(0);
|
||
//
|
||
// /quickly
|
||
//
|
||
} else if (!_wcsnicmp(Argv[i], L"/quickly", 8)) {
|
||
SetInterval = TRUE;
|
||
UseShortInterval = 1;
|
||
if (*(Argv[i] + 8) != L'\0') {
|
||
if (*(Argv[i] + 8) != L'=') {
|
||
fprintf(stderr, "Don't understand %ws\n", Argv[i]);
|
||
Usage(1);
|
||
}
|
||
if (*(Argv[i] + 9) == L'\0') {
|
||
ShortInterval = NTFRSAPI_DEFAULT_SHORT_INTERVAL;
|
||
} else {
|
||
ShortInterval = wcstoul(Argv[i] + 9, NULL, 10);
|
||
}
|
||
if (ShortInterval < NTFRSAPI_MIN_INTERVAL ||
|
||
ShortInterval > NTFRSAPI_MAX_INTERVAL) {
|
||
fprintf(stderr, "Interval must be between %d and %d\n",
|
||
NTFRSAPI_MIN_INTERVAL, NTFRSAPI_MAX_INTERVAL);
|
||
Usage(1);
|
||
}
|
||
}
|
||
//
|
||
// /slowly
|
||
//
|
||
} else if (!_wcsnicmp(Argv[i], L"/slowly", 7)) {
|
||
SetInterval = TRUE;
|
||
if (*(Argv[i] + 7) != L'\0') {
|
||
if (*(Argv[i] + 7) != L'=') {
|
||
fprintf(stderr, "Don't understand %ws\n", Argv[i]);
|
||
Usage(1);
|
||
}
|
||
if (*(Argv[i] + 8) == L'\0') {
|
||
LongInterval = NTFRSAPI_DEFAULT_LONG_INTERVAL;
|
||
} else {
|
||
LongInterval = wcstoul(Argv[i] + 8, NULL, 10);
|
||
}
|
||
if (LongInterval < NTFRSAPI_MIN_INTERVAL ||
|
||
LongInterval > NTFRSAPI_MAX_INTERVAL) {
|
||
fprintf(stderr, "Interval must be between %d and %d\n",
|
||
NTFRSAPI_MIN_INTERVAL, NTFRSAPI_MAX_INTERVAL);
|
||
Usage(1);
|
||
}
|
||
}
|
||
//
|
||
// /now
|
||
//
|
||
} else if (!_wcsnicmp(Argv[i], L"/now", 4)) {
|
||
SetInterval = TRUE;
|
||
if (*(Argv[i] + 4) != L'\0') {
|
||
fprintf(stderr, "Don't understand %ws\n", Argv[i]);
|
||
Usage(1);
|
||
}
|
||
//
|
||
// Don't understand
|
||
//
|
||
} else {
|
||
fprintf(stderr, "Don't understand %ws\n", Argv[i]);
|
||
Usage(1);
|
||
}
|
||
}
|
||
if (SetInterval) {
|
||
//
|
||
// Set the interval and initiate a new polling cycle
|
||
//
|
||
WStatus = NtFrsApi_Set_DsPollingIntervalW(ComputerName,
|
||
UseShortInterval,
|
||
LongInterval,
|
||
ShortInterval);
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
Win32ToMsg(L"Can't set interval:", WStatus);
|
||
exit(1);
|
||
}
|
||
} else {
|
||
//
|
||
// Get the current polling cycles
|
||
//
|
||
WStatus = NtFrsApi_Get_DsPollingIntervalW(ComputerName,
|
||
&Interval,
|
||
&LongInterval,
|
||
&ShortInterval);
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
Win32ToMsg(L"Can't get intervals:", WStatus);
|
||
exit(1);
|
||
}
|
||
printf("Current Interval: %6d minutes\n", Interval);
|
||
printf("Short Interval : %6d minutes\n", ShortInterval);
|
||
printf("Long Interval : %6d minutes\n", LongInterval);
|
||
}
|
||
exit(0);
|
||
}
|
||
|
||
|
||
VOID
|
||
ProcessDump(
|
||
IN DWORD argc,
|
||
IN PWCHAR *Argv,
|
||
IN DWORD TypeOfInformation
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Dump bunches of stuff
|
||
|
||
Arguments:
|
||
argc
|
||
Argv
|
||
TypeOfInformation
|
||
|
||
Return Value:
|
||
Exits with 0 if everything went okay. Otherwise, 1.
|
||
--*/
|
||
{
|
||
DWORD WStatus;
|
||
PCHAR Line;
|
||
BOOL FirstTime = TRUE;
|
||
PVOID Info = NULL;
|
||
PWCHAR ComputerName = NULL;
|
||
|
||
if (argc > 2) {
|
||
ComputerName = Argv[2];
|
||
}
|
||
|
||
do {
|
||
WStatus = NtFrsApi_InfoW(ComputerName,
|
||
TypeOfInformation,
|
||
0,
|
||
&Info);
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
fprintf(stderr, "ERROR NtFrsApi_InfoW() Error %d\n", WStatus);
|
||
NtFrsApi_InfoFreeW(&Info);
|
||
exit(1);
|
||
}
|
||
if (Info) {
|
||
if (!FirstTime) {
|
||
printf("===== THE FOLLOWING INFO MAY BE INCONSISTENT DUE TO REFETCH =====\n");
|
||
}
|
||
FirstTime = FALSE;
|
||
|
||
Line = NULL;
|
||
do {
|
||
WStatus = NtFrsApi_InfoLineW(Info, &Line);
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
fprintf(stderr, "ERROR NtFrsApi_InfoLineW() Error %d\n", WStatus);
|
||
NtFrsApi_InfoFreeW(&Info);
|
||
exit(1);
|
||
}
|
||
if (Line) {
|
||
printf("%s", Line);
|
||
}
|
||
} while (Line);
|
||
}
|
||
} while (Info);
|
||
exit(0);
|
||
}
|
||
|
||
|
||
typedef struct _DIRS DIRS, *PDIRS;
|
||
struct _DIRS {
|
||
PDIRS Next;
|
||
PWCHAR Dir;
|
||
PVOID BurSet;
|
||
};
|
||
VOID
|
||
ProcessBackupRestore(
|
||
IN DWORD argc,
|
||
IN PWCHAR *Argv,
|
||
IN DWORD BurFlags
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Dump replicated dirs
|
||
|
||
Arguments:
|
||
argc
|
||
Argv
|
||
|
||
Return Value:
|
||
Exits with 0 if everything went okay. Otherwise, 1.
|
||
--*/
|
||
{
|
||
DWORD WStatus;
|
||
DWORD i;
|
||
DWORD BurSetIndex;
|
||
DWORD DestroyBurFlags = NTFRSAPI_BUR_FLAGS_NONE;
|
||
PVOID BurContext;
|
||
PVOID BurSet;
|
||
BOOL IsSysvol;
|
||
BOOL ExpectKey = FALSE;
|
||
BOOL Spin = FALSE;
|
||
HKEY HKey;
|
||
PWCHAR DirPath;
|
||
PWCHAR DirType;
|
||
PDIRS Dirs = NULL;
|
||
PDIRS Dir = NULL;
|
||
DWORD BufferSize;
|
||
WCHAR Buffer[1024];
|
||
DWORD Buffer2Size;
|
||
WCHAR Buffer2[1024];
|
||
DWORD FiltersSize;
|
||
WCHAR Filters[1024];
|
||
PWCHAR Str;
|
||
|
||
for (i = 2; i < argc; ++i) {
|
||
printf("%ws\n", Argv[i]);
|
||
if (!_wcsicmp(Argv[i], L"/auth")) {
|
||
BurFlags |= NTFRSAPI_BUR_FLAGS_AUTHORITATIVE;
|
||
} else if (!_wcsicmp(Argv[i], L"/nonauth")) {
|
||
BurFlags |= NTFRSAPI_BUR_FLAGS_NON_AUTHORITATIVE;
|
||
} else if (!_wcsicmp(Argv[i], L"/primary")) {
|
||
BurFlags |= NTFRSAPI_BUR_FLAGS_PRIMARY;
|
||
} else if (!_wcsicmp(Argv[i], L"/system")) {
|
||
BurFlags |= NTFRSAPI_BUR_FLAGS_SYSTEM;
|
||
} else if (!_wcsicmp(Argv[i], L"/ds")) {
|
||
BurFlags |= NTFRSAPI_BUR_FLAGS_ACTIVE_DIRECTORY;
|
||
} else if (!_wcsicmp(Argv[i], L"/normal")) {
|
||
BurFlags |= NTFRSAPI_BUR_FLAGS_NORMAL;
|
||
} else if (!_wcsicmp(Argv[i], L"/all")) {
|
||
BurFlags |= NTFRSAPI_BUR_FLAGS_ALL_DIRECTORIES_AND_VOLUMES;
|
||
} else if (!_wcsicmp(Argv[i], L"/restart")) {
|
||
DestroyBurFlags |= NTFRSAPI_BUR_FLAGS_RESTART;
|
||
} else if (!_wcsicmp(Argv[i], L"/unknown")) {
|
||
BurFlags |= 0x80000000;
|
||
} else if (!_wcsicmp(Argv[i], L"/destroyunknown")) {
|
||
DestroyBurFlags |= 0x80000000;
|
||
} else if (!_wcsicmp(Argv[i], L"/key")) {
|
||
ExpectKey = TRUE;
|
||
} else if (!_wcsicmp(Argv[i], L"/spin")) {
|
||
Spin = TRUE;
|
||
} else if (*Argv[i] == L'/') {
|
||
fprintf(stderr, "Don't understand %ws\n", Argv[i]);
|
||
exit(1);
|
||
}
|
||
}
|
||
SPIN_ON_INITIALIZE:
|
||
WStatus = NtFrsApiInitializeBackupRestore(FrsErrorCallBack,
|
||
BurFlags,
|
||
&BurContext);
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
fprintf(stderr,
|
||
"ERROR NtFrsApiInitializeBackupRestore(%08x) Error %d\n",
|
||
BurFlags,
|
||
WStatus);
|
||
if (Spin) {
|
||
Sleep(2 * 1000);
|
||
goto SPIN_ON_INITIALIZE;
|
||
}
|
||
exit(1);
|
||
}
|
||
WStatus = NtFrsApiGetBackupRestoreSets(BurContext);
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
fprintf(stderr,
|
||
"WARN NtFrsApiGetBackupRestoreSets() Error %d\n",
|
||
WStatus);
|
||
goto DESTROY;
|
||
}
|
||
BurSetIndex = 0;
|
||
while (TRUE) {
|
||
WStatus = NtFrsApiEnumBackupRestoreSets(BurContext,
|
||
BurSetIndex,
|
||
&BurSet);
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
break;
|
||
}
|
||
WStatus = NtFrsApiIsBackupRestoreSetASysvol(BurContext,
|
||
BurSet,
|
||
&IsSysvol);
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
fprintf(stderr,
|
||
"ERROR NtFrsApiIsBackupRestoreSetASysvol(%d) Error %d\n",
|
||
BurSetIndex,
|
||
WStatus);
|
||
goto DESTROY;
|
||
}
|
||
//
|
||
// Directory
|
||
//
|
||
BufferSize = 1;
|
||
WStatus = NtFrsApiGetBackupRestoreSetDirectory(BurContext,
|
||
BurSet,
|
||
&BufferSize,
|
||
Buffer);
|
||
if (WStatus != ERROR_INSUFFICIENT_BUFFER) {
|
||
fprintf(stderr,
|
||
"ERROR NtFrsApiIsBackupRestoreSetASysvol(%d) Error %d\n",
|
||
BurSetIndex,
|
||
WStatus);
|
||
}
|
||
BufferSize = 1024;
|
||
WStatus = NtFrsApiGetBackupRestoreSetDirectory(BurContext,
|
||
BurSet,
|
||
&BufferSize,
|
||
Buffer);
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
fprintf(stderr,
|
||
"ERROR NtFrsApiIsBackupRestoreSetASysvol(%d) Error %d\n",
|
||
BurSetIndex,
|
||
WStatus);
|
||
goto DESTROY;
|
||
}
|
||
//
|
||
// Paths
|
||
//
|
||
Buffer2Size = 1;
|
||
FiltersSize = 1;
|
||
WStatus = NtFrsApiGetBackupRestoreSetPaths(BurContext,
|
||
BurSet,
|
||
&Buffer2Size,
|
||
Buffer2,
|
||
&FiltersSize,
|
||
Filters);
|
||
if (WStatus != ERROR_INSUFFICIENT_BUFFER) {
|
||
fprintf(stderr,
|
||
"ERROR NtFrsApiGetBackupRestorePaths(%d) Error %d\n",
|
||
BurSetIndex,
|
||
WStatus);
|
||
}
|
||
Buffer2Size = 1024;
|
||
FiltersSize = 1;
|
||
WStatus = NtFrsApiGetBackupRestoreSetPaths(BurContext,
|
||
BurSet,
|
||
&Buffer2Size,
|
||
Buffer2,
|
||
&FiltersSize,
|
||
Filters);
|
||
if (WStatus != ERROR_INSUFFICIENT_BUFFER) {
|
||
fprintf(stderr,
|
||
"ERROR NtFrsApiGetBackupRestorePaths(FILTERS %d) Error %d\n",
|
||
BurSetIndex,
|
||
WStatus);
|
||
}
|
||
|
||
Buffer2Size = 1024;
|
||
FiltersSize = 1024;
|
||
WStatus = NtFrsApiGetBackupRestoreSetPaths(BurContext,
|
||
BurSet,
|
||
&Buffer2Size,
|
||
Buffer2,
|
||
&FiltersSize,
|
||
Filters);
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
fprintf(stderr,
|
||
"ERROR NtFrsApiGetBackupRestorePaths(%d) Error %d\n",
|
||
BurSetIndex,
|
||
WStatus);
|
||
goto DESTROY;
|
||
}
|
||
if (IsSysvol) {
|
||
printf("BurSet %d: %ws is a sysvol\n",
|
||
BurSetIndex,
|
||
Buffer);
|
||
} else {
|
||
printf("BurSet %d: %ws\n",
|
||
BurSetIndex,
|
||
Buffer);
|
||
}
|
||
if (Buffer2Size) {
|
||
Str = Buffer2;
|
||
while(*Str) {
|
||
printf(" Path : %ws\n", Str);
|
||
Str += wcslen(Str) + 1;
|
||
}
|
||
}
|
||
if (FiltersSize) {
|
||
Str = Filters;
|
||
while(*Str) {
|
||
printf(" Filter: %ws\n", Str);
|
||
Str += wcslen(Str) + 1;
|
||
}
|
||
}
|
||
Dir = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(DIRS));
|
||
Dir->Dir = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, BufferSize);
|
||
CopyMemory(Dir->Dir, Buffer, BufferSize);
|
||
Dir->BurSet = BurSet;
|
||
Dir->Next = Dirs;
|
||
Dirs = Dir;
|
||
++BurSetIndex;
|
||
}
|
||
if (!WIN_SUCCESS(WStatus) && WStatus != ERROR_NO_MORE_ITEMS) {
|
||
fprintf(stderr,
|
||
"ERROR NtFrsApiEnumBackupRestoreSets(%d) Error %d\n",
|
||
BurSetIndex,
|
||
WStatus);
|
||
goto DESTROY;
|
||
}
|
||
for (i = 2; i < argc; ++i) {
|
||
if (*Argv[i] == L'/') {
|
||
continue;
|
||
}
|
||
DirPath = Argv[i++];
|
||
if (i >= argc) {
|
||
printf("%ws does not have a corresponding primary|nonauth\n",
|
||
DirPath);
|
||
continue;
|
||
}
|
||
DirType = Argv[i];
|
||
printf("Processing %ws %ws\n", DirPath, DirType);
|
||
if (!_wcsicmp(DirType, L"primary")) {
|
||
BurFlags = NTFRSAPI_BUR_FLAGS_PRIMARY;
|
||
} else if (!_wcsicmp(DirType, L"nonauth")) {
|
||
BurFlags = NTFRSAPI_BUR_FLAGS_NON_AUTHORITATIVE;
|
||
} else {
|
||
printf("Don't understand %ws\n", DirType);
|
||
continue;
|
||
}
|
||
for (Dir = Dirs; Dir; Dir = Dir->Next) {
|
||
if (!_wcsicmp(Dir->Dir, DirPath)) {
|
||
break;
|
||
}
|
||
}
|
||
if (!Dir) {
|
||
printf("%ws not found\n", DirPath);
|
||
continue;
|
||
}
|
||
WStatus = NtFrsApiRestoringDirectory(BurContext,
|
||
Dir->BurSet,
|
||
BurFlags);
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
fprintf(stderr,
|
||
"ERROR NtFrsApiRestoringDirectory(%ws, %08x) Error %d\n",
|
||
DirPath,
|
||
BurFlags,
|
||
WStatus);
|
||
continue;
|
||
}
|
||
WStatus = NtFrsApiFinishedRestoringDirectory(BurContext,
|
||
Dir->BurSet,
|
||
NTFRSAPI_BUR_FLAGS_NONE);
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
fprintf(stderr,
|
||
"ERROR NtFrsApiFinishedRestoringDirectory(%ws, %08x) Error %d\n",
|
||
DirPath,
|
||
BurFlags,
|
||
WStatus);
|
||
continue;
|
||
}
|
||
printf("Finished restoring %ws\n", DirPath);
|
||
}
|
||
|
||
DESTROY:
|
||
if (Spin) {
|
||
printf("Spinning...\n");
|
||
}
|
||
while (Spin) {
|
||
Sleep(2 * 1000);
|
||
}
|
||
BufferSize = 1024;
|
||
WStatus = NtFrsApiDestroyBackupRestore(&BurContext,
|
||
DestroyBurFlags,
|
||
(ExpectKey) ? &HKey : NULL,
|
||
(ExpectKey) ? &BufferSize : NULL,
|
||
(ExpectKey) ? Buffer : NULL);
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
fprintf(stderr,
|
||
"ERROR NtFrsApiDestroyBackupRestore(%08x) Error %d\n",
|
||
DestroyBurFlags,
|
||
WStatus);
|
||
exit(1);
|
||
}
|
||
if (ExpectKey) {
|
||
printf("%08x HKey, %d KeySize, %ws\n", HKey, BufferSize, Buffer);
|
||
}
|
||
|
||
#if 0
|
||
WStatus = NtFrsApi_GetReplicatedDirectoriesW(FrsErrorCallBack, &Dirs);
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
fprintf(stderr, "ERROR NtFrsApi_GetReplicatedDirectories() Error %d\n", WStatus);
|
||
exit(1);
|
||
}
|
||
if (Dirs) {
|
||
while (*Dirs != L'\0') {
|
||
fprintf(stdout, "Dirs:%ws:\n", Dirs);
|
||
Dirs = &Dirs[wcslen(Dirs) + 1];
|
||
}
|
||
LocalFree(Dirs);
|
||
}
|
||
WStatus = NtFrsApi_StopServiceForFullNonAuthRestoreW(Primary,
|
||
FrsErrorCallBack);
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
fprintf(stderr, "ERROR NtFrsApi_StopServiceForFullNonAuth() Error %d\n", WStatus);
|
||
exit(1);
|
||
}
|
||
WStatus = NtFrsApi_StartServiceAfterFullNonAuthRestoreW(FrsErrorCallBack);
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
fprintf(stderr, "ERROR NtFrsApi_StartServiceAfterFullNonAuth() Error %d\n", WStatus);
|
||
exit(1);
|
||
}
|
||
#endif 0
|
||
exit(0);
|
||
}
|
||
|
||
|
||
VOID
|
||
ProcessComm(
|
||
IN DWORD argc,
|
||
IN PWCHAR *Argv,
|
||
IN DWORD CommCommand
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Dump bunches of stuff
|
||
|
||
Arguments:
|
||
argc
|
||
Argv
|
||
CommCommand
|
||
|
||
Return Value:
|
||
Exits with 0 if everything went okay. Otherwise, 1.
|
||
--*/
|
||
{
|
||
DWORD WStatus;
|
||
PWCHAR Line;
|
||
PWCHAR ComputerName1 = NULL;
|
||
PWCHAR ComputerName2 = NULL;
|
||
PWCHAR Account = NULL;
|
||
PWCHAR Password = NULL;
|
||
PVOID Info = NULL;
|
||
|
||
if (argc > 2) {
|
||
ComputerName1 = Argv[2];
|
||
if (ComputerName1 && !*ComputerName1) {
|
||
ComputerName1 = NULL;
|
||
}
|
||
}
|
||
if (argc > 3) {
|
||
ComputerName2 = Argv[3];
|
||
if (ComputerName2 && !*ComputerName2) {
|
||
ComputerName2 = NULL;
|
||
}
|
||
}
|
||
if (argc > 4) {
|
||
Account = Argv[4];
|
||
if (Account && !*Account) {
|
||
Account = NULL;
|
||
}
|
||
}
|
||
if (argc > 5) {
|
||
Password = Argv[5];
|
||
if (Password && !*Password) {
|
||
Password = NULL;
|
||
}
|
||
}
|
||
|
||
#if 0
|
||
not yet implemented
|
||
WStatus = NtFrsApi_CommW(CommCommand,
|
||
ComputerName1,
|
||
ComputerName2,
|
||
Account,
|
||
Password,
|
||
&Info);
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
fprintf(stderr, "NtFrsApi_CommW() -> %d\n", WStatus);
|
||
exit(1);
|
||
}
|
||
Line = NULL;
|
||
AGAIN:
|
||
WStatus = NtFrsApi_InfoLineW(Info, &Line);
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
fprintf(stderr, "NtFrsApi_InfoLineW() -> %d\n", WStatus);
|
||
exit(1);
|
||
}
|
||
if (Line) {
|
||
printf("%ws", Line);
|
||
goto AGAIN;
|
||
}
|
||
NtFrsApi_Free_InfoW(&Info);
|
||
#endif 0
|
||
exit(0);
|
||
}
|
||
|
||
|
||
#define PRIV_BUF_LENGTH (1024)
|
||
VOID
|
||
LogOnAsComputer(
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Check if the caller is a member of Groups
|
||
|
||
Arguments:
|
||
ServerHandle
|
||
Groups
|
||
|
||
Return Value:
|
||
Win32 Status
|
||
--*/
|
||
{
|
||
#define DEBSUB "CheckGroups:"
|
||
DWORD WStatus;
|
||
PVOID PrivBuf;
|
||
DWORD PrivBufLen;
|
||
DWORD LastPrivBufLen;
|
||
HANDLE IdHandle;
|
||
HANDLE TokenHandle;
|
||
DWORD i;
|
||
DWORD j;
|
||
TOKEN_PRIVILEGES *Tp;
|
||
DWORD ComputerLen;
|
||
WCHAR ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
|
||
DWORD PrivLen;
|
||
WCHAR PrivName[MAX_PATH + 1];
|
||
|
||
ComputerLen = MAX_COMPUTERNAME_LENGTH;
|
||
ComputerName[0] = L'\0';
|
||
if (!GetComputerName(ComputerName, &ComputerLen)) {
|
||
printf("FRS: Cannot get the computer's name\n");
|
||
return;
|
||
}
|
||
printf("Computer name is %ws\n", ComputerName);
|
||
|
||
//
|
||
// For this process
|
||
//
|
||
IdHandle = GetCurrentProcess();
|
||
if (!OpenProcessToken(IdHandle, TOKEN_QUERY, &TokenHandle)) {
|
||
WStatus = GetLastError();
|
||
printf("Can't open process token; WStatus %d\n", WStatus);
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// Get the groups from the access token for this thread or process
|
||
//
|
||
PrivBufLen = PRIV_BUF_LENGTH;
|
||
do {
|
||
PrivBuf = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, PrivBufLen);
|
||
LastPrivBufLen = PrivBufLen;
|
||
if (!GetTokenInformation(TokenHandle,
|
||
TokenPrivileges,
|
||
PrivBuf,
|
||
PrivBufLen,
|
||
&PrivBufLen)) {
|
||
WStatus = GetLastError();
|
||
printf("Can't get privs groups; WStatus %d (lastlen %d; curlen %d\n",
|
||
WStatus,
|
||
LastPrivBufLen,
|
||
PrivBufLen);
|
||
FREE(PrivBuf);
|
||
} else {
|
||
WStatus = ERROR_SUCCESS;
|
||
}
|
||
|
||
} while (!WIN_SUCCESS(WStatus) && LastPrivBufLen < PrivBufLen);
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
goto cleanup;
|
||
}
|
||
|
||
Tp = (TOKEN_PRIVILEGES *)PrivBuf;
|
||
for (i = 0; i < Tp->PrivilegeCount; ++i) {
|
||
PrivLen = MAX_PATH + 1;
|
||
if (!LookupPrivilegeName(NULL,
|
||
&Tp->Privileges[i].Luid,
|
||
PrivName,
|
||
&PrivLen)) {
|
||
printf("lookuppriv error %d\n", GetLastError());
|
||
exit(0);
|
||
}
|
||
printf("Priv %d is %ws\n", i, PrivName);
|
||
}
|
||
|
||
printf("Okay\n");
|
||
|
||
CloseHandle(TokenHandle);
|
||
if (!LogonUser(L"Administrator",
|
||
NULL,
|
||
NULL,
|
||
LOGON32_LOGON_SERVICE,
|
||
LOGON32_PROVIDER_DEFAULT,
|
||
&TokenHandle)) {
|
||
printf("ERROR - %d logon\n", GetLastError());
|
||
exit(0);
|
||
}
|
||
|
||
cleanup:
|
||
CloseHandle(TokenHandle);
|
||
CloseHandle(IdHandle);
|
||
FREE(PrivBuf);
|
||
}
|
||
|
||
// --------------- Process Install Stage
|
||
|
||
|
||
BOOL
|
||
FrsSetCompression(
|
||
IN PWCHAR Path,
|
||
IN HANDLE Handle,
|
||
IN USHORT TypeOfCompression
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Enable compression on Handle.
|
||
|
||
Arguments:
|
||
Path
|
||
Handle
|
||
TypeOfCompression
|
||
|
||
Return Value:
|
||
Set the compression mode on a file
|
||
--*/
|
||
{
|
||
DWORD BytesReturned;
|
||
if (!DeviceIoControl(Handle,
|
||
FSCTL_SET_COMPRESSION,
|
||
&TypeOfCompression,
|
||
sizeof(TypeOfCompression),
|
||
NULL,
|
||
0,
|
||
&BytesReturned,
|
||
NULL)) {
|
||
Win32ToMsg(Path, GetLastError());
|
||
return FALSE;
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOL
|
||
FrsSetFileAttributes(
|
||
PWCHAR Path,
|
||
HANDLE Handle,
|
||
ULONG FileAttributes
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
This routine sets the file's attributes
|
||
|
||
Arguments:
|
||
Path - for error messages
|
||
Handle - Supplies a handle to the file that is to be marked for delete.
|
||
Attributes - Attributes for the file
|
||
Return Value:
|
||
TRUE - attributes have been set
|
||
FALSE
|
||
--*/
|
||
{
|
||
IO_STATUS_BLOCK IoStatus;
|
||
FILE_BASIC_INFORMATION BasicInformation;
|
||
NTSTATUS Status;
|
||
|
||
//
|
||
// Set the attributes
|
||
//
|
||
ZeroMemory(&BasicInformation, sizeof(BasicInformation));
|
||
BasicInformation.FileAttributes = FileAttributes | FILE_ATTRIBUTE_NORMAL;
|
||
Status = NtSetInformationFile(Handle,
|
||
&IoStatus,
|
||
&BasicInformation,
|
||
sizeof(BasicInformation),
|
||
FileBasicInformation);
|
||
if (!NT_SUCCESS(Status)) {
|
||
fprintf(stderr, "NtSetFileInformationFile(%ws); NtStatus 0x%08x\n",
|
||
Path,
|
||
Status);
|
||
return FALSE;
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
FrsSetFilePointer(
|
||
IN PWCHAR Name,
|
||
IN HANDLE Handle,
|
||
IN ULONG High,
|
||
IN ULONG Low
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Position file pointer
|
||
|
||
Arguments:
|
||
Handle
|
||
Name
|
||
High
|
||
Low
|
||
|
||
Return Value:
|
||
Win32 Error Status
|
||
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "FrsSetFilePointer:"
|
||
|
||
DWORD WStatus;
|
||
|
||
Low = SetFilePointer(Handle, Low, &High, FILE_BEGIN);
|
||
|
||
if (Low == INVALID_SET_FILE_POINTER) {
|
||
WStatus = GetLastError();
|
||
if (WStatus != NO_ERROR) {
|
||
Win32ToMsg(Name, WStatus);
|
||
return WStatus;
|
||
}
|
||
}
|
||
|
||
return ERROR_SUCCESS;
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
StuReadFile(
|
||
IN PWCHAR Path,
|
||
IN HANDLE Handle,
|
||
IN PVOID Buf,
|
||
IN DWORD BytesToRead,
|
||
OUT PDWORD BytesRead
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Read data from a file
|
||
|
||
Arguments:
|
||
Path
|
||
Handle
|
||
Buf
|
||
BytesToRead
|
||
|
||
Return Value:
|
||
TRUE - no problem
|
||
FALSE - couldn't read
|
||
--*/
|
||
{
|
||
BOOL DidRead;
|
||
|
||
//
|
||
// Read the file's name into the file
|
||
//
|
||
DidRead = ReadFile(Handle, Buf, BytesToRead, BytesRead, NULL);
|
||
|
||
//
|
||
// Read error
|
||
//
|
||
if (!DidRead) {
|
||
Win32ToMsg(Path, GetLastError());
|
||
return FALSE;
|
||
}
|
||
//
|
||
// Done
|
||
//
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOL
|
||
FrsSetFileTime(
|
||
IN PWCHAR Path,
|
||
IN HANDLE Handle,
|
||
IN FILETIME *CreateTime,
|
||
IN FILETIME *AccessTime,
|
||
IN FILETIME *WriteTime
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Position file pointer
|
||
|
||
Arguments:
|
||
Path
|
||
Handle
|
||
Attributes
|
||
CreateTime
|
||
AccessTime
|
||
WriteTime
|
||
|
||
Return Value:
|
||
TRUE - no problem
|
||
FALSE - couldn't set size
|
||
--*/
|
||
{
|
||
if (!SetFileTime(Handle, CreateTime, AccessTime, WriteTime)) {
|
||
Win32ToMsg(Path, GetLastError());
|
||
return FALSE;
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
#define IOSIZE (64 * 1024)
|
||
VOID
|
||
ProcessInstall(
|
||
IN DWORD argc,
|
||
IN PWCHAR *Argv
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Restore the StagePath to TargetPath if TargetPath is non-NULL.
|
||
|
||
Arguments:
|
||
argc - number of argv's
|
||
Argv - stagepath and, optionally, targetpath
|
||
|
||
Return Value:
|
||
Win32 status
|
||
--*/
|
||
{
|
||
BOOL IsDir;
|
||
BOOL ExistingOid;
|
||
ULONG High;
|
||
ULONG Low;
|
||
ULONG WStatus;
|
||
ULONG Restored;
|
||
ULONG ToRestore;
|
||
ULONG FileOffset;
|
||
PUCHAR RestoreBuf = NULL;
|
||
PVOID RestoreContext = NULL;
|
||
DWORD BytesRead = 0;
|
||
HANDLE StageHandle = INVALID_HANDLE_VALUE;
|
||
PWCHAR StagePath = NULL;
|
||
PWCHAR TargetPath = NULL;
|
||
HANDLE TargetHandle = INVALID_HANDLE_VALUE;
|
||
STAGE_HEADER Header;
|
||
WIN32_STREAM_ID *StreamId = NULL;
|
||
DWORD RestoreStreamOffset = 0;
|
||
#if 0
|
||
typedef struct _WIN32_STREAM_ID {
|
||
DWORD dwStreamId ;
|
||
DWORD dwStreamAttributes ;
|
||
LARGE_INTEGER Size ;
|
||
DWORD dwStreamNameSize ;
|
||
WCHAR cStreamName[ ANYSIZE_ARRAY ] ;
|
||
} WIN32_STREAM_ID, *LPWIN32_STREAM_ID ;
|
||
#endif 0
|
||
|
||
//
|
||
// Check params
|
||
//
|
||
if (argc < 3 || argc > 4) {
|
||
Usage(1);
|
||
}
|
||
|
||
StagePath = Argv[2];
|
||
if (argc == 4) {
|
||
TargetPath = Argv[3];
|
||
}
|
||
|
||
printf("%ws %ws %ws %ws\n",
|
||
Argv[0],
|
||
Argv[1],
|
||
Argv[2],
|
||
(argc == 4) ? Argv[3] : L"");
|
||
|
||
|
||
//
|
||
// Open the stage file for shared, sequential reads
|
||
//
|
||
//
|
||
// Open the file
|
||
//
|
||
printf("Stage path: %ws\n", StagePath);
|
||
StageHandle = CreateFile(StagePath,
|
||
GENERIC_READ,
|
||
FILE_SHARE_READ,
|
||
NULL,
|
||
OPEN_EXISTING,
|
||
FILE_FLAG_SEQUENTIAL_SCAN |
|
||
FILE_FLAG_BACKUP_SEMANTICS,
|
||
NULL);
|
||
if (StageHandle == INVALID_HANDLE_VALUE) {
|
||
Win32ToMsg(StagePath, GetLastError());
|
||
Win32ToMsg(L"CreateFile(StagePath)", GetLastError());
|
||
goto CLEANUP;
|
||
}
|
||
|
||
|
||
//
|
||
// Read the header
|
||
//
|
||
if (!ReadFile(StageHandle,
|
||
&Header,
|
||
sizeof(STAGE_HEADER),
|
||
&BytesRead,
|
||
NULL)) {
|
||
Win32ToMsg(StagePath, GetLastError());
|
||
goto CLEANUP;
|
||
}
|
||
if (BytesRead != sizeof(STAGE_HEADER)) {
|
||
fprintf(stderr, "%ws: Read %d bytes, not %d\n",
|
||
StagePath,
|
||
BytesRead,
|
||
sizeof(STAGE_HEADER));
|
||
goto CLEANUP;
|
||
}
|
||
printf("Stage Header:\n");
|
||
printf("\tName : %ws\n", Header.ChangeOrderCommand.FileName);
|
||
printf("\tMajor : %08x\n", Header.Major);
|
||
printf("\tMinor : %08x\n", Header.Minor);
|
||
printf("\tDataHigh : %08x\n", Header.DataHigh);
|
||
printf("\tDataLow : %08x\n", Header.DataLow);
|
||
printf("\tCompression: %08x\n", Header.Compression);
|
||
printf("\tAttributes : %08x\n", Header.Attributes.FileAttributes);
|
||
|
||
//
|
||
// Don't understand this header format
|
||
//
|
||
if (Header.Major != NTFRS_MAJOR) {
|
||
fprintf(stderr, "%ws: Major %d != NtFrsMajor %d\n",
|
||
StagePath,
|
||
Header.Major,
|
||
NTFRS_MAJOR);
|
||
goto CLEANUP;
|
||
}
|
||
|
||
if (!TargetPath) {
|
||
goto CLEANUP;
|
||
}
|
||
|
||
//
|
||
// INSTALL STAGE FILE
|
||
//
|
||
//
|
||
// Open the file
|
||
//
|
||
printf("Target path: %ws\n", TargetPath);
|
||
IsDir = Header.Attributes.FileAttributes & FILE_ATTRIBUTE_DIRECTORY;
|
||
TargetHandle = CreateFile(TargetPath,
|
||
RESTORE_ACCESS,
|
||
0,
|
||
NULL,
|
||
OPEN_ALWAYS,
|
||
OPEN_OPTIONS,
|
||
NULL);
|
||
if (TargetHandle == INVALID_HANDLE_VALUE) {
|
||
Win32ToMsg(TargetPath, GetLastError());
|
||
Win32ToMsg(L"CreateFile(TargetPath)", GetLastError());
|
||
goto CLEANUP;
|
||
}
|
||
|
||
//
|
||
// Truncate the file if not a directory
|
||
//
|
||
if (!IsDir && !SetEndOfFile(TargetHandle)) {
|
||
Win32ToMsg(TargetPath, GetLastError());
|
||
goto CLEANUP;
|
||
}
|
||
|
||
//
|
||
// Set compression mode
|
||
//
|
||
if (!FrsSetCompression(TargetPath,
|
||
TargetHandle,
|
||
Header.Compression)) {
|
||
goto CLEANUP;
|
||
}
|
||
|
||
//
|
||
// Set attributes
|
||
//
|
||
if (!FrsSetFileAttributes(TargetPath,
|
||
TargetHandle,
|
||
Header.Attributes.FileAttributes &
|
||
~NOREPL_ATTRIBUTES)) {
|
||
goto CLEANUP;
|
||
}
|
||
|
||
|
||
//
|
||
// Seek to the first byte of data in the stage file
|
||
//
|
||
if (FrsSetFilePointer(StagePath,
|
||
StageHandle,
|
||
Header.DataHigh,
|
||
Header.DataLow) != ERROR_SUCCESS) {
|
||
goto CLEANUP;
|
||
}
|
||
FileOffset = Header.DataLow;
|
||
|
||
|
||
//
|
||
// Restore the stage file into the temporary file
|
||
//
|
||
RestoreBuf = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, IOSIZE);
|
||
|
||
do {
|
||
//
|
||
// read stage
|
||
//
|
||
printf("Reading %d bytes at %08x\n", IOSIZE, FileOffset);
|
||
if (!StuReadFile(StagePath,
|
||
StageHandle,
|
||
RestoreBuf,
|
||
IOSIZE,
|
||
&ToRestore)) {
|
||
goto CLEANUP;
|
||
}
|
||
printf("Read %d bytes at %08x\n", ToRestore, FileOffset);
|
||
FileOffset += ToRestore;
|
||
|
||
if (ToRestore == 0) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Dump stream heads in first restore buffer
|
||
// Increase buffer size to catch all heads OR
|
||
// enhance code to remember stream head offsets
|
||
// across restore bufs.
|
||
//
|
||
if (StreamId == NULL) {
|
||
RestoreStreamOffset = 0;
|
||
while (RestoreStreamOffset < ToRestore) {
|
||
StreamId = (WIN32_STREAM_ID *)(RestoreBuf + RestoreStreamOffset);
|
||
printf("StreamId: %08x %d (%08x)\n", StreamId, RestoreStreamOffset);
|
||
printf("dwStreamId: %d\n", StreamId->dwStreamId);
|
||
printf("dwStreamAttributes: %08x\n", StreamId->dwStreamAttributes);
|
||
printf("Size High: %08x\n", StreamId->Size.HighPart);
|
||
printf("Size Low: %08x\n", StreamId->Size.LowPart);
|
||
printf("dwStreamNameSize: %d\n", StreamId->dwStreamNameSize);
|
||
RestoreStreamOffset += (sizeof(WIN32_STREAM_ID) - 4);
|
||
RestoreStreamOffset += StreamId->dwStreamNameSize;
|
||
RestoreStreamOffset += StreamId->Size.LowPart;
|
||
}
|
||
}
|
||
|
||
if (!BackupWrite(TargetHandle,
|
||
RestoreBuf,
|
||
ToRestore,
|
||
&Restored,
|
||
FALSE,
|
||
TRUE,
|
||
&RestoreContext)) {
|
||
WStatus = GetLastError();
|
||
printf("BackupWrite(%08x, %d) returned %d\n",
|
||
RestoreContext,
|
||
ToRestore,
|
||
WStatus);
|
||
if (IsDir && WStatus == ERROR_ALREADY_EXISTS) {
|
||
fprintf(stderr, "%ws: WStatus %d IGNORED; dirs and altstreams\n",
|
||
TargetPath,
|
||
WStatus);
|
||
}
|
||
//
|
||
// Uknown stream header or couldn't apply object id
|
||
//
|
||
if (WStatus == ERROR_INVALID_DATA ||
|
||
WStatus == ERROR_DUP_NAME ||
|
||
(IsDir && WStatus == ERROR_ALREADY_EXISTS)) {
|
||
//
|
||
// Seek to the next stream. Stop if there are none.
|
||
//
|
||
printf("BackupWrite() returned %d; try to seek past bad data\n", WStatus);
|
||
BackupSeek(TargetHandle,
|
||
-1,
|
||
-1,
|
||
&Low,
|
||
&High,
|
||
&RestoreContext);
|
||
if (Low == 0 && High == 0) {
|
||
printf("BackupSeek failed; abort\n");
|
||
break;
|
||
}
|
||
fprintf(stderr, "%ws: WStatus %d IGNORED; BackupSeek() okay\n",
|
||
TargetPath,
|
||
WStatus);
|
||
} else {
|
||
//
|
||
// Unknown error; abort
|
||
//
|
||
Win32ToMsg(TargetPath, GetLastError());
|
||
goto CLEANUP;
|
||
}
|
||
} else {
|
||
printf("BackupWrite(%08x, %d) okay\n", RestoreContext, ToRestore);
|
||
}
|
||
} while (TRUE);
|
||
|
||
#if 0
|
||
//
|
||
// Insure the correct object ID is on the file.
|
||
//
|
||
FRS_ASSERT(!memcmp(Header->FileObjId.ObjectId, &Coc->FileGuid, sizeof(GUID)));
|
||
bugbug("do we have to write the extend OID data here???")
|
||
WStatus = FrsGetOrSetFileObjectId(DstHandle,
|
||
Coc->FileName,
|
||
TRUE,
|
||
&Header->FileObjId);
|
||
if (WStatus == ERROR_DUP_NAME) {
|
||
DPRINT2(0, "Stealing object id for %ws; WStatus %d\n",
|
||
Coc->FileName,
|
||
WStatus);
|
||
ZeroMemory(&FileObjID, sizeof(FileObjID));
|
||
FrsUuidCreate((GUID *)(&FileObjID.ObjectId[0]));
|
||
|
||
ExistingOid = FALSE;
|
||
WStatus = ChgOrdHammerObjectId(Coc->FileName,
|
||
&Coc->FileGuid,
|
||
OBJECT_ID_LENGTH,
|
||
Coc->NewReplica->pVme,
|
||
TRUE,
|
||
NULL,
|
||
&FileObjID,
|
||
&ExistingOid);
|
||
if (WIN_SUCCESS(WStatus)) {
|
||
WStatus = FrsGetOrSetFileObjectId(DstHandle,
|
||
Coc->FileName,
|
||
TRUE,
|
||
&Header->FileObjId);
|
||
}
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
DPRINT2(0, "Retry install of %ws because of object id; WStatus %d\n",
|
||
Coc->FileName,
|
||
WStatus);
|
||
WStatus = ERROR_RETRY;
|
||
}
|
||
}
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
goto out;
|
||
}
|
||
#endif 0
|
||
|
||
//
|
||
// Set times
|
||
//
|
||
if (!FrsSetFileTime(TargetPath,
|
||
TargetHandle,
|
||
(PFILETIME)&Header.Attributes.CreationTime.QuadPart,
|
||
(PFILETIME)&Header.Attributes.LastAccessTime.QuadPart,
|
||
(PFILETIME)&Header.Attributes.LastWriteTime.QuadPart)) {
|
||
goto CLEANUP;
|
||
}
|
||
|
||
//
|
||
// Set final attributes
|
||
//
|
||
if (!FrsSetFileAttributes(TargetPath,
|
||
TargetHandle,
|
||
Header.Attributes.FileAttributes)) {
|
||
goto CLEANUP;
|
||
}
|
||
|
||
//
|
||
// Make sure all of the data is on disk. We don't want to lose
|
||
// it across reboots
|
||
//
|
||
if (!FlushFileBuffers(TargetHandle)) {
|
||
Win32ToMsg(TargetPath, GetLastError());
|
||
goto CLEANUP;
|
||
}
|
||
|
||
CLEANUP:
|
||
//
|
||
// Free up the restore context before we close TmpHandle (just in case)
|
||
//
|
||
if (RestoreContext) {
|
||
printf("Discard BackupWrite(%08x)\n", RestoreContext);
|
||
BackupWrite(TargetHandle,
|
||
NULL,
|
||
0,
|
||
NULL,
|
||
TRUE,
|
||
TRUE,
|
||
&RestoreContext);
|
||
}
|
||
if (StageHandle && StageHandle != INVALID_HANDLE_VALUE) {
|
||
CloseHandle(StageHandle);
|
||
}
|
||
if (TargetHandle && TargetHandle != INVALID_HANDLE_VALUE) {
|
||
CloseHandle(TargetHandle);
|
||
}
|
||
FREE(RestoreBuf);
|
||
printf("Install of %ws into %ws complete\n",
|
||
StagePath,
|
||
TargetPath);
|
||
}
|
||
// ----------------
|
||
|
||
|
||
VOID _cdecl
|
||
main(
|
||
IN DWORD argc,
|
||
IN PCHAR *argv
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Process the command line.
|
||
|
||
Arguments:
|
||
argc
|
||
argv
|
||
|
||
Return Value:
|
||
Exits with 0 if everything went okay. Otherwise, 1.
|
||
--*/
|
||
{
|
||
PWCHAR *Argv;
|
||
|
||
//
|
||
// Print usage and exit
|
||
//
|
||
if (argc == 1) {
|
||
Usage(0);
|
||
}
|
||
|
||
//
|
||
// Use wide char parameters
|
||
//
|
||
Argv = ConvertArgv(argc, argv);
|
||
|
||
//
|
||
// Find the subcommand
|
||
//
|
||
if (!wcscmp(Argv[1], L"poll")) {
|
||
ProcessPoll(argc, Argv);
|
||
} else if (!_wcsicmp(Argv[1], L"promote")) {
|
||
ProcessPromote(argc, Argv);
|
||
} else if (!_wcsicmp(Argv[1], L"promoteabort")) {
|
||
ProcessPromoteAbort(argc, Argv);
|
||
} else if (!_wcsicmp(Argv[1], L"promotesysvols")) {
|
||
ProcessPromoteSysVols(argc, Argv);
|
||
} else if (!_wcsicmp(Argv[1], L"demote")) {
|
||
ProcessDemote(argc, Argv);
|
||
} else if (!_wcsicmp(Argv[1], L"demoteabort")) {
|
||
ProcessDemoteAbort(argc, Argv);
|
||
} else if (!_wcsicmp(Argv[1], L"demotesysvols")) {
|
||
ProcessDemoteSysVols(argc, Argv);
|
||
} else if (!_wcsicmp(Argv[1], L"version")) {
|
||
ProcessDump(argc, Argv, NTFRSAPI_INFO_TYPE_VERSION);
|
||
} else if (!_wcsicmp(Argv[1], L"sets")) {
|
||
ProcessDump(argc, Argv, NTFRSAPI_INFO_TYPE_SETS);
|
||
} else if (!_wcsicmp(Argv[1], L"ds")) {
|
||
ProcessDump(argc, Argv, NTFRSAPI_INFO_TYPE_DS);
|
||
} else if (!_wcsicmp(Argv[1], L"memory")) {
|
||
ProcessDump(argc, Argv, NTFRSAPI_INFO_TYPE_MEMORY);
|
||
} else if (!_wcsicmp(Argv[1], L"idtable")) {
|
||
ProcessDump(argc, Argv, NTFRSAPI_INFO_TYPE_IDTABLE);
|
||
} else if (!_wcsicmp(Argv[1], L"inlog")) {
|
||
ProcessDump(argc, Argv, NTFRSAPI_INFO_TYPE_INLOG);
|
||
} else if (!_wcsicmp(Argv[1], L"outlog")) {
|
||
ProcessDump(argc, Argv, NTFRSAPI_INFO_TYPE_OUTLOG);
|
||
} else if (!_wcsicmp(Argv[1], L"threads")) {
|
||
ProcessDump(argc, Argv, NTFRSAPI_INFO_TYPE_THREADS);
|
||
} else if (!_wcsicmp(Argv[1], L"stage")) {
|
||
ProcessDump(argc, Argv, NTFRSAPI_INFO_TYPE_STAGE);
|
||
} else if (!_wcsicmp(Argv[1], L"install")) {
|
||
ProcessInstall(argc, Argv);
|
||
} else if (!_wcsicmp(Argv[1], L"restore")) {
|
||
ProcessBackupRestore(argc, Argv, NTFRSAPI_BUR_FLAGS_RESTORE);
|
||
} else if (!_wcsicmp(Argv[1], L"backup")) {
|
||
ProcessBackupRestore(argc, Argv, NTFRSAPI_BUR_FLAGS_BACKUP);
|
||
} else if (!_wcsicmp(Argv[1], L"comm")) {
|
||
// Not implemented
|
||
// ProcessComm(argc, Argv, NTFRSAPI_COMM_COMMAND_TEST);
|
||
} else {
|
||
fprintf(stderr, "Don't understand %ws\n", Argv[1]);
|
||
Usage(1);
|
||
}
|
||
exit(0);
|
||
}
|