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

2261 lines
63 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. ntfrsupg.c
  5. Abstract:
  6. Upgrade ntfrs.
  7. Supports upgrading previous IDS (1717) to current IDS (~1770)
  8. Basically, it builds the sysvol hierarchy, adjusts the netlogon
  9. share, and sets up the registry so the service can create the
  10. sysvols. There is no seeding.
  11. Author:
  12. Isaac Heizer and Billy J. Fuller 9-Mar-1998
  13. Environment
  14. User mode winnt
  15. --*/
  16. extern "C" {
  17. #include <ntreppch.h>
  18. #pragma hdrstop
  19. #include <lm.h>
  20. #include <netcan.h>
  21. #include <icanon.h>
  22. #include <dsgetdc.h>
  23. #include <dsrole.h>
  24. #include <frs.h>
  25. #include <tablefcn.h>
  26. }
  27. /*
  28. * This program performs the steps necessary to configure NTFRS on a DC, prepared
  29. * to support the system volumes.
  30. *
  31. * It was created as an interim tool to support the initialization of NTFRS on a DC
  32. * which was running NT5 generation software before NTFRS was available. After upgrading
  33. * that DC with the latest NT5 version, this tool must be manually run to complete the
  34. * initialization of NTFRS and system volumes.
  35. */
  36. WCHAR SysVolShare[] = L"SYSVOL";
  37. WCHAR SysVolRemark[] = L"System Volume Share (Migrated)";
  38. WCHAR FRSSysvol[] = L"System\\CurrentControlSet\\Services\\NtFrs\\Parameters\\Sysvol";
  39. WCHAR FRSParameters[] = L"System\\CurrentControlSet\\Services\\NtFrs\\Parameters";
  40. #define DSROLEP_FRS_COMMAND L"Replica Set Command"
  41. #define DSROLEP_FRS_NAME L"Replica Set Name"
  42. #define DSROLEP_FRS_TYPE L"Replica Set Type"
  43. #define DSROLEP_FRS_PRIMARY L"Replica Set Primary"
  44. #define DSROLEP_FRS_STAGE L"Replica Set Stage"
  45. #define DSROLEP_FRS_ROOT L"Replica Set Root"
  46. #define DSROLEP_FRS_CREATE L"Create"
  47. #define DSROLEP_FRS_DELETE L"Delete"
  48. #define DSROLEP_FRS_COMMITTED L"SysVol Information is Committed"
  49. #define DSROLEP_FRS_LONG_NAME L"File Replication Service"
  50. #define DSROLEP_FRS_SHORT_NAME L"NtFrs"
  51. #define DSROLEP_FRS_RECOVERY L"Catastrophic Restore at Startup"
  52. #define FREE(_x_) { if (_x_) { free(_x_); (_x_) = NULL; } }
  53. //
  54. // These are the static directories created within a system volume share
  55. //
  56. LPWSTR StaticSysvolDirs[] = {
  57. L"sysvol",
  58. L"domain",
  59. L"staging",
  60. L"staging areas",
  61. L"staging\\domain",
  62. 0
  63. };
  64. //
  65. // Print out the usage message
  66. //
  67. void
  68. Usage( int argc, char *argv[] )
  69. {
  70. fprintf( stderr, "Usage: %s [-D] sysvol\n\n", argv[0] );
  71. fprintf( stderr, " -D this is the first upgraded DC in this domain\n\n" );
  72. fprintf( stderr, " sysvol is the path for the system volume share.\n" );
  73. fprintf( stderr, " The system volume must reside on NTFS version 5.\n" );
  74. fprintf( stderr, " \n");
  75. fprintf( stderr, " After running this program with the -D option, copy\n");
  76. fprintf( stderr, " the files in the scripts directory from the old\n");
  77. fprintf( stderr, " system volume into the scripts directory in the new\n");
  78. fprintf( stderr, " domain system volume. Otherwise, wait for replication to\n");
  79. fprintf( stderr, " populate the scripts directory in the new domain\n");
  80. fprintf( stderr, " system volume.\n");
  81. fprintf( stderr, " \n");
  82. fprintf( stderr, "Usage: %s [-Y] -RESTORE\n\n", argv[0] );
  83. fprintf( stderr, " -RESTORE Delete replicated directories.\n");
  84. fprintf( stderr, " -Y Delete directories without prompting.\n");
  85. fprintf( stderr, " \n");
  86. fprintf( stderr, " WARNING: FILE REPLICATION SERVICE STATE WILL BE DELETED!\n");
  87. fprintf( stderr, " WARNING: ALL REPLICATED DIRECTORIES WILL BE DELETED!\n");
  88. fprintf( stderr, " When run with the -RESTORE option, the contents of\n");
  89. fprintf( stderr, " the replicated directories and the service's state \n");
  90. fprintf( stderr, " are deleted with the expectation that the data will \n");
  91. fprintf( stderr, " be supplied by a replication partner at a later time. \n");
  92. fprintf( stderr, " The user is prompted for each replicated directory.\n");
  93. fprintf( stderr, " The contents of the replicated directory are not deleted\n");
  94. fprintf( stderr, " if you type n. The contents are deleted if you type y.\n");
  95. fprintf( stderr, " Type n if there are no replication partners.\n");
  96. }
  97. //
  98. // Print 'text' and render 'code' into an error message
  99. //
  100. void
  101. errmsg( char *text, ULONG code )
  102. {
  103. int i;
  104. char msg[ 100 ];
  105. i = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | sizeof( msg ),
  106. NULL,
  107. code,
  108. 0,
  109. msg,
  110. sizeof(msg),
  111. NULL );
  112. if( i )
  113. fprintf( stderr, "%s: %s\n", text ? text : "", msg );
  114. else
  115. fprintf( stderr, "%s: error %d\n", text ? text : "", code );
  116. }
  117. //
  118. // Print unicode 'text' and render 'code' into an error message
  119. //
  120. void
  121. errmsg( LPWSTR text, ULONG code )
  122. {
  123. int i;
  124. WCHAR msg[ 100 ];
  125. i = FormatMessageW( FORMAT_MESSAGE_FROM_SYSTEM | sizeof( msg ),
  126. NULL,
  127. code,
  128. 0,
  129. msg,
  130. sizeof(msg) / sizeof(WCHAR),
  131. NULL );
  132. if( i )
  133. fprintf( stderr, "%ws: %ws\n", text ? text : L"", msg );
  134. else
  135. fprintf( stderr, "%ws: error %d\n", text ? text : L"", code );
  136. }
  137. //
  138. // Write a string value to the registry
  139. //
  140. BOOLEAN
  141. WriteRegistry( LPWSTR KeyName, LPWSTR ValueName, LPWSTR Value )
  142. {
  143. HKEY hKey;
  144. DWORD disposition;
  145. LONG retval;
  146. //
  147. // First ensure that 'keyname' exists in the registry
  148. //
  149. retval = RegCreateKeyEx(
  150. HKEY_LOCAL_MACHINE,
  151. KeyName,
  152. NULL,
  153. NULL,
  154. REG_OPTION_NON_VOLATILE,
  155. KEY_ALL_ACCESS,
  156. NULL,
  157. &hKey,
  158. &disposition
  159. );
  160. if (!WIN_SUCCESS(retval)) {
  161. errmsg( KeyName, retval );
  162. return FALSE;
  163. }
  164. if( ARGUMENT_PRESENT( ValueName ) ) {
  165. retval = RegSetValueEx(
  166. hKey,
  167. ValueName,
  168. 0,
  169. REG_SZ,
  170. (BYTE *)Value,
  171. (wcslen( Value ) + 1) * sizeof( WCHAR )
  172. );
  173. if (!WIN_SUCCESS(retval)) {
  174. errmsg( ValueName, retval );
  175. RegCloseKey( hKey );
  176. return FALSE;
  177. }
  178. }
  179. RegCloseKey( hKey );
  180. return TRUE;
  181. }
  182. //
  183. // Write a DWORD value to the registry
  184. //
  185. BOOLEAN
  186. WriteRegistry( LPWSTR KeyName, LPWSTR ValueName, DWORD Value )
  187. {
  188. HKEY hKey;
  189. DWORD disposition;
  190. LONG retval;
  191. //
  192. // First ensure that 'keyname' exists in the registry
  193. //
  194. retval = RegCreateKeyEx(
  195. HKEY_LOCAL_MACHINE,
  196. KeyName,
  197. NULL,
  198. NULL,
  199. REG_OPTION_NON_VOLATILE,
  200. KEY_ALL_ACCESS,
  201. NULL,
  202. &hKey,
  203. &disposition
  204. );
  205. if (!WIN_SUCCESS(retval)) {
  206. errmsg( KeyName, retval );
  207. return FALSE;
  208. }
  209. if( ARGUMENT_PRESENT( ValueName ) ) {
  210. retval = RegSetValueEx(
  211. hKey,
  212. ValueName,
  213. 0,
  214. REG_DWORD,
  215. (BYTE *)&Value,
  216. sizeof( Value )
  217. );
  218. if (!WIN_SUCCESS(retval)) {
  219. errmsg( ValueName, retval );
  220. RegCloseKey( hKey );
  221. return FALSE;
  222. }
  223. }
  224. RegCloseKey( hKey );
  225. return TRUE;
  226. }
  227. //
  228. // Make sure that 'DirName' exists. Create it if it doesn't
  229. //
  230. BOOLEAN
  231. EnsureDirectoryExists( LPWSTR DirName )
  232. {
  233. DWORD retval;
  234. retval = GetFileAttributes( DirName );
  235. if( retval == 0xFFFFFFFF ) {
  236. printf( " Create directory: %ws\n", DirName );
  237. if( !CreateDirectory( DirName, NULL ) ) {
  238. retval = GetLastError();
  239. errmsg( DirName, GetLastError() );
  240. return FALSE;
  241. }
  242. } else if( !(retval & FILE_ATTRIBUTE_DIRECTORY) ) {
  243. fprintf( stderr, "Not a directory: %ws\n", DirName );
  244. return FALSE;
  245. }
  246. return TRUE;
  247. }
  248. BOOLEAN
  249. LinkAToB( LPWSTR DirA, LPWSTR DirB )
  250. {
  251. NTSTATUS Status;
  252. BOOLEAN RetValue = FALSE;
  253. HANDLE Handle = INVALID_HANDLE_VALUE;
  254. UNICODE_STRING UnicodeNameB;
  255. UNICODE_STRING DosNameB;
  256. IO_STATUS_BLOCK IoStatusBlock;
  257. PREPARSE_DATA_BUFFER ReparseBufferHeader = NULL;
  258. PCHAR ReparseBuffer;
  259. USHORT ReparseDataLength;
  260. PWSTR FreeBuffer = NULL;
  261. if( !EnsureDirectoryExists( DirA ) ||
  262. !EnsureDirectoryExists( DirB ) ) {
  263. goto CLEANUP;
  264. }
  265. Handle = CreateFile( DirA,
  266. GENERIC_WRITE,
  267. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  268. NULL,
  269. OPEN_EXISTING,
  270. FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
  271. NULL
  272. );
  273. if (!HANDLE_IS_VALID(Handle)) {
  274. fprintf( stderr, "Unable to open %ws", DirA );
  275. errmsg( (LPWSTR)NULL, GetLastError() );
  276. goto CLEANUP;
  277. }
  278. //
  279. // Get the NT path name of the directory to which we want to link
  280. //
  281. if( !RtlDosPathNameToNtPathName_U(
  282. DirB,
  283. &UnicodeNameB,
  284. NULL,
  285. NULL
  286. )) {
  287. errmsg( DirB, GetLastError() );
  288. goto CLEANUP;
  289. }
  290. //
  291. // Remember the unicode buffer to free.
  292. //
  293. FreeBuffer = UnicodeNameB.Buffer;
  294. RtlInitUnicodeString( &DosNameB, DirB);
  295. //
  296. // Set the reparse point with mount point or symbolic link tag and determine
  297. // the appropriate length of the buffer.
  298. //
  299. ReparseDataLength = (USHORT) ((FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) -
  300. REPARSE_DATA_BUFFER_HEADER_SIZE) +
  301. UnicodeNameB.Length + sizeof(UNICODE_NULL) +
  302. DosNameB.Length + sizeof(UNICODE_NULL));
  303. //
  304. // Allocate a buffer to set the reparse point.
  305. //
  306. ReparseBufferHeader = (PREPARSE_DATA_BUFFER)LocalAlloc( LPTR,
  307. REPARSE_DATA_BUFFER_HEADER_SIZE +
  308. ReparseDataLength
  309. );
  310. if (ReparseBufferHeader == NULL) {
  311. errmsg( "Unable to allocate reparse buffer", GetLastError() );
  312. goto CLEANUP;
  313. }
  314. ReparseBufferHeader->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
  315. ReparseBufferHeader->ReparseDataLength = (USHORT)ReparseDataLength;
  316. ReparseBufferHeader->Reserved = 0;
  317. ReparseBufferHeader->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0;
  318. ReparseBufferHeader->SymbolicLinkReparseBuffer.SubstituteNameLength = UnicodeNameB.Length;
  319. ReparseBufferHeader->SymbolicLinkReparseBuffer.PrintNameOffset = UnicodeNameB.Length + sizeof( UNICODE_NULL );
  320. ReparseBufferHeader->SymbolicLinkReparseBuffer.PrintNameLength = DosNameB.Length;
  321. RtlCopyMemory(
  322. ReparseBufferHeader->SymbolicLinkReparseBuffer.PathBuffer,
  323. UnicodeNameB.Buffer,
  324. UnicodeNameB.Length
  325. );
  326. RtlCopyMemory(
  327. (PCHAR)(ReparseBufferHeader->SymbolicLinkReparseBuffer.PathBuffer)+
  328. UnicodeNameB.Length + sizeof(UNICODE_NULL),
  329. DosNameB.Buffer,
  330. DosNameB.Length
  331. );
  332. Status = NtFsControlFile(
  333. Handle,
  334. NULL,
  335. NULL,
  336. NULL,
  337. &IoStatusBlock,
  338. FSCTL_SET_REPARSE_POINT,
  339. ReparseBufferHeader,
  340. REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseBufferHeader->ReparseDataLength,
  341. NULL, // no output buffer
  342. 0 // output buffer length
  343. );
  344. if (!NT_SUCCESS(Status)) {
  345. switch( Status ) {
  346. case STATUS_VOLUME_NOT_UPGRADED:
  347. case STATUS_INVALID_DEVICE_REQUEST:
  348. printf( "%ws must be on an NT5 NTFS volume.\n", DirA );
  349. break;
  350. default:
  351. printf( "Unable to set reparse point data, status %X", Status );
  352. break;
  353. }
  354. goto CLEANUP;
  355. }
  356. //
  357. // SUCCESS
  358. //
  359. RetValue = TRUE;
  360. CLEANUP:
  361. if ((HLOCAL)ReparseBufferHeader) {
  362. LocalFree((HLOCAL)ReparseBufferHeader);
  363. }
  364. if (FreeBuffer != NULL) {
  365. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  366. }
  367. FRS_CLOSE(Handle);
  368. return RetValue;
  369. }
  370. //
  371. // Create the system volume subtree
  372. //
  373. BOOLEAN
  374. CreateSysVolTree( LPWSTR SysVolPath, BOOLEAN IsFirstDCInDomain , PWCHAR domainName)
  375. {
  376. DWORD i;
  377. WCHAR bufA[ MAX_PATH ];
  378. WCHAR bufB[ MAX_PATH ];
  379. printf( "Checking %ws subtree at %ws\n", SysVolShare, SysVolPath );
  380. if( !EnsureDirectoryExists( SysVolPath) ) {
  381. return FALSE;
  382. }
  383. //
  384. // First create the static system volume directories
  385. //
  386. for( i = 0; StaticSysvolDirs[i]; i++ ) {
  387. wcscpy( bufA, SysVolPath );
  388. wcscat( bufA, L"\\" );
  389. wcscat( bufA, StaticSysvolDirs[i] );
  390. if( !EnsureDirectoryExists( bufA ) ) {
  391. return FALSE;
  392. }
  393. }
  394. //
  395. // Create the DNS domain link for the sysvol share
  396. //
  397. wcscpy( bufA, SysVolPath );
  398. wcscat( bufA, L"\\sysvol\\" );
  399. wcscat( bufA, domainName );
  400. wcscpy( bufB, SysVolPath );
  401. wcscat( bufB, L"\\domain" );
  402. if( !LinkAToB( bufA, bufB ) ) {
  403. return FALSE;
  404. }
  405. //
  406. // Create the DNS domain link in the staging area
  407. //
  408. wcscpy( bufA, SysVolPath );
  409. wcscat( bufA, L"\\staging areas\\" );
  410. wcscat( bufA, domainName );
  411. wcscpy( bufB, SysVolPath );
  412. wcscat( bufB, L"\\staging\\domain" );
  413. if( !LinkAToB( bufA, bufB ) ) {
  414. return FALSE;
  415. }
  416. //
  417. // Finally, if we are the first DC initialized in this domain,
  418. // we need to create the scripts directory
  419. //
  420. if( IsFirstDCInDomain ) {
  421. wcscpy( bufA, SysVolPath );
  422. wcscat( bufA, L"\\domain\\scripts" );
  423. if( !EnsureDirectoryExists( bufA ) ) {
  424. return FALSE;
  425. }
  426. }
  427. return TRUE;
  428. }
  429. //
  430. // Create the system volume share.
  431. //
  432. BOOLEAN
  433. CreateSysVolShare( LPWSTR SysVolPath )
  434. {
  435. DWORD dwType, retval;
  436. SHARE_INFO_2 si2, *psi2;
  437. WCHAR SysVol[ MAX_PATH ];
  438. printf( "Creating system volume share:\n" );
  439. //
  440. // Blow away the current sysvol share if it exists
  441. //
  442. retval = NetShareGetInfo( NULL, SysVolShare, 2, (LPBYTE *)&psi2 );
  443. if( retval == NO_ERROR ) {
  444. if( psi2->shi2_type != STYPE_DISKTREE ) {
  445. fprintf( stderr, "%ws is shared, but is not a disk share!\n", SysVolShare );
  446. return FALSE;
  447. }
  448. printf( " Delete current share: %ws=%ws\n", psi2->shi2_netname, psi2->shi2_path );
  449. NetApiBufferFree( psi2 );
  450. //
  451. // Try to delete this share
  452. //
  453. retval = NetShareDel( NULL, SysVolShare, 0 );
  454. if( retval != NO_ERROR ) {
  455. errmsg( "Unable to delete sysvol share", retval );
  456. return FALSE;
  457. }
  458. }
  459. //
  460. // sysvol share
  461. //
  462. wcscpy( SysVol, SysVolPath );
  463. wcscat( SysVol, L"\\sysvol" );
  464. //
  465. // Add the new sysvol share
  466. //
  467. si2.shi2_netname = SysVolShare;
  468. si2.shi2_type = STYPE_DISKTREE;
  469. si2.shi2_remark = SysVolRemark;
  470. si2.shi2_permissions = 0;
  471. si2.shi2_max_uses = (DWORD)-1;
  472. si2.shi2_current_uses = 0;
  473. si2.shi2_path = SysVol;
  474. si2.shi2_passwd = 0;
  475. printf( " Add share: %ws=%ws\n", SysVolShare, SysVol );
  476. retval = NetShareAdd( NULL, 2, (LPBYTE)&si2, &dwType );
  477. if( retval != NO_ERROR ) {
  478. errmsg( "Unable to share new sysvol share", retval );
  479. return FALSE;
  480. }
  481. //
  482. // Add the registry key telling netlogon to share this out as the system volume share
  483. //
  484. printf( " Add netlogon sysvol registry key\n" );
  485. return WriteRegistry( L"System\\CurrentControlSet\\Services\\Netlogon\\Parameters",
  486. L"SysVol",
  487. SysVol
  488. );
  489. }
  490. //
  491. // Add the registry keys needed for NTFRS. Do what DcPromo would have done
  492. //
  493. BOOLEAN
  494. AddRegKeys(
  495. IN PWCHAR ReplicaSetName,
  496. IN PWCHAR ReplicaSetType,
  497. IN DWORD ReplicaSetPrimary,
  498. IN PWCHAR ReplicaSetStage,
  499. IN PWCHAR ReplicaSetRoot )
  500. {
  501. WCHAR KeyName[512];
  502. //
  503. // Make sure the NTFRS section is there
  504. //
  505. WriteRegistry( L"System\\CurrentControlSet\\services\\NtFrs", 0, (DWORD)0 );
  506. WriteRegistry( L"System\\CurrentControlSet\\services\\NtFrs\\Parameters", 0, (DWORD)0 );
  507. WriteRegistry( L"System\\CurrentControlSet\\services\\NtFrs\\Parameters\\Sysvol", 0, (DWORD)0 );
  508. //
  509. // Sysvol key + values
  510. //
  511. wcscpy( KeyName, L"System\\CurrentControlSet\\services\\NtFrs\\Parameters\\Sysvol\\" );
  512. wcscat( KeyName, ReplicaSetName );
  513. WriteRegistry( KeyName, DSROLEP_FRS_COMMAND, DSROLEP_FRS_CREATE );
  514. WriteRegistry( KeyName, DSROLEP_FRS_NAME, ReplicaSetName );
  515. WriteRegistry( KeyName, DSROLEP_FRS_TYPE, ReplicaSetType );
  516. WriteRegistry( KeyName, DSROLEP_FRS_PRIMARY, (DWORD)ReplicaSetPrimary );
  517. WriteRegistry( KeyName, DSROLEP_FRS_ROOT, ReplicaSetRoot );
  518. WriteRegistry( KeyName, DSROLEP_FRS_STAGE, ReplicaSetStage );
  519. return TRUE;
  520. }
  521. //
  522. // Commit the registry keys so that if NtFrs is running it can now
  523. // pick up a consistent set of values.
  524. //
  525. BOOLEAN
  526. CommitRegKeys(
  527. VOID )
  528. {
  529. //
  530. // Make sure the NTFRS section is there
  531. //
  532. WriteRegistry( L"System\\CurrentControlSet\\services\\NtFrs", 0, (DWORD)0 );
  533. WriteRegistry( L"System\\CurrentControlSet\\services\\NtFrs\\Parameters", 0, (DWORD)0 );
  534. WriteRegistry( L"System\\CurrentControlSet\\services\\NtFrs\\Parameters\\Sysvol", 0, (DWORD)0 );
  535. //
  536. // Commit both sysvols
  537. //
  538. WriteRegistry( L"System\\CurrentControlSet\\services\\NtFrs\\Parameters\\Sysvol",
  539. DSROLEP_FRS_COMMITTED, (DWORD)1 );
  540. return TRUE;
  541. }
  542. //
  543. // Commit the registry keys so that if NtFrs is running it can now
  544. // pick up a consistent set of values.
  545. //
  546. BOOLEAN
  547. DeleteRegKeys(
  548. VOID )
  549. {
  550. DWORD WStatus;
  551. HKEY HKey = 0;
  552. WCHAR KeyBuf[MAX_PATH + 1];
  553. BOOLEAN RetValue = FALSE;
  554. //
  555. // Make sure the NTFRS section is there
  556. //
  557. WriteRegistry( L"System\\CurrentControlSet\\services\\NtFrs", 0, (DWORD)0 );
  558. WriteRegistry( L"System\\CurrentControlSet\\services\\NtFrs\\Parameters", 0, (DWORD)0 );
  559. WriteRegistry( L"System\\CurrentControlSet\\services\\NtFrs\\Parameters\\Sysvol", 0, (DWORD)0 );
  560. WStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  561. L"System\\CurrentControlSet\\services\\NtFrs\\Parameters\\Sysvol",
  562. 0,
  563. KEY_ALL_ACCESS,
  564. &HKey);
  565. if (!WIN_SUCCESS(WStatus)) {
  566. errmsg("Cannot open registry", WStatus);
  567. goto CLEANUP;
  568. }
  569. WStatus = RegDeleteValue(HKey, DSROLEP_FRS_COMMITTED);
  570. if (!WIN_SUCCESS(WStatus) && WStatus != ERROR_FILE_NOT_FOUND) {
  571. errmsg("Cannot delete registry value", WStatus);
  572. goto CLEANUP;
  573. }
  574. //
  575. // Delete the subkeys
  576. //
  577. do {
  578. WStatus = RegEnumKey(HKey, 0, KeyBuf, MAX_PATH + 1);
  579. if (WIN_SUCCESS(WStatus)) {
  580. WStatus = RegDeleteKey(HKey, KeyBuf);
  581. }
  582. } while (WIN_SUCCESS(WStatus));
  583. if (WStatus != ERROR_NO_MORE_ITEMS) {
  584. errmsg("Cannot delete registry key", WStatus);
  585. goto CLEANUP;
  586. }
  587. //
  588. // SUCCESS
  589. //
  590. RetValue = TRUE;
  591. CLEANUP:
  592. if (HKey) {
  593. RegCloseKey(HKey);
  594. }
  595. return RetValue;
  596. }
  597. //
  598. // Set FRS to auto start
  599. //
  600. BOOLEAN
  601. SetFRSAutoStart( void )
  602. {
  603. SC_HANDLE ServiceHandle = NULL;
  604. SC_HANDLE SCMHandle = NULL;
  605. BOOLEAN RetValue = FALSE;
  606. printf( "Set NTFRS to Auto Start\n" );
  607. //
  608. // Contact the SC manager.
  609. //
  610. SCMHandle = OpenSCManager(NULL,
  611. NULL,
  612. SC_MANAGER_CONNECT);
  613. if (SCMHandle == NULL) {
  614. errmsg("Can't set NtFrs to Auto Start", GetLastError());
  615. goto CLEANUP;
  616. }
  617. //
  618. // Contact the NtFrs service.
  619. //
  620. ServiceHandle = OpenService(SCMHandle,
  621. DSROLEP_FRS_SHORT_NAME,
  622. SERVICE_INTERROGATE |
  623. SERVICE_PAUSE_CONTINUE |
  624. SERVICE_QUERY_STATUS |
  625. SERVICE_START |
  626. SERVICE_STOP |
  627. SERVICE_CHANGE_CONFIG);
  628. if (ServiceHandle == NULL) {
  629. errmsg("Can't set NtFrs to Auto Start", GetLastError());
  630. goto CLEANUP;
  631. }
  632. //
  633. // Service starts automatically at startup
  634. //
  635. if (!ChangeServiceConfig(ServiceHandle,
  636. SERVICE_NO_CHANGE,
  637. SERVICE_AUTO_START,
  638. SERVICE_NO_CHANGE,
  639. NULL,
  640. NULL,
  641. NULL,
  642. NULL,
  643. NULL,
  644. NULL,
  645. DSROLEP_FRS_LONG_NAME)) {
  646. errmsg("Can't set NtFrs to Auto Start", GetLastError());
  647. goto CLEANUP;
  648. }
  649. //
  650. // SUCCESS
  651. //
  652. RetValue = TRUE;
  653. CLEANUP:
  654. if (SCMHandle) {
  655. CloseServiceHandle(SCMHandle);
  656. }
  657. if (ServiceHandle) {
  658. CloseServiceHandle(ServiceHandle);
  659. }
  660. return RetValue;
  661. }
  662. //
  663. // Start FRS
  664. //
  665. BOOLEAN
  666. StartFRS( void )
  667. {
  668. DWORD WStatus;
  669. SC_HANDLE ServiceHandle = NULL;
  670. SC_HANDLE SCMHandle = NULL;
  671. SERVICE_STATUS ServiceStatus;
  672. BOOLEAN RetValue = FALSE;
  673. printf( "Start NTFRS\n" );
  674. //
  675. // Contact the SC manager.
  676. //
  677. SCMHandle = OpenSCManager(NULL,
  678. NULL,
  679. SC_MANAGER_CONNECT);
  680. if (SCMHandle == NULL) {
  681. errmsg("Can't start NtFrs", GetLastError());
  682. goto CLEANUP;
  683. }
  684. //
  685. // Contact the NtFrs service.
  686. //
  687. ServiceHandle = OpenService(SCMHandle,
  688. DSROLEP_FRS_SHORT_NAME,
  689. SERVICE_INTERROGATE |
  690. SERVICE_PAUSE_CONTINUE |
  691. SERVICE_QUERY_STATUS |
  692. SERVICE_START |
  693. SERVICE_STOP |
  694. SERVICE_CHANGE_CONFIG);
  695. if (ServiceHandle == NULL) {
  696. errmsg("Can't start NtFrs", GetLastError());
  697. goto CLEANUP;
  698. }
  699. //
  700. // stop the service
  701. //
  702. ControlService(ServiceHandle, SERVICE_CONTROL_STOP, &ServiceStatus);
  703. //
  704. // Start the service
  705. //
  706. if (!StartService(ServiceHandle, 0, NULL)) {
  707. //
  708. // May be shutting down; retry in a bit
  709. //
  710. Sleep(3 * 1000);
  711. if (!StartService(ServiceHandle, 0, NULL)) {
  712. WStatus = GetLastError();
  713. if (WStatus != ERROR_SERVICE_ALREADY_RUNNING) {
  714. errmsg("Can't start NtFrs", WStatus);
  715. goto CLEANUP;
  716. }
  717. }
  718. }
  719. //
  720. // SUCCESS
  721. //
  722. RetValue = TRUE;
  723. CLEANUP:
  724. if (SCMHandle) {
  725. CloseServiceHandle(SCMHandle);
  726. }
  727. if (ServiceHandle) {
  728. CloseServiceHandle(ServiceHandle);
  729. }
  730. return RetValue;
  731. }
  732. //
  733. // Stop FRS
  734. //
  735. BOOLEAN
  736. StopFRS( void )
  737. {
  738. DWORD WStatus;
  739. SC_HANDLE ServiceHandle;
  740. SC_HANDLE SCMHandle;
  741. SERVICE_STATUS ServiceStatus;
  742. //
  743. // Contact the SC manager.
  744. //
  745. SCMHandle = OpenSCManager(NULL,
  746. NULL,
  747. SC_MANAGER_CONNECT);
  748. if (SCMHandle == NULL) {
  749. errmsg("Can't stop NtFrs", GetLastError());
  750. return FALSE;
  751. }
  752. //
  753. // Contact the NtFrs service.
  754. //
  755. ServiceHandle = OpenService(SCMHandle,
  756. DSROLEP_FRS_SHORT_NAME,
  757. SERVICE_INTERROGATE |
  758. SERVICE_PAUSE_CONTINUE |
  759. SERVICE_QUERY_STATUS |
  760. SERVICE_START |
  761. SERVICE_STOP |
  762. SERVICE_CHANGE_CONFIG);
  763. if (ServiceHandle == NULL) {
  764. errmsg("Can't Stop NtFrs", GetLastError());
  765. return FALSE;
  766. }
  767. CloseServiceHandle(SCMHandle);
  768. //
  769. // stop the service
  770. //
  771. STOP_AGAIN:
  772. if (!ControlService(ServiceHandle, SERVICE_CONTROL_STOP, &ServiceStatus)) {
  773. WStatus = GetLastError();
  774. if (WStatus != ERROR_SERVICE_REQUEST_TIMEOUT &&
  775. WStatus != ERROR_SERVICE_NOT_ACTIVE) {
  776. errmsg("Can't Stop NtFrs", WStatus);
  777. CloseServiceHandle(ServiceHandle);
  778. return FALSE;
  779. }
  780. }
  781. if (!QueryServiceStatus(ServiceHandle, &ServiceStatus)) {
  782. errmsg("Can't Stop NtFrs", GetLastError());
  783. CloseServiceHandle(ServiceHandle);
  784. return FALSE;
  785. }
  786. if (ServiceStatus.dwCurrentState == SERVICE_STOP_PENDING) {
  787. Sleep(5 * 1000);
  788. goto STOP_AGAIN;
  789. }
  790. if (ServiceStatus.dwCurrentState != SERVICE_STOPPED) {
  791. fprintf(stderr,
  792. "Can't stop NtFrs; NtFrs is in state %d\n",
  793. ServiceStatus.dwCurrentState);
  794. CloseServiceHandle(ServiceHandle);
  795. return FALSE;
  796. }
  797. //
  798. // SUCCESS
  799. //
  800. CloseServiceHandle(ServiceHandle);
  801. return TRUE;
  802. }
  803. ////////
  804. //
  805. // BEGIN code that processes -restore option
  806. //
  807. ///////
  808. ULONG
  809. UpgSetLastNTError(
  810. NTSTATUS Status
  811. )
  812. /*++
  813. Routine Description:
  814. Translate NT status codes to WIN32 status codes for those functions that
  815. make NT calls. Map a few status values differently.
  816. Arguments:
  817. Status - the NTstatus to map.
  818. Return Value:
  819. The WIN32 status. Also puts this into LastError.
  820. --*/
  821. {
  822. ULONG WStatus;
  823. //
  824. // Do the standard system mapping first.
  825. //
  826. WStatus = RtlNtStatusToDosError( Status );
  827. SetLastError( WStatus );
  828. return WStatus;
  829. }
  830. BOOL
  831. UpgGetFileInfoByHandle(
  832. IN PWCHAR Name,
  833. IN HANDLE Handle,
  834. OUT PFILE_NETWORK_OPEN_INFORMATION FileOpenInfo
  835. )
  836. /*++
  837. Routine Description:
  838. Return the network file info for the specified handle.
  839. Arguments:
  840. Name - File's name for printing error messages
  841. Handle - Open file handle
  842. FileOpenInfo - Returns the file FILE_NETWORK_OPEN_INFORMATION data.
  843. Return Value:
  844. TRUE - FileOpenInfo contains the file's info
  845. FALSE - Contents of FileOpenInfo is undefined
  846. --*/
  847. {
  848. DWORD WStatus;
  849. NTSTATUS NtStatus;
  850. IO_STATUS_BLOCK IoStatusBlock;
  851. //
  852. // Return some file info
  853. //
  854. NtStatus = NtQueryInformationFile(Handle,
  855. &IoStatusBlock,
  856. FileOpenInfo,
  857. sizeof(FILE_NETWORK_OPEN_INFORMATION),
  858. FileNetworkOpenInformation);
  859. if (!NT_SUCCESS(NtStatus)) {
  860. WStatus = UpgSetLastNTError(NtStatus);
  861. return FALSE;
  862. }
  863. return TRUE;
  864. }
  865. BOOL
  866. UpgSetFileAttributes(
  867. PWCHAR Name,
  868. HANDLE Handle,
  869. ULONG FileAttributes
  870. )
  871. /*++
  872. Routine Description:
  873. This routine sets the file's attributes
  874. Arguments:
  875. Name - for error messages
  876. Handle - Supplies a handle to the file that is to be marked for delete.
  877. Attributes - Attributes for the file
  878. Return Value:
  879. TRUE - attributes have been set
  880. FALSE
  881. --*/
  882. {
  883. IO_STATUS_BLOCK IoStatus;
  884. FILE_BASIC_INFORMATION BasicInformation;
  885. DWORD WStatus;
  886. NTSTATUS NtStatus;
  887. //
  888. // Set the attributes
  889. //
  890. ZeroMemory(&BasicInformation, sizeof(BasicInformation));
  891. BasicInformation.FileAttributes = FileAttributes | FILE_ATTRIBUTE_NORMAL;
  892. NtStatus = NtSetInformationFile(Handle,
  893. &IoStatus,
  894. &BasicInformation,
  895. sizeof(BasicInformation),
  896. FileBasicInformation);
  897. if (!NT_SUCCESS(NtStatus)) {
  898. WStatus = UpgSetLastNTError(NtStatus);
  899. return FALSE;
  900. }
  901. return TRUE;
  902. }
  903. BOOL
  904. UpgResetAttributesForDelete(
  905. PWCHAR Name,
  906. HANDLE Handle
  907. )
  908. /*++
  909. Routine Description:
  910. This routine turns off the attributes that prevent deletion
  911. Arguments:
  912. Name - for error messages
  913. Handle - Supplies a handle to the file that is to be marked for delete.
  914. Return Value:
  915. None.
  916. --*/
  917. {
  918. FILE_NETWORK_OPEN_INFORMATION FileInfo;
  919. //
  920. // Get the file's attributes
  921. //
  922. if (!UpgGetFileInfoByHandle(Name, Handle, &FileInfo)) {
  923. return FALSE;
  924. }
  925. //
  926. // Turn off the access attributes that prevent deletion and write
  927. //
  928. if (FileInfo.FileAttributes & NOREPL_ATTRIBUTES) {
  929. if (!UpgSetFileAttributes(Name, Handle,
  930. FileInfo.FileAttributes & ~NOREPL_ATTRIBUTES)) {
  931. return FALSE;
  932. }
  933. }
  934. return TRUE;
  935. }
  936. DWORD
  937. UpgEnumerateDirectory(
  938. IN HANDLE DirectoryHandle,
  939. IN PWCHAR DirectoryName,
  940. IN DWORD DirectoryLevel,
  941. IN DWORD DirectoryFlags,
  942. IN PVOID Context,
  943. IN PENUMERATE_DIRECTORY_ROUTINE Function
  944. )
  945. /*++
  946. Routine Description:
  947. Enumerate the directory identified by DirectoryHandle, passing each
  948. directory record to Function. If the record is for a directory,
  949. call Function before recursing if ProcessBeforeCallingFunction
  950. is TRUE.
  951. Function controls the enumeration of the CURRENT directory
  952. by setting ContinueEnumeration to TRUE (continue) or
  953. FALSE (terminate).
  954. Function controls the enumeration of the entire directory
  955. tree by returning a WIN32 STATUS that is not ERROR_SUCCESS.
  956. UpgEnumerateDirectory() will terminate the entire directory
  957. enumeration by returning a WIN32 STATUS other than ERROR_SUCCESS
  958. when encountering an error.
  959. Context passes global info from the caller to Function.
  960. Arguments:
  961. DirectoryHandle - Handle for this directory.
  962. DirectoryName - Relative name of directory
  963. DirectoryLevel - Directory level
  964. DirectoryFlags - See tablefcn.h, ENUMERATE_DIRECTORY_FLAGS_
  965. Context - Passes global info from the caller to Function
  966. Function - Called for every record
  967. Return Value:
  968. WIN32 STATUS
  969. --*/
  970. {
  971. DWORD WStatus;
  972. NTSTATUS NtStatus;
  973. BOOL Recurse;
  974. PFILE_DIRECTORY_INFORMATION DirectoryRecord;
  975. PFILE_DIRECTORY_INFORMATION DirectoryBuffer = NULL;
  976. BOOLEAN RestartScan = TRUE;
  977. PWCHAR FileName = NULL;
  978. DWORD FileNameLength = 0;
  979. DWORD NumBuffers = 0;
  980. DWORD NumRecords = 0;
  981. UNICODE_STRING ObjectName;
  982. OBJECT_ATTRIBUTES ObjectAttributes;
  983. IO_STATUS_BLOCK IoStatusBlock;
  984. //
  985. // The buffer size is configurable with registry value
  986. // ENUMERATE_DIRECTORY_SIZE
  987. //
  988. DirectoryBuffer = (PFILE_DIRECTORY_INFORMATION)malloc(DEFAULT_ENUMERATE_DIRECTORY_SIZE);
  989. if (DirectoryBuffer == NULL) {
  990. WStatus = ERROR_NOT_ENOUGH_MEMORY;
  991. goto CLEANUP;
  992. }
  993. ZeroMemory(DirectoryBuffer, DEFAULT_ENUMERATE_DIRECTORY_SIZE);
  994. NEXT_BUFFER:
  995. //
  996. // READ A BUFFER FULL OF DIRECTORY INFORMATION
  997. //
  998. NtStatus = NtQueryDirectoryFile(DirectoryHandle, // Directory Handle
  999. NULL, // Event
  1000. NULL, // ApcRoutine
  1001. NULL, // ApcContext
  1002. &IoStatusBlock,
  1003. DirectoryBuffer,
  1004. DEFAULT_ENUMERATE_DIRECTORY_SIZE,
  1005. FileDirectoryInformation,
  1006. FALSE, // return single entry
  1007. NULL, // FileName
  1008. RestartScan // restart scan
  1009. );
  1010. //
  1011. // Enumeration Complete
  1012. //
  1013. if (NtStatus == STATUS_NO_MORE_FILES) {
  1014. WStatus = ERROR_SUCCESS;
  1015. goto CLEANUP;
  1016. }
  1017. //
  1018. // Error enumerating directory; return to caller
  1019. //
  1020. if (!NT_SUCCESS(NtStatus)) {
  1021. WStatus = UpgSetLastNTError(NtStatus);
  1022. errmsg(DirectoryName, WStatus);
  1023. if (DirectoryFlags & ENUMERATE_DIRECTORY_FLAGS_ERROR_CONTINUE) {
  1024. //
  1025. // Don't abort the entire enumeration; just this directory
  1026. //
  1027. WStatus = ERROR_SUCCESS;
  1028. }
  1029. goto CLEANUP;
  1030. }
  1031. ++NumBuffers;
  1032. //
  1033. // PROCESS DIRECTORY RECORDS
  1034. //
  1035. DirectoryRecord = DirectoryBuffer;
  1036. NEXT_RECORD:
  1037. ++NumRecords;
  1038. //
  1039. // Filter . and ..
  1040. //
  1041. if (DirectoryRecord->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  1042. //
  1043. // Skip .
  1044. //
  1045. if (DirectoryRecord->FileNameLength == 2 &&
  1046. DirectoryRecord->FileName[0] == L'.') {
  1047. goto ADVANCE_TO_NEXT_RECORD;
  1048. }
  1049. //
  1050. // Skip ..
  1051. //
  1052. if (DirectoryRecord->FileNameLength == 4 &&
  1053. DirectoryRecord->FileName[0] == L'.' &&
  1054. DirectoryRecord->FileName[1] == L'.') {
  1055. goto ADVANCE_TO_NEXT_RECORD;
  1056. }
  1057. }
  1058. //
  1059. // Add a terminating NULL to the FileName (painful)
  1060. //
  1061. if (FileNameLength < DirectoryRecord->FileNameLength + sizeof(WCHAR)) {
  1062. FREE(FileName);
  1063. FileNameLength = DirectoryRecord->FileNameLength + sizeof(WCHAR);
  1064. FileName = (PWCHAR)malloc(FileNameLength);
  1065. if (FileName == NULL) {
  1066. WStatus = ERROR_NOT_ENOUGH_MEMORY;
  1067. goto CLEANUP;
  1068. }
  1069. }
  1070. CopyMemory(FileName, DirectoryRecord->FileName, DirectoryRecord->FileNameLength);
  1071. FileName[DirectoryRecord->FileNameLength / sizeof(WCHAR)] = UNICODE_NULL;
  1072. //
  1073. // Process the record
  1074. //
  1075. WStatus = (*Function)(DirectoryHandle,
  1076. DirectoryName,
  1077. DirectoryLevel,
  1078. DirectoryRecord,
  1079. DirectoryFlags,
  1080. FileName,
  1081. Context);
  1082. if (!WIN_SUCCESS(WStatus)) {
  1083. if (DirectoryFlags & ENUMERATE_DIRECTORY_FLAGS_ERROR_CONTINUE) {
  1084. //
  1085. // Don't abort the entire enumeration; just this entry
  1086. //
  1087. WStatus = ERROR_SUCCESS;
  1088. } else {
  1089. //
  1090. // Abort the entire enumeration
  1091. //
  1092. goto CLEANUP;
  1093. }
  1094. }
  1095. ADVANCE_TO_NEXT_RECORD:
  1096. //
  1097. // Next record
  1098. //
  1099. if (DirectoryRecord->NextEntryOffset) {
  1100. DirectoryRecord = (PFILE_DIRECTORY_INFORMATION)(((PCHAR)DirectoryRecord) + DirectoryRecord->NextEntryOffset);
  1101. goto NEXT_RECORD;
  1102. }
  1103. //
  1104. // Done with this buffer; go get another one
  1105. // But don't restart the scan for every loop!
  1106. //
  1107. RestartScan = FALSE;
  1108. goto NEXT_BUFFER;
  1109. CLEANUP:
  1110. FREE(FileName);
  1111. FREE(DirectoryBuffer);
  1112. return WStatus;
  1113. }
  1114. DWORD
  1115. UpgEnumerateDirectoryRecurse(
  1116. IN HANDLE DirectoryHandle,
  1117. IN PWCHAR DirectoryName,
  1118. IN DWORD DirectoryLevel,
  1119. IN PFILE_DIRECTORY_INFORMATION DirectoryRecord,
  1120. IN DWORD DirectoryFlags,
  1121. IN PWCHAR FileName,
  1122. IN HANDLE FileHandle,
  1123. IN PVOID Context,
  1124. IN PENUMERATE_DIRECTORY_ROUTINE Function
  1125. )
  1126. /*++
  1127. Routine Description:
  1128. Open the directory identified by FileName in the directory
  1129. identified by DirectoryHandle and call UpgEnumerateDirectory().
  1130. Arguments:
  1131. DirectoryHandle - Handle for this directory.
  1132. DirectoryName - Relative name of directory
  1133. DirectoryLevel - Directory level
  1134. DirectoryRecord - From UpgEnumerateRecord()
  1135. DirectoryFlags - See tablefcn.h, ENUMERATE_DIRECTORY_FLAGS_
  1136. FileName - Open this directory and recurse
  1137. FileHandle - Use for FileName if not INVALID_HANDLE_VALUE
  1138. Context - Passes global info from the caller to Function
  1139. Function - Called for every record
  1140. Return Value:
  1141. WIN32 STATUS
  1142. --*/
  1143. {
  1144. DWORD WStatus;
  1145. NTSTATUS NtStatus;
  1146. HANDLE LocalHandle = INVALID_HANDLE_VALUE;
  1147. UNICODE_STRING ObjectName;
  1148. OBJECT_ATTRIBUTES ObjectAttributes;
  1149. IO_STATUS_BLOCK IoStatusBlock;
  1150. //
  1151. // Relative open
  1152. //
  1153. if (!HANDLE_IS_VALID(FileHandle)) {
  1154. ZeroMemory(&ObjectAttributes, sizeof(OBJECT_ATTRIBUTES));
  1155. ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
  1156. ObjectName.Length = (USHORT)DirectoryRecord->FileNameLength;
  1157. ObjectName.MaximumLength = (USHORT)DirectoryRecord->FileNameLength;
  1158. ObjectName.Buffer = DirectoryRecord->FileName;
  1159. ObjectAttributes.ObjectName = &ObjectName;
  1160. ObjectAttributes.RootDirectory = DirectoryHandle;
  1161. NtStatus = NtCreateFile(&LocalHandle,
  1162. READ_ACCESS,
  1163. &ObjectAttributes,
  1164. &IoStatusBlock,
  1165. NULL, // AllocationSize
  1166. FILE_ATTRIBUTE_NORMAL,
  1167. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1168. FILE_OPEN,
  1169. FILE_OPEN_REPARSE_POINT |
  1170. FILE_SEQUENTIAL_ONLY |
  1171. FILE_SYNCHRONOUS_IO_NONALERT,
  1172. NULL, // EA buffer
  1173. 0 // EA buffer size
  1174. );
  1175. //
  1176. // Error opening directory
  1177. //
  1178. if (!NT_SUCCESS(NtStatus)) {
  1179. WStatus = UpgSetLastNTError(NtStatus);
  1180. errmsg(FileName, WStatus);
  1181. if (DirectoryFlags & ENUMERATE_DIRECTORY_FLAGS_ERROR_CONTINUE) {
  1182. //
  1183. // Skip this directory tree
  1184. //
  1185. WStatus = ERROR_SUCCESS;
  1186. }
  1187. goto CLEANUP;
  1188. }
  1189. FileHandle = LocalHandle;
  1190. }
  1191. //
  1192. // RECURSE
  1193. //
  1194. WStatus = UpgEnumerateDirectory(FileHandle,
  1195. FileName,
  1196. DirectoryLevel + 1,
  1197. DirectoryFlags,
  1198. Context,
  1199. Function);
  1200. CLEANUP:
  1201. FRS_CLOSE(LocalHandle);
  1202. return WStatus;
  1203. }
  1204. DWORD
  1205. UpgDeleteByHandle(
  1206. IN PWCHAR Name,
  1207. IN HANDLE Handle
  1208. )
  1209. /*++
  1210. Routine Description:
  1211. This routine marks a file for delete, so that when the supplied handle
  1212. is closed, the file will actually be deleted.
  1213. Arguments:
  1214. Name - for error messages
  1215. Handle - Supplies a handle to the file that is to be marked for delete.
  1216. Return Value:
  1217. Win Status
  1218. --*/
  1219. {
  1220. FILE_DISPOSITION_INFORMATION DispositionInformation;
  1221. IO_STATUS_BLOCK IoStatus;
  1222. NTSTATUS NtStatus;
  1223. DWORD WStatus;
  1224. if (!HANDLE_IS_VALID(Handle)) {
  1225. return ERROR_SUCCESS;
  1226. }
  1227. //
  1228. // Mark the file for delete. The delete happens when the handle is closed.
  1229. //
  1230. #undef DeleteFile
  1231. DispositionInformation.DeleteFile = TRUE;
  1232. NtStatus = NtSetInformationFile(Handle,
  1233. &IoStatus,
  1234. &DispositionInformation,
  1235. sizeof(DispositionInformation),
  1236. FileDispositionInformation);
  1237. if (!NT_SUCCESS(NtStatus)) {
  1238. WStatus = UpgSetLastNTError(NtStatus);
  1239. return WStatus;
  1240. }
  1241. return ERROR_SUCCESS;
  1242. }
  1243. DWORD
  1244. UpgEnumerateDirectoryDeleteWorker(
  1245. IN HANDLE DirectoryHandle,
  1246. IN PWCHAR DirectoryName,
  1247. IN DWORD DirectoryLevel,
  1248. IN PFILE_DIRECTORY_INFORMATION DirectoryRecord,
  1249. IN DWORD DirectoryFlags,
  1250. IN PWCHAR FileName,
  1251. IN PVOID Ignored
  1252. )
  1253. /*++
  1254. Routine Description:
  1255. Empty a directory of non-replicating files and dirs if this is
  1256. an ERROR_DIR_NOT_EMPTY and this is a retry change order for a
  1257. directory delete.
  1258. Arguments:
  1259. DirectoryHandle - Handle for this directory.
  1260. DirectoryName - Relative name of directory
  1261. DirectoryLevel - Directory level (0 == root)
  1262. DirectoryFlags - See tablefcn.h, ENUMERATE_DIRECTORY_FLAGS_
  1263. DirectoryRecord - Record from DirectoryHandle
  1264. FileName - From DirectoryRecord (w/terminating NULL)
  1265. Ignored - Context is ignored
  1266. Return Value:
  1267. Win32 Status
  1268. --*/
  1269. {
  1270. DWORD WStatus;
  1271. NTSTATUS NtStatus;
  1272. HANDLE Handle = INVALID_HANDLE_VALUE;
  1273. UNICODE_STRING ObjectName;
  1274. OBJECT_ATTRIBUTES ObjectAttributes;
  1275. IO_STATUS_BLOCK IoStatusBlock;
  1276. //
  1277. // Depth first
  1278. //
  1279. if (DirectoryRecord->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  1280. WStatus = UpgEnumerateDirectoryRecurse(DirectoryHandle,
  1281. DirectoryName,
  1282. DirectoryLevel,
  1283. DirectoryRecord,
  1284. DirectoryFlags,
  1285. FileName,
  1286. INVALID_HANDLE_VALUE,
  1287. Ignored,
  1288. UpgEnumerateDirectoryDeleteWorker);
  1289. if (!WIN_SUCCESS(WStatus)) {
  1290. goto CLEANUP;
  1291. }
  1292. }
  1293. //
  1294. // Relative open
  1295. //
  1296. ZeroMemory(&ObjectAttributes, sizeof(OBJECT_ATTRIBUTES));
  1297. ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
  1298. ObjectName.Length = (USHORT)DirectoryRecord->FileNameLength;
  1299. ObjectName.MaximumLength = (USHORT)DirectoryRecord->FileNameLength;
  1300. ObjectName.Buffer = DirectoryRecord->FileName;
  1301. ObjectAttributes.ObjectName = &ObjectName;
  1302. ObjectAttributes.RootDirectory = DirectoryHandle;
  1303. NtStatus = NtCreateFile(&Handle,
  1304. GENERIC_READ |
  1305. SYNCHRONIZE |
  1306. DELETE |
  1307. FILE_WRITE_ATTRIBUTES,
  1308. &ObjectAttributes,
  1309. &IoStatusBlock,
  1310. NULL, // AllocationSize
  1311. FILE_ATTRIBUTE_NORMAL,
  1312. FILE_SHARE_READ |
  1313. FILE_SHARE_WRITE |
  1314. FILE_SHARE_DELETE,
  1315. FILE_OPEN,
  1316. FILE_OPEN_REPARSE_POINT |
  1317. FILE_SYNCHRONOUS_IO_NONALERT,
  1318. NULL, // EA buffer
  1319. 0 // EA buffer size
  1320. );
  1321. //
  1322. // Error opening file or directory
  1323. //
  1324. if (!NT_SUCCESS(NtStatus)) {
  1325. WStatus = UpgSetLastNTError(NtStatus);
  1326. errmsg(FileName, WStatus);
  1327. goto CLEANUP;
  1328. }
  1329. //
  1330. // Turn off readonly, system, and hidden
  1331. //
  1332. UpgResetAttributesForDelete(FileName, Handle);
  1333. //
  1334. // Delete the file
  1335. //
  1336. WStatus = UpgDeleteByHandle(FileName, Handle);
  1337. if (!WIN_SUCCESS(WStatus)) {
  1338. errmsg(FileName, WStatus);
  1339. }
  1340. CLEANUP:
  1341. FRS_CLOSE(Handle);
  1342. return WStatus;
  1343. }
  1344. DWORD
  1345. UpgOpenDirectoryPath(
  1346. OUT PHANDLE Handle,
  1347. IN PWCHAR lpFileName
  1348. )
  1349. /*++
  1350. Routine Description:
  1351. This function opens the specified directory
  1352. Arguments:
  1353. Handle - A pointer to a handle to return an open handle.
  1354. lpFileName - Represents the name of the directory to be opened.
  1355. Return Value:
  1356. Win32 Status
  1357. --*/
  1358. {
  1359. DWORD WStatus;
  1360. NTSTATUS NtStatus;
  1361. OBJECT_ATTRIBUTES Obja;
  1362. UNICODE_STRING FileName;
  1363. IO_STATUS_BLOCK IoStatusBlock;
  1364. BOOLEAN TranslationStatus;
  1365. RTL_RELATIVE_NAME_U RelativeName;
  1366. PVOID FreeBuffer;
  1367. //
  1368. // Convert the Dos name to an NT name.
  1369. //
  1370. TranslationStatus = RtlDosPathNameToRelativeNtPathName_U(
  1371. lpFileName,
  1372. &FileName,
  1373. NULL,
  1374. &RelativeName
  1375. );
  1376. if ( !TranslationStatus ) {
  1377. return ERROR_BAD_PATHNAME;
  1378. }
  1379. FreeBuffer = FileName.Buffer;
  1380. if ( RelativeName.RelativeName.Length ) {
  1381. FileName = RelativeName.RelativeName;
  1382. }
  1383. else {
  1384. RelativeName.ContainingDirectory = NULL;
  1385. }
  1386. InitializeObjectAttributes(
  1387. &Obja,
  1388. &FileName,
  1389. OBJ_CASE_INSENSITIVE,
  1390. RelativeName.ContainingDirectory,
  1391. NULL
  1392. );
  1393. NtStatus = NtCreateFile(Handle,
  1394. READ_ACCESS,
  1395. &Obja,
  1396. &IoStatusBlock,
  1397. NULL, // Initial allocation size
  1398. FILE_ATTRIBUTE_NORMAL,
  1399. FILE_SHARE_READ |
  1400. FILE_SHARE_WRITE |
  1401. FILE_SHARE_DELETE,
  1402. FILE_OPEN,
  1403. FILE_SEQUENTIAL_ONLY |
  1404. FILE_SYNCHRONOUS_IO_NONALERT,
  1405. NULL,
  1406. 0);
  1407. if ( !NT_SUCCESS(NtStatus) ) {
  1408. *Handle = INVALID_HANDLE_VALUE;
  1409. WStatus = UpgSetLastNTError(NtStatus);
  1410. } else {
  1411. WStatus = ERROR_SUCCESS;
  1412. }
  1413. RtlReleaseRelativeName(&RelativeName);
  1414. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  1415. return WStatus;
  1416. }
  1417. DWORD
  1418. DeleteTree(
  1419. IN PWCHAR Path
  1420. )
  1421. /*++
  1422. Routine Description:
  1423. Delete the contents of Path
  1424. Arguments:
  1425. Path - directory path
  1426. Return Value:
  1427. WIN32 STATUS
  1428. --*/
  1429. {
  1430. DWORD WStatus;
  1431. HANDLE FileHandle = INVALID_HANDLE_VALUE;
  1432. //
  1433. // Done deleting nothing
  1434. //
  1435. if (Path == NULL) {
  1436. return ERROR_SUCCESS;
  1437. }
  1438. //
  1439. // Open directory
  1440. //
  1441. WStatus = UpgOpenDirectoryPath(&FileHandle, Path);
  1442. if (!WIN_SUCCESS(WStatus)) {
  1443. if (WStatus == ERROR_FILE_NOT_FOUND) {
  1444. WStatus = ERROR_SUCCESS;
  1445. goto CLEANUP;
  1446. }
  1447. errmsg(Path, WStatus);
  1448. goto CLEANUP;
  1449. }
  1450. //
  1451. // RECURSE
  1452. //
  1453. WStatus = UpgEnumerateDirectory(FileHandle,
  1454. Path,
  1455. 1,
  1456. ENUMERATE_DIRECTORY_FLAGS_ERROR_CONTINUE,
  1457. NULL,
  1458. UpgEnumerateDirectoryDeleteWorker);
  1459. CLEANUP:
  1460. FRS_CLOSE(FileHandle);
  1461. return WStatus;
  1462. }
  1463. PWCHAR
  1464. GetConfigString(
  1465. IN HKEY HKey,
  1466. IN PWCHAR Param
  1467. )
  1468. /*++
  1469. Routine Description:
  1470. This function reads a keyword value from the registry.
  1471. Arguments:
  1472. HKey - Key to be read
  1473. Param - item for which we want the value
  1474. Return Value:
  1475. String or NULL. Free with free().
  1476. --*/
  1477. {
  1478. DWORD WStatus;
  1479. DWORD Type;
  1480. DWORD Len;
  1481. DWORD Bytes;
  1482. PWCHAR RetValue;
  1483. WCHAR Value[MAX_PATH + 1];
  1484. //
  1485. // Read the value
  1486. //
  1487. Len = sizeof(Value);
  1488. WStatus = RegQueryValueEx(HKey, Param, NULL, &Type, (PUCHAR)&Value[0], &Len);
  1489. if (!WIN_SUCCESS(WStatus)) {
  1490. return NULL;
  1491. }
  1492. //
  1493. // Duplicate the string
  1494. //
  1495. if (Type == REG_SZ) {
  1496. Bytes = (wcslen(Value) + 1) * sizeof(WCHAR);
  1497. RetValue = (PWCHAR)malloc(Bytes);
  1498. if (RetValue != NULL) {
  1499. CopyMemory(RetValue, Value, Bytes);
  1500. }
  1501. return RetValue;
  1502. }
  1503. return NULL;
  1504. }
  1505. //
  1506. // RestoreFRS
  1507. //
  1508. DWORD
  1509. RestoreFRS( IN BOOLEAN IsYes )
  1510. {
  1511. DWORD WStatus = ERROR_SUCCESS;
  1512. DWORD KeyIdx;
  1513. DWORD SysvolReady;
  1514. HKEY HKey = 0;
  1515. HKEY HSetsKey = 0;
  1516. HKEY HSetKey = 0;
  1517. HKEY HNetKey = 0;
  1518. PWCHAR Value = NULL;
  1519. BOOLEAN DeleteIt = FALSE;
  1520. WCHAR KeyBuf[MAX_PATH + 1];
  1521. CHAR InStr[512];
  1522. PCHAR pInStr;
  1523. if (!StopFRS()) {
  1524. return 1;
  1525. }
  1526. //
  1527. // Open the NtFrs parameters key
  1528. //
  1529. WStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1530. FRS_CONFIG_SECTION,
  1531. 0,
  1532. KEY_ALL_ACCESS,
  1533. &HKey);
  1534. if (!WIN_SUCCESS(WStatus)) {
  1535. errmsg(FRS_CONFIG_SECTION, WStatus);
  1536. goto CLEANUP;
  1537. }
  1538. //
  1539. // Open (or create) the Replica Sets key
  1540. //
  1541. WStatus = RegCreateKey(HKey,
  1542. FRS_SETS_KEY,
  1543. &HSetsKey);
  1544. if (!WIN_SUCCESS(WStatus)) {
  1545. errmsg(FRS_SETS_KEY, WStatus);
  1546. goto CLEANUP;
  1547. }
  1548. Value = GetConfigString(HSetsKey, JET_PATH);
  1549. if (!Value) {
  1550. goto CLEANUP;
  1551. }
  1552. //
  1553. // We have a jet path; see if the user wants to
  1554. // delete it.
  1555. //
  1556. ASK_STATE_AGAIN:
  1557. if (Value) {
  1558. //
  1559. // The user did not specify yes to all so query
  1560. //
  1561. if (!IsYes) {
  1562. //
  1563. // Describe the situation
  1564. //
  1565. printf("\nDelete File Replication Service state? [yn] ");
  1566. //
  1567. // Query the user
  1568. //
  1569. pInStr = gets(InStr);
  1570. printf("\n");
  1571. //
  1572. // Query resulted in NULL?
  1573. //
  1574. if (!pInStr) {
  1575. //
  1576. // Eof; query again
  1577. //
  1578. if (feof(stdin)) {
  1579. goto ASK_STATE_AGAIN;
  1580. }
  1581. //
  1582. // Error; exit
  1583. //
  1584. if (ferror(stdin)) {
  1585. fprintf(stderr, "Error reading stdin.\n");
  1586. WStatus = ERROR_OPERATION_ABORTED;
  1587. goto CLEANUP;
  1588. }
  1589. }
  1590. //
  1591. // Accept only y or n
  1592. //
  1593. if (*pInStr != 'y' &&
  1594. *pInStr != 'Y' &&
  1595. *pInStr != 'n' &&
  1596. *pInStr != 'N') {
  1597. goto ASK_STATE_AGAIN;
  1598. }
  1599. }
  1600. //
  1601. // If yes to all or a query resulted in yes; delete root
  1602. //
  1603. if (IsYes || *pInStr == 'y' || *pInStr == 'Y') {
  1604. WStatus = DeleteTree(Value);
  1605. if (!WIN_SUCCESS(WStatus)) {
  1606. goto CLEANUP;
  1607. }
  1608. //
  1609. // Access the netlogon\parameters key
  1610. //
  1611. WStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1612. NETLOGON_SECTION,
  1613. 0,
  1614. KEY_ALL_ACCESS,
  1615. &HNetKey);
  1616. if (WIN_SUCCESS(WStatus)) {
  1617. //
  1618. // Tell NetLogon to stop sharing the sysvol
  1619. //
  1620. SysvolReady = 0;
  1621. WStatus = RegSetValueEx(HNetKey,
  1622. SYSVOL_READY,
  1623. 0,
  1624. REG_DWORD,
  1625. (PUCHAR)&SysvolReady,
  1626. sizeof(DWORD));
  1627. }
  1628. WStatus = ERROR_SUCCESS;
  1629. } else {
  1630. WStatus = ERROR_OPERATION_ABORTED;
  1631. goto CLEANUP;
  1632. }
  1633. FREE(Value);
  1634. }
  1635. //
  1636. // Delete the subkeys
  1637. //
  1638. KeyIdx = 0;
  1639. do {
  1640. WStatus = RegEnumKey(HSetsKey, KeyIdx, KeyBuf, MAX_PATH + 1);
  1641. if (WIN_SUCCESS(WStatus)) {
  1642. //
  1643. // Open (or create) a replica set key
  1644. //
  1645. WStatus = RegCreateKey(HSetsKey,
  1646. KeyBuf,
  1647. &HSetKey);
  1648. if (!WIN_SUCCESS(WStatus)) {
  1649. errmsg(KeyBuf, WStatus);
  1650. goto CLEANUP;
  1651. } else {
  1652. Value = GetConfigString(HSetKey, REPLICA_SET_ROOT);
  1653. //
  1654. // We have a root path; see if the user wants to
  1655. // delete it.
  1656. //
  1657. ASK_AGAIN:
  1658. if (Value) {
  1659. //
  1660. // The user did not specify yes to all so query
  1661. //
  1662. if (!IsYes) {
  1663. //
  1664. // Describe the situation
  1665. //
  1666. printf(
  1667. "\nThe contents of the replicated directory %ws \n"
  1668. "will be deleted with the expectation that the data \n"
  1669. "can be retrieved from a replication partner at a later \n"
  1670. "time. The contents of %ws should not be deleted \n"
  1671. "if there are no replication partners. \n\n"
  1672. "Are there replication partners that can supply the \n"
  1673. "data for %ws at a later time? [yn] ",
  1674. Value,
  1675. Value,
  1676. Value);
  1677. //
  1678. // Query the user
  1679. //
  1680. pInStr = gets(InStr);
  1681. printf("\n");
  1682. //
  1683. // Query resulted in NULL?
  1684. //
  1685. if (!pInStr) {
  1686. //
  1687. // Eof; query again
  1688. //
  1689. if (feof(stdin)) {
  1690. goto ASK_AGAIN;
  1691. }
  1692. //
  1693. // Error; exit
  1694. //
  1695. if (ferror(stdin)) {
  1696. fprintf(stderr, "Error reading stdin.\n");
  1697. WStatus = ERROR_OPERATION_ABORTED;
  1698. goto CLEANUP;
  1699. }
  1700. }
  1701. //
  1702. // Accept only y or n
  1703. //
  1704. if (*pInStr != 'y' &&
  1705. *pInStr != 'Y' &&
  1706. *pInStr != 'n' &&
  1707. *pInStr != 'N') {
  1708. goto ASK_AGAIN;
  1709. }
  1710. }
  1711. //
  1712. // If yes to all or a query resulted in yes; delete root
  1713. //
  1714. if (IsYes || *pInStr == 'y' || *pInStr == 'Y') {
  1715. WStatus = DeleteTree(Value);
  1716. if (!WIN_SUCCESS(WStatus)) {
  1717. goto CLEANUP;
  1718. }
  1719. }
  1720. FREE(Value);
  1721. }
  1722. }
  1723. if (HSetKey) {
  1724. RegCloseKey(HSetKey);
  1725. HSetKey = 0;
  1726. }
  1727. }
  1728. ++KeyIdx;
  1729. } while (WIN_SUCCESS(WStatus));
  1730. if (WStatus != ERROR_NO_MORE_ITEMS) {
  1731. errmsg(FRS_SETS_KEY, WStatus);
  1732. goto CLEANUP;
  1733. }
  1734. //
  1735. // SUCCESS
  1736. //
  1737. WStatus = ERROR_SUCCESS;
  1738. CLEANUP:
  1739. if (HKey) {
  1740. RegCloseKey(HKey);
  1741. }
  1742. if (HSetsKey) {
  1743. RegCloseKey(HSetsKey);
  1744. }
  1745. if (HSetKey) {
  1746. RegCloseKey(HSetKey);
  1747. }
  1748. if (HNetKey) {
  1749. RegCloseKey(HNetKey);
  1750. }
  1751. if (Value) {
  1752. free(Value);
  1753. }
  1754. if (WIN_SUCCESS(WStatus)) {
  1755. return 0;
  1756. }
  1757. return 1;
  1758. }
  1759. ////////
  1760. //
  1761. // END code that processes -restore option
  1762. //
  1763. ///////
  1764. BOOLEAN
  1765. IsThisADC(
  1766. IN PWCHAR domainName )
  1767. {
  1768. DWORD WStatus;
  1769. PWCHAR p;
  1770. DSROLE_PRIMARY_DOMAIN_INFO_BASIC *DsRole;
  1771. //
  1772. // Is this a domain controller?
  1773. //
  1774. WStatus = DsRoleGetPrimaryDomainInformation(NULL,
  1775. DsRolePrimaryDomainInfoBasic,
  1776. (PBYTE *)&DsRole);
  1777. if (!WIN_SUCCESS(WStatus)) {
  1778. errmsg("Can't get primary domain information", WStatus);
  1779. return FALSE;
  1780. }
  1781. //
  1782. // Domain Controller (DC)
  1783. //
  1784. if (DsRole->MachineRole == DsRole_RoleBackupDomainController ||
  1785. DsRole->MachineRole == DsRole_RolePrimaryDomainController) {
  1786. if (!DsRole->DomainNameDns) {
  1787. errmsg( "Unable to get domain name", ERROR_PATH_NOT_FOUND );
  1788. return FALSE;
  1789. }
  1790. wcscpy(domainName, DsRole->DomainNameDns);
  1791. DsRoleFreeMemory(DsRole);
  1792. for( p = domainName; *p != L'\0'; p++ );
  1793. if( *(p-1) == L'.' ) {
  1794. *(p-1) = L'\0';
  1795. }
  1796. return TRUE;
  1797. }
  1798. DsRoleFreeMemory(DsRole);
  1799. return FALSE;
  1800. }
  1801. /*
  1802. * Make it so NTFRS will run on this DC
  1803. */
  1804. __cdecl
  1805. main( int argc, char *argv[] )
  1806. {
  1807. DWORD i;
  1808. LONG retval;
  1809. BOOLEAN IsFirstDCInDomain = FALSE;
  1810. BOOLEAN FixSysvols = FALSE;
  1811. WCHAR SysVolPath[ MAX_PATH ], stage[ MAX_PATH ], root[ MAX_PATH ];
  1812. DWORD pathType;
  1813. BOOLEAN IsRestore = FALSE;
  1814. BOOLEAN IsYes = FALSE;
  1815. WCHAR domainName[512];
  1816. SysVolPath[0] = 0;
  1817. for( i = 1; i < (DWORD)argc; i++ ) {
  1818. switch( argv[i][0] ) {
  1819. case '/':
  1820. case '-':
  1821. switch( argv[i][1] ) {
  1822. case 'D':
  1823. case 'd':
  1824. IsFirstDCInDomain = TRUE;
  1825. break;
  1826. case 'F':
  1827. case 'f':
  1828. FixSysvols = TRUE;
  1829. break;
  1830. case 'R':
  1831. case 'r':
  1832. //
  1833. // Prepare for restore by stopping the service and
  1834. // setting a registry value. The registry value
  1835. // will force the service to DELETE ALL FILES
  1836. // AND DIRECTORIES in the known replica sets and
  1837. // then delete the database the very next time the
  1838. // service starts.
  1839. //
  1840. if (!_stricmp(&argv[i][1], "restore")) {
  1841. IsRestore = TRUE;
  1842. } else {
  1843. fprintf( stderr, "Unrecognized option: %s\n\n", argv[i] );
  1844. Usage( argc, argv );
  1845. return 1;
  1846. }
  1847. break;
  1848. case 'Y':
  1849. case 'y':
  1850. IsYes = TRUE;
  1851. break;
  1852. default:
  1853. fprintf( stderr, "Unrecognized option: %c\n\n", argv[i][1] );
  1854. Usage( argc, argv );
  1855. return 1;
  1856. }
  1857. break;
  1858. default:
  1859. if( SysVolPath[0] != 0 ) {
  1860. fprintf( stderr, "Too many 'sysvol' paths! Need quotes?\n\n" );
  1861. Usage( argc, argv );
  1862. return 1;
  1863. }
  1864. mbstowcs( SysVolPath, argv[i], sizeof( SysVolPath ) / sizeof(WCHAR) );
  1865. //
  1866. // Make sure the system volume path is reasonable
  1867. //
  1868. retval = NetpPathType( NULL, SysVolPath, &pathType, 0 );
  1869. if( retval != NO_ERROR || pathType != ITYPE_PATH_ABSD ) {
  1870. fprintf( stderr, "Invalid system volume path. Must be an absolute path.\n" );
  1871. return 1;
  1872. }
  1873. break;
  1874. }
  1875. }
  1876. //
  1877. // Restore in progress; delete state
  1878. //
  1879. if (IsRestore) {
  1880. return (RestoreFRS(IsYes));
  1881. }
  1882. if( IsThisADC( domainName ) == FALSE ) {
  1883. fprintf( stderr, "This program can only be run on a DC!\n" );
  1884. return 1;
  1885. }
  1886. if( SysVolPath[0] == 0 ) {
  1887. Usage( argc, argv );
  1888. return 1;
  1889. }
  1890. printf( "Initializing the NT MultiMaster File Replication Service:\n" );
  1891. printf( " Domain: %ws\n", domainName );
  1892. if( IsFirstDCInDomain ) {
  1893. printf( " First DC in the domain\n" );
  1894. }
  1895. printf( " System Volume: %ws\n", SysVolPath );
  1896. //
  1897. // Create the sysvol tree and share it out, if needed
  1898. //
  1899. if (!FixSysvols) {
  1900. if( !CreateSysVolTree( SysVolPath, IsFirstDCInDomain, domainName ) ||
  1901. !CreateSysVolShare( SysVolPath ) ) {
  1902. return 1;
  1903. }
  1904. }
  1905. //
  1906. // Uncommit and delete old keys
  1907. //
  1908. if (!DeleteRegKeys()) {
  1909. goto errout;
  1910. }
  1911. //
  1912. // Add the registry keys for the NTFRS domain volume
  1913. //
  1914. wcscpy( stage, SysVolPath );
  1915. wcscat( stage, L"\\staging areas\\" );
  1916. wcscat( stage, domainName );
  1917. wcscpy( root, SysVolPath );
  1918. wcscat( root, L"\\sysvol\\" );
  1919. wcscat( root, domainName );
  1920. if( !AddRegKeys( domainName,
  1921. L"domain",
  1922. IsFirstDCInDomain,
  1923. stage,
  1924. root ) ) {
  1925. goto errout;
  1926. }
  1927. //
  1928. // Commit the keys only after all of the values are set without error.
  1929. // Otherwise, a running NtFrs might pick up the keys while they are in
  1930. // an incomplete state.
  1931. //
  1932. if( !CommitRegKeys()) {
  1933. goto errout;
  1934. }
  1935. //
  1936. // Now ensure that the replication service is running, and will run at each boot
  1937. //
  1938. if( !SetFRSAutoStart() || !StartFRS() ) {
  1939. goto errout;
  1940. }
  1941. printf( "Success!\n" );
  1942. return 0;
  1943. errout:
  1944. if (!FixSysvols) {
  1945. fprintf( stderr, "Warning: SYSVOL share path may have been changed.\n" );
  1946. }
  1947. return 1;
  1948. }