Source code of Windows XP (NT5)
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.

1276 lines
30 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. sisSetup.c
  5. Abstract:
  6. This module is used to install the SIS and GROVELER services.
  7. Environment:
  8. User Mode Only
  9. Revision History:
  10. --*/
  11. #include <windows.h>
  12. #include <stdio.h>
  13. #include <conio.h>
  14. #include <stdlib.h>
  15. #include <winioctl.h>
  16. #include <aclapi.h>
  17. //#include <winldap.h>
  18. //
  19. // Global variables
  20. //
  21. SC_HANDLE scm = NULL;
  22. BOOL MakeCommonStoreDirHidden = TRUE;
  23. BOOL UseSystemACL = TRUE;
  24. const wchar_t CommonStoreDirName[] = L"\\SIS Common Store";
  25. const wchar_t MaxIndexName[] = L"\\MaxIndex";
  26. const wchar_t BackupExludeList[] = L"\\SIS Common Store\\*.* /s" L"\000";
  27. //
  28. // Functions
  29. //
  30. VOID
  31. DisplayUsage (
  32. void
  33. )
  34. /*++
  35. Routine Description:
  36. This routine will display an error message based off of the Win32 error
  37. code that is passed in. This allows the user to see an understandable
  38. error message instead of just the code.
  39. Arguments:
  40. None
  41. Return Value:
  42. None.
  43. --*/
  44. {
  45. printf( "\nUsage: sisSetup [/?] [/h] [/i] [/u] [/n] [drive: [...]]\n"
  46. " /? /h Display usage information (default if no operation specified).\n"
  47. " /i Create the SIS and GROVELER services.\n"
  48. " /u Delete the SIS and GROVELER services.\n"
  49. " /n Do NOT make the \"SIS Common Store\" directory \"Hidden|System\".\n"
  50. " Will unhide the directory if it already exists and is hidden.\n"
  51. " /a Do NOT set SYSTEM ACL on \"SIS Common Store \" directory, instead\n"
  52. " set ADMINISTRATORS group ACL.\n"
  53. " This will change the ACL setting for existing directories.\n"
  54. " drive: A list of NTFS volumes you would like initialized for SIS.\n"
  55. " If no drives are specified, only the services will be installed.\n"
  56. " This will only initialize local hard drives with NTFS on them.\n"
  57. " The BOOT volume is never initialized.\n"
  58. "\n"
  59. " You must reboot for the changes to take affect.\n"
  60. "\n"
  61. "Example: sisSetup /i d: e:\n"
  62. " This will create the SIS and GROVELER services and initialize the\n"
  63. " \"SIS Common Store\" directory on the specified volumes.\n"
  64. );
  65. }
  66. void
  67. DisplayError (
  68. DWORD Code,
  69. LPSTR Msg,
  70. ...
  71. )
  72. /*++
  73. Routine Description:
  74. This routine will display an error message based off of the Win32 error
  75. code that is passed in. This allows the user to see an understandable
  76. error message instead of just the code.
  77. Arguments:
  78. Msg - The error message to display
  79. Code - The error code to be translated.
  80. Return Value:
  81. None.
  82. --*/
  83. {
  84. wchar_t errmsg[128];
  85. DWORD count;
  86. va_list ap;
  87. //printf("\n");
  88. va_start( ap, Msg );
  89. vprintf( Msg, ap );
  90. va_end( ap );
  91. //
  92. // Translate the Win32 error code into a useful message.
  93. //
  94. count = FormatMessage(
  95. FORMAT_MESSAGE_FROM_SYSTEM,
  96. NULL,
  97. Code,
  98. 0,
  99. errmsg,
  100. sizeof(errmsg),
  101. NULL );
  102. //
  103. // Make sure that the message could be translated.
  104. //
  105. if (count == 0) {
  106. printf( "(%d) Could not translate Error\n", Code );
  107. } else {
  108. //
  109. // Display the translated error.
  110. //
  111. printf( "(%d) %S", Code, errmsg );
  112. }
  113. }
  114. DWORD
  115. SetRegistryValue(
  116. LPCTSTR RegistryKey,
  117. LPCTSTR DataName,
  118. DWORD DataType,
  119. CONST BYTE *Data,
  120. DWORD DataSize
  121. )
  122. {
  123. HKEY regHandle = NULL;
  124. DWORD status;
  125. //
  126. // Get a handle to the services registry key.
  127. //
  128. status = RegOpenKeyEx (
  129. HKEY_LOCAL_MACHINE,
  130. RegistryKey,
  131. 0,
  132. KEY_ALL_ACCESS,
  133. &regHandle);
  134. if (ERROR_SUCCESS != status) {
  135. DisplayError(
  136. status,
  137. "Opening the registry key \"%S\", ",
  138. RegistryKey);
  139. return status;
  140. }
  141. //
  142. // Set the data value
  143. //
  144. status = RegSetValueEx(
  145. regHandle,
  146. DataName,
  147. 0,
  148. DataType,
  149. Data,
  150. DataSize);
  151. if (ERROR_SUCCESS != status) {
  152. DisplayError(
  153. status,
  154. "Setting data to the \"%S\" registry key, ",
  155. RegistryKey);
  156. return status;
  157. }
  158. return ERROR_SUCCESS;
  159. }
  160. DWORD
  161. SetupService(
  162. LPCTSTR Name,
  163. LPCTSTR DisplayName,
  164. LPCTSTR DriverPath,
  165. LPCTSTR LoadOrderGroup,
  166. LPCTSTR Dependencies,
  167. DWORD ServiceType,
  168. DWORD StartType,
  169. LPCTSTR RegistryKey,
  170. LPCTSTR RegDescription
  171. )
  172. /*++
  173. Routine Description:
  174. This routine will initialize the given service.
  175. Arguments:
  176. Return Value:
  177. Status of operation
  178. --*/
  179. {
  180. DWORD status;
  181. ULONG tag;
  182. SC_HANDLE srvHandle = NULL;
  183. HKEY regHandle = NULL;
  184. static CONST wchar_t DescriptionRegValue[] = L"Description";
  185. try {
  186. //
  187. // Create the given service
  188. //
  189. srvHandle = CreateService(
  190. scm,
  191. Name,
  192. DisplayName,
  193. STANDARD_RIGHTS_REQUIRED | SERVICE_START,
  194. ServiceType,
  195. StartType,
  196. SERVICE_ERROR_NORMAL,
  197. DriverPath,
  198. LoadOrderGroup,
  199. ((ServiceType == SERVICE_FILE_SYSTEM_DRIVER) ? &tag : NULL),
  200. Dependencies,
  201. NULL,
  202. NULL );
  203. if ( !srvHandle ) {
  204. status = GetLastError();
  205. if (ERROR_SERVICE_EXISTS != status) {
  206. DisplayError(
  207. status,
  208. "Creating the service \"%S\", ",
  209. Name);
  210. return status;
  211. }
  212. printf( "The \"%S\" service already exists.\n", Name );
  213. return ERROR_SUCCESS;
  214. }
  215. //
  216. // Get a handle to the services registry key.
  217. //
  218. status = RegOpenKeyEx (
  219. HKEY_LOCAL_MACHINE,
  220. RegistryKey,
  221. 0,
  222. KEY_ALL_ACCESS,
  223. &regHandle);
  224. if (ERROR_SUCCESS != status) {
  225. DisplayError(
  226. status,
  227. "Opening the registry key \"%S\", ",
  228. RegistryKey);
  229. return status;
  230. }
  231. //
  232. // Add the DESCRIPTION to the service
  233. //
  234. status = RegSetValueEx(
  235. regHandle,
  236. DescriptionRegValue,
  237. 0,
  238. REG_SZ,
  239. (CONST BYTE *)RegDescription,
  240. (wcslen(RegDescription) * sizeof(wchar_t)));
  241. if (ERROR_SUCCESS != status) {
  242. DisplayError(
  243. status,
  244. "Adding \"%S\" value to the \"%S\" registry key, ",
  245. DescriptionRegValue,
  246. RegistryKey);
  247. return status;
  248. }
  249. } finally {
  250. if (regHandle) {
  251. RegCloseKey( regHandle );
  252. }
  253. if (srvHandle) {
  254. CloseServiceHandle( srvHandle );
  255. }
  256. }
  257. printf( "The \"%S\" service was successfully added.\n", Name );
  258. return ERROR_SUCCESS;
  259. }
  260. DWORD
  261. CreateServices (
  262. void
  263. )
  264. /*++
  265. Routine Description:
  266. This will create the SIS and GROVELER service.
  267. Arguments:
  268. None
  269. Return Value:
  270. None.
  271. --*/
  272. {
  273. DWORD status;
  274. //
  275. // Create SIS service
  276. //
  277. status = SetupService(
  278. L"Sis",
  279. L"Single Instance Storage",
  280. L"%SystemRoot%\\system32\\drivers\\sis.sys",
  281. L"FSFilter System",
  282. NULL,
  283. SERVICE_FILE_SYSTEM_DRIVER,
  284. SERVICE_BOOT_START,
  285. L"SYSTEM\\CurrentControlSet\\Services\\Sis",
  286. L"A File System Filter that manages duplicate copies of files on hard-disk volumes. It copies one instance of the duplicate file into a central directory, and the duplicates are replaced with a link to the central copy in order to improve disk usage. This service can not be stopped. If this service is disabled, all linked files will no longer be accessible. If the central directory is deleted, all linked files will become permanently inaccessible." );
  287. if (ERROR_SUCCESS != status) {
  288. return status;
  289. }
  290. //
  291. // Create GROVELER service
  292. //
  293. status = SetupService(
  294. L"Groveler",
  295. L"Single Instance Storage Groveler",
  296. L"%SystemRoot%\\system32\\grovel.exe",
  297. NULL,
  298. L"SIS\0",
  299. SERVICE_WIN32_OWN_PROCESS,
  300. SERVICE_AUTO_START,
  301. L"SYSTEM\\CurrentControlSet\\Services\\Groveler",
  302. L"Scans the hard-disk volumes on a Remote Installation Services (RIS) server for duplicate copies of files. If found, one instance of the duplicate file is stored in a central directory, and the duplicates are replaced with a link to the central copy in order to improve disk usage. If this service is stopped, files will no longer be automatically linked in this manner, but the existing linked files will still be accessible." );
  303. if (ERROR_SUCCESS != status) {
  304. return status;
  305. }
  306. return ERROR_SUCCESS;
  307. }
  308. DWORD
  309. RemoveService(
  310. LPCTSTR Name
  311. )
  312. /*++
  313. Routine Description:
  314. This will delete the given service. This will make sure the given
  315. service is stopped first.
  316. Arguments:
  317. None
  318. Return Value:
  319. Status of operation
  320. --*/
  321. {
  322. DWORD status;
  323. SC_HANDLE srvHandle = NULL;
  324. BOOL state;
  325. SERVICE_STATUS servStatus;
  326. int retryLimit;
  327. # define RETRY_TIMEOUT 500 //1/2 second
  328. # define RETRY_COUNT (6*2) //try for a few seconds
  329. try {
  330. //
  331. // Open the service
  332. //
  333. srvHandle = OpenService(
  334. scm,
  335. Name,
  336. SERVICE_ALL_ACCESS );
  337. if ( !srvHandle ) {
  338. status = GetLastError();
  339. if (ERROR_SERVICE_DOES_NOT_EXIST != status) {
  340. DisplayError(
  341. status,
  342. "Opening the service \"%S\", ",
  343. Name);
  344. return status;
  345. }
  346. printf( "The \"%S\" service does not exist.\n", Name );
  347. return ERROR_SUCCESS;
  348. }
  349. //
  350. // Stop the service
  351. //
  352. state = ControlService(
  353. srvHandle,
  354. SERVICE_CONTROL_STOP,
  355. &servStatus );
  356. if ( !state ) {
  357. status = GetLastError();
  358. if ((ERROR_SERVICE_NOT_ACTIVE != status) &&
  359. (ERROR_INVALID_SERVICE_CONTROL != status) ) {
  360. DisplayError(
  361. status,
  362. "Stoping the \"%S\" service, ",
  363. Name);
  364. return status;
  365. }
  366. }
  367. //
  368. // Wait a few seconds for the service to stop.
  369. //
  370. for (retryLimit=0;
  371. (SERVICE_STOPPED != servStatus.dwCurrentState);
  372. ) {
  373. Sleep( RETRY_TIMEOUT ); //wait for 1/4 second
  374. state = QueryServiceStatus(
  375. srvHandle,
  376. &servStatus );
  377. if ( !state ) {
  378. status = GetLastError();
  379. DisplayError(
  380. status,
  381. "Querrying service status for the \"%S\" service, ",
  382. Name);
  383. return status;
  384. }
  385. if (++retryLimit >= RETRY_COUNT) {
  386. printf("The \"%S\" service could not be stopped.\n",Name);
  387. break;
  388. }
  389. }
  390. //
  391. // Delete the service
  392. //
  393. state = DeleteService( srvHandle );
  394. if ( !state ) {
  395. status = GetLastError();
  396. DisplayError(
  397. status,
  398. "Deleting the \"%S\" service, ",
  399. Name);
  400. return status;
  401. }
  402. } finally {
  403. if (srvHandle) {
  404. CloseServiceHandle( srvHandle );
  405. }
  406. }
  407. printf( "The \"%S\" service was successfully deleted.\n", Name );
  408. return ERROR_SUCCESS;
  409. }
  410. DWORD
  411. DeleteServices(
  412. void
  413. )
  414. /*++
  415. Routine Description:
  416. This will delete the SIS and GROVELER services from the system
  417. Arguments:
  418. None
  419. Return Value:
  420. Status of operation
  421. --*/
  422. {
  423. DWORD status;
  424. status = RemoveService( L"Groveler" );
  425. if (ERROR_SUCCESS != status) {
  426. return status;
  427. }
  428. status = RemoveService( L"Sis" );
  429. if (ERROR_SUCCESS != status) {
  430. return status;
  431. }
  432. return ERROR_SUCCESS;
  433. }
  434. DWORD
  435. InitVolume(
  436. char *DevName
  437. )
  438. /*++
  439. Routine Description:
  440. This routine will initialize SIS on the given volume. This will verify
  441. that the volume is an NTFS volume and that it is not the BOOT volume.
  442. Arguments:
  443. DevName - The name of the volume to init
  444. Return Value:
  445. Status of operation
  446. --*/
  447. {
  448. HANDLE hVolume;
  449. HANDLE hCSDir;
  450. HANDLE hMaxIndex = INVALID_HANDLE_VALUE;
  451. DWORD status;
  452. DWORD transferCount;
  453. LONGLONG maxIndex;
  454. PSID pSid = NULL;
  455. PACL pAcl = NULL;
  456. EXPLICIT_ACCESS ExplicitEntries;
  457. SECURITY_ATTRIBUTES sa;
  458. SID_IDENTIFIER_AUTHORITY ntSidAuthority = SECURITY_NT_AUTHORITY;
  459. SECURITY_DESCRIPTOR SecDescriptor;
  460. BOOL state;
  461. USHORT compressionMode = COMPRESSION_FORMAT_DEFAULT;
  462. wchar_t name[MAX_PATH];
  463. wchar_t dirName[MAX_PATH];
  464. wchar_t fileSystemType[MAX_PATH];
  465. wchar_t uDevName[MAX_PATH];
  466. try {
  467. //
  468. // Convert the DEVICE name to unicode
  469. //
  470. status = MultiByteToWideChar(
  471. CP_ACP,
  472. MB_PRECOMPOSED,
  473. DevName,
  474. -1,
  475. uDevName,
  476. (sizeof(uDevName) / sizeof(wchar_t)) );
  477. if (status == 0) {
  478. status = GetLastError();
  479. DisplayError(
  480. status,
  481. "Translating \"%s\" to unicode, ",
  482. DevName );
  483. }
  484. //
  485. // Get the "SystemDrive" environemnt variable
  486. //
  487. status = GetEnvironmentVariable(
  488. L"SystemDrive",
  489. name,
  490. (sizeof(name) / sizeof(wchar_t)));
  491. if (status <= 0) {
  492. printf( "Unable to retrieve the environment variable \"SystemDrive\"." );
  493. return ERROR_INVALID_FUNCTION;
  494. }
  495. //
  496. // See if they have requested the SYSTEM drive. If so return an error
  497. //
  498. if (_wcsicmp(name,uDevName) == 0) {
  499. printf( "The volume \"%s\" is the BOOT volume, SIS not initialized on it.\n", DevName );
  500. return ERROR_SUCCESS;
  501. }
  502. //
  503. // Get the TYPE of the drive, see if it is a local HARDDISK (fixed
  504. // or removable). If not return now.
  505. //
  506. wsprintf(name,L"%s\\",uDevName); //generate ROOTDIR name
  507. status = GetDriveType( name );
  508. if ((status == DRIVE_UNKNOWN) ||
  509. (status == DRIVE_NO_ROOT_DIR)) {
  510. printf("The volume \"%s\" does not exist.\n",DevName);
  511. return ERROR_SUCCESS;
  512. } else if ((status != DRIVE_FIXED) &&
  513. (status != DRIVE_REMOVABLE)) {
  514. printf("The volume \"%s\" is not a local hard drive, SIS not initialized on it.\n",DevName);
  515. return ERROR_SUCCESS;
  516. }
  517. //
  518. // Get the type of the file system on the volume. If not NTFS
  519. // return now.
  520. //
  521. state = GetVolumeInformation(
  522. name,
  523. NULL,
  524. 0,
  525. NULL,
  526. NULL,
  527. NULL,
  528. fileSystemType,
  529. sizeof(fileSystemType));
  530. if ( !state ) {
  531. status = GetLastError();
  532. if (ERROR_PATH_NOT_FOUND != status) {
  533. DisplayError(
  534. status,
  535. "Opening volume \"%s\", ",
  536. DevName );
  537. return status;
  538. }
  539. printf("The volume \"%s\" does not exist.\n",DevName);
  540. return ERROR_SUCCESS;
  541. }
  542. if (_wcsnicmp(fileSystemType, L"NTFS", 4 ) != 0) {
  543. printf("The volume \"%s\" is not an NTFS volume, SIS not initialized on it.\n",DevName);
  544. return ERROR_SUCCESS;
  545. }
  546. //
  547. // Create the Common Store Directory. Keep going if the directory
  548. // already exits.
  549. //
  550. wsprintf( dirName, L"%s%s", uDevName, CommonStoreDirName );
  551. state = CreateDirectory(dirName, NULL);
  552. if ( !state ) {
  553. status = GetLastError();
  554. if (ERROR_ALREADY_EXISTS != status) {
  555. DisplayError(
  556. status,
  557. "Creating directory \"%S\", ",
  558. dirName);
  559. return status;
  560. }
  561. }
  562. //
  563. // Mark the directory as SYSTEM and HIDDEN if requested.
  564. //
  565. state = SetFileAttributes( dirName,
  566. ((MakeCommonStoreDirHidden) ?
  567. FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM :
  568. FILE_ATTRIBUTE_NORMAL) );
  569. if ( !state ) {
  570. status = GetLastError();
  571. DisplayError(
  572. status,
  573. "Setting attributes on directory \"%S\", ",
  574. dirName);
  575. }
  576. //
  577. // Set compression on the "SIS Common Store" directory
  578. // Don't do it for now.
  579. //
  580. // //
  581. // // Open the directory
  582. // //
  583. //
  584. // hCSDir = CreateFile(
  585. // dirName,
  586. // GENERIC_READ|GENERIC_WRITE,
  587. // FILE_SHARE_READ | FILE_SHARE_WRITE,
  588. // NULL,
  589. // OPEN_EXISTING,
  590. // FILE_FLAG_BACKUP_SEMANTICS,
  591. // NULL);
  592. //
  593. // if (INVALID_HANDLE_VALUE == hCSDir) {
  594. //
  595. // DisplayError(
  596. // status,
  597. // "Opening directory \"%S\" to update compression, ",
  598. // dirName);
  599. //
  600. // } else {
  601. //
  602. // //
  603. // // Enable compression
  604. // //
  605. //
  606. // state = DeviceIoControl(
  607. // hCSDir,
  608. // FSCTL_SET_COMPRESSION,
  609. // &compressionMode,
  610. // sizeof(compressionMode),
  611. // NULL,
  612. // 0,
  613. // &transferCount,
  614. // NULL);
  615. //
  616. // if ( !state ) {
  617. //
  618. // status = GetLastError();
  619. // DisplayError(
  620. // status,
  621. // "Enabling compression on \"%S\", ",
  622. // dirName);
  623. // }
  624. //
  625. // //
  626. // // Close directory handle
  627. // //
  628. //
  629. // CloseHandle( hCSDir );
  630. // }
  631. //
  632. // Create the MaxIndex file
  633. //
  634. wsprintf( name, L"%s%s", dirName, MaxIndexName );
  635. hMaxIndex = CreateFile(
  636. name,
  637. GENERIC_READ | GENERIC_WRITE,
  638. 0,
  639. NULL,
  640. CREATE_NEW,
  641. FILE_ATTRIBUTE_NORMAL,
  642. NULL);
  643. if (INVALID_HANDLE_VALUE == hMaxIndex) {
  644. status = GetLastError();
  645. if (ERROR_FILE_EXISTS != status) {
  646. DisplayError(
  647. status,
  648. "Creating file \"%S\", ",
  649. name);
  650. return status;
  651. }
  652. } else {
  653. //
  654. // The MaxIndex file did not exist, init it.
  655. //
  656. maxIndex = 1;
  657. state = WriteFile(
  658. hMaxIndex,
  659. &maxIndex,
  660. sizeof(maxIndex),
  661. &transferCount,
  662. NULL);
  663. if ( !state || (transferCount < sizeof(maxIndex)) ) {
  664. status = GetLastError();
  665. DisplayError(
  666. status,
  667. "Writing file \"%S\", ",
  668. name);
  669. return status;
  670. }
  671. //
  672. // Close the file
  673. //
  674. CloseHandle( hMaxIndex );
  675. hMaxIndex = INVALID_HANDLE_VALUE;
  676. }
  677. //
  678. // Set security information on the common store directory
  679. //
  680. //
  681. // build AccessEntry structure
  682. //
  683. ZeroMemory( &ExplicitEntries, sizeof(ExplicitEntries) );
  684. if (UseSystemACL) {
  685. state = AllocateAndInitializeSid(
  686. &ntSidAuthority,
  687. 1,
  688. SECURITY_LOCAL_SYSTEM_RID,
  689. 0, 0, 0, 0, 0, 0, 0,
  690. &pSid );
  691. } else {
  692. state = AllocateAndInitializeSid(
  693. &ntSidAuthority,
  694. 2,
  695. SECURITY_BUILTIN_DOMAIN_RID,
  696. DOMAIN_ALIAS_RID_ADMINS,
  697. 0, 0, 0, 0, 0, 0,
  698. &pSid );
  699. }
  700. if ( !state || (pSid == NULL) ) {
  701. status = GetLastError();
  702. DisplayError(
  703. status,
  704. "Creating SID, ");
  705. return status;
  706. }
  707. BuildTrusteeWithSid( &ExplicitEntries.Trustee, pSid );
  708. ExplicitEntries.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  709. ExplicitEntries.grfAccessMode = SET_ACCESS;
  710. ExplicitEntries.grfAccessPermissions = FILE_ALL_ACCESS;
  711. //
  712. // Set the Acl with the ExplicitEntry rights
  713. //
  714. status = SetEntriesInAcl( 1,
  715. &ExplicitEntries,
  716. NULL,
  717. &pAcl );
  718. if ( status != ERROR_SUCCESS ) {
  719. DisplayError(
  720. status,
  721. "Creating ACL, ");
  722. return status;
  723. }
  724. //
  725. // Create the Security Descriptor
  726. //
  727. InitializeSecurityDescriptor( &SecDescriptor, SECURITY_DESCRIPTOR_REVISION );
  728. state = SetSecurityDescriptorDacl( &SecDescriptor, TRUE, pAcl, FALSE );
  729. if ( !state ) {
  730. status = GetLastError();
  731. DisplayError(
  732. status,
  733. "Setting Security DACL, ");
  734. return status;
  735. }
  736. //
  737. // SET security on the Directory
  738. //
  739. state = SetFileSecurity(dirName,
  740. DACL_SECURITY_INFORMATION,
  741. &SecDescriptor);
  742. if ( !state ) {
  743. status = GetLastError();
  744. DisplayError(
  745. status,
  746. "Setting File Security, ");
  747. return status;
  748. }
  749. } finally {
  750. //
  751. // Cleanup
  752. //
  753. if (hMaxIndex != INVALID_HANDLE_VALUE) {
  754. CloseHandle( hMaxIndex );
  755. }
  756. if ( pSid ) {
  757. FreeSid( pSid );
  758. }
  759. if ( pAcl ) {
  760. LocalFree( pAcl );
  761. }
  762. }
  763. printf( "The volume \"%s\" was successfully initialized.\n", DevName );
  764. return ERROR_SUCCESS;
  765. }
  766. //DWORD
  767. //CleanupVolume(
  768. // char *DevName
  769. // )
  770. //
  771. ///*++
  772. //
  773. //Routine Description:
  774. //
  775. //
  776. //
  777. //Arguments:
  778. //
  779. // None
  780. //
  781. //Return Value:
  782. //
  783. // Status of operation
  784. //
  785. //--*/
  786. //
  787. //{
  788. // printf("Remove SIS on \"%s\"\n",DevName);
  789. // return ERROR_SUCCESS;
  790. //}
  791. //
  792. // Main FUNCTION
  793. //
  794. void __cdecl
  795. main(
  796. int argc,
  797. char *argv[])
  798. /*++
  799. Routine Description:
  800. This is the program entry point and main processing routine for the
  801. installation console mode application.
  802. Arguments:
  803. argc - The count of arguments passed into the command line.
  804. argv - Array of arguments passed into the command line.
  805. Return Value:
  806. None.
  807. --*/
  808. {
  809. char *param;
  810. # define OP_UNKNOWN 0
  811. # define OP_CREATE 1
  812. # define OP_DELETE 2
  813. int operation = OP_UNKNOWN;
  814. int servicesState = OP_UNKNOWN;
  815. int i;
  816. DWORD status;
  817. //
  818. // Begin by displaying an introduction message to the user to let them
  819. // know that the application has started.
  820. //
  821. // printf("\nSIS/GROVELER Simple Installation Aid\n"
  822. // "Copyright (c) 2000 Microsoft Corporation\n\n");
  823. //
  824. // Obtain a handle to the service control manager requesting all access
  825. //
  826. scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  827. //
  828. // Verify that a handle could be obtained.
  829. //
  830. if (!scm) {
  831. //
  832. // A handle could not be obtained, report error.
  833. //
  834. DisplayError(GetLastError(),
  835. "The Service Control Manager could not be opened, ");
  836. return;
  837. }
  838. try {
  839. //
  840. // Parase parameters then perform the operations that we can
  841. //
  842. for (i=1; i < argc; i++) {
  843. param = argv[i];
  844. //
  845. // See if a SWITCH
  846. //
  847. if ((param[0] == '-') || (param[0] == '/')) {
  848. //
  849. // We have a switch header, make sure it is 1 character long
  850. //
  851. if (param[2] != 0) {
  852. DisplayError(ERROR_INVALID_PARAMETER,
  853. "Parsing \"%s\", ",
  854. param);
  855. DisplayUsage();
  856. return;
  857. }
  858. //
  859. // Figure out the switch
  860. //
  861. switch (param[1]) {
  862. case '?':
  863. case 'h':
  864. case 'H':
  865. DisplayUsage();
  866. return;
  867. case 'i':
  868. case 'I':
  869. operation = OP_CREATE;
  870. break;
  871. case 'u':
  872. case 'U':
  873. operation = OP_DELETE;
  874. break;
  875. case 'n':
  876. case 'N':
  877. MakeCommonStoreDirHidden = FALSE;
  878. break;
  879. case 'a':
  880. case 'A':
  881. UseSystemACL = FALSE;
  882. break;
  883. default:
  884. DisplayError(ERROR_INVALID_PARAMETER,
  885. "Parsing \"%s\", ",
  886. param);
  887. DisplayUsage();
  888. return;
  889. }
  890. } else {
  891. //
  892. // Execute the given operation
  893. //
  894. switch (operation) {
  895. case OP_CREATE:
  896. if (servicesState != OP_CREATE) {
  897. status = CreateServices();
  898. if (ERROR_SUCCESS != status) {
  899. goto Cleanup;
  900. }
  901. servicesState = OP_CREATE;
  902. }
  903. status = InitVolume(param);
  904. if (ERROR_SUCCESS != status) {
  905. goto Cleanup;
  906. }
  907. status = SetRegistryValue(
  908. L"SYSTEM\\CurrentControlSet\\Control\\BackupRestore\\FilesNotToBackup",
  909. L"Single Instance Storage",
  910. REG_MULTI_SZ,
  911. (const BYTE *)BackupExludeList,
  912. sizeof(BackupExludeList));
  913. if (ERROR_SUCCESS != status) {
  914. goto Cleanup;
  915. }
  916. break;
  917. case OP_DELETE:
  918. if (servicesState != OP_DELETE) {
  919. status = DeleteServices();
  920. if (ERROR_SUCCESS != status) {
  921. goto Cleanup;
  922. }
  923. servicesState = OP_DELETE;
  924. }
  925. // status = CleanupVolume(param);
  926. // if (ERROR_SUCCESS != status) {
  927. //
  928. // goto Cleanup;
  929. // }
  930. break;
  931. }
  932. }
  933. }
  934. //
  935. // See if any operation was performed. If not then no drive letter was
  936. // specified, so do what ever operation they said without a drive letter.
  937. //
  938. if (servicesState == OP_UNKNOWN) {
  939. switch (operation) {
  940. case OP_UNKNOWN:
  941. DisplayUsage();
  942. break;
  943. case OP_CREATE:
  944. CreateServices();
  945. break;
  946. case OP_DELETE:
  947. DeleteServices();
  948. break;
  949. }
  950. }
  951. Cleanup: ;
  952. } finally {
  953. CloseServiceHandle(scm);
  954. }
  955. }