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.
2293 lines
66 KiB
2293 lines
66 KiB
/*++
|
|
|
|
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);
|
|
}
|