|
|
/*++
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); }
|