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.

756 lines
17 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 <nt.h>
  12. #include <ntrtl.h>
  13. #include <nturtl.h>
  14. #include <ntstatus.h>
  15. #include <windows.h>
  16. #include <strsafe.h>
  17. #include <stdlib.h>
  18. #include <objbase.h>
  19. //
  20. // SIS reparse buffer definition
  21. //
  22. #define SIS_REPARSE_BUFFER_FORMAT_VERSION 5
  23. typedef struct _SIS_REPARSE_BUFFER {
  24. ULONG ReparsePointFormatVersion;
  25. ULONG Reserved;
  26. //
  27. // The id of the common store file.
  28. //
  29. GUID CSid;
  30. //
  31. // The index of this link file.
  32. //
  33. LARGE_INTEGER LinkIndex;
  34. //
  35. // The file ID of the link file.
  36. //
  37. LARGE_INTEGER LinkFileNtfsId;
  38. //
  39. // The file ID of the common store file.
  40. //
  41. LARGE_INTEGER CSFileNtfsId;
  42. //
  43. // A "131 hash" checksum of the contents of the
  44. // common store file.
  45. //
  46. LARGE_INTEGER CSChecksum;
  47. //
  48. // A "131 hash" checksum of this structure.
  49. // N.B. Must be last.
  50. //
  51. LARGE_INTEGER Checksum;
  52. } SIS_REPARSE_BUFFER, *PSIS_REPARSE_BUFFER;
  53. //
  54. // Global variables
  55. //
  56. const wchar_t ReparseIndexName[] = L"$Extend\\$Reparse:$R:$INDEX_ALLOCATION";
  57. //
  58. // Functions
  59. //
  60. void
  61. DisplayUsage (
  62. void
  63. )
  64. /*++
  65. Routine Description:
  66. This routine will display an error message based off of the Win32 error
  67. code that is passed in. This allows the user to see an understandable
  68. error message instead of just the code.
  69. Arguments:
  70. None
  71. Return Value:
  72. None.
  73. --*/
  74. {
  75. printf( "\nUsage: sisInfo [/?] [/h] [drive:]\n"
  76. " /? /h Display usage information (default if no operation specified).\n"
  77. " drive: The volume to display SIS information on\n"
  78. );
  79. }
  80. void
  81. DisplayError (
  82. DWORD Code,
  83. LPSTR Msg,
  84. ...
  85. )
  86. /*++
  87. Routine Description:
  88. This routine will display an error message based off of the Win32 error
  89. code that is passed in. This allows the user to see an understandable
  90. error message instead of just the code.
  91. Arguments:
  92. Msg - The error message to display
  93. Code - The error code to be translated.
  94. Return Value:
  95. None.
  96. --*/
  97. {
  98. wchar_t errmsg[128];
  99. DWORD count;
  100. va_list ap;
  101. //printf("\n");
  102. va_start( ap, Msg );
  103. vprintf( Msg, ap );
  104. va_end( ap );
  105. //
  106. // Translate the Win32 error code into a useful message.
  107. //
  108. count = FormatMessage(
  109. FORMAT_MESSAGE_FROM_SYSTEM,
  110. NULL,
  111. Code,
  112. 0,
  113. errmsg,
  114. sizeof(errmsg),
  115. NULL );
  116. //
  117. // Make sure that the message could be translated.
  118. //
  119. if (count == 0) {
  120. printf( "(%d) Could not translate Error\n", Code );
  121. } else {
  122. //
  123. // Display the translated error.
  124. //
  125. printf( "(%d) %S", Code, errmsg );
  126. }
  127. }
  128. DWORD
  129. OpenReparseInformation(
  130. IN wchar_t *name,
  131. OUT HANDLE *hReparseIndex,
  132. OUT HANDLE *hRootDirectory,
  133. OUT wchar_t *volName,
  134. OUT DWORD volNameSize //in characters
  135. )
  136. /*++
  137. Routine Description:
  138. Arguments:
  139. Return Value:
  140. --*/
  141. {
  142. BOOL bResult;
  143. DWORD status = ERROR_SUCCESS;
  144. wchar_t *idxName = NULL;
  145. DWORD bfSz;
  146. *hReparseIndex = INVALID_HANDLE_VALUE;
  147. *hRootDirectory = INVALID_HANDLE_VALUE;
  148. try {
  149. //
  150. // Get the volume name from the given path
  151. //
  152. bResult = GetVolumePathName( name,
  153. volName,
  154. volNameSize );
  155. if (!bResult) {
  156. status = GetLastError();
  157. //ASSERT(status != ERROR_SUCCESS);
  158. DisplayError( status,
  159. "Error calling GetVolumePathName on \"%s\"\n",
  160. name );
  161. leave;
  162. }
  163. //
  164. // Open the root directory of the volume
  165. //
  166. *hRootDirectory = CreateFile( volName,
  167. GENERIC_READ,
  168. FILE_SHARE_READ,
  169. NULL,
  170. OPEN_EXISTING,
  171. FILE_FLAG_BACKUP_SEMANTICS | SECURITY_IMPERSONATION,
  172. NULL );
  173. if (*hRootDirectory == INVALID_HANDLE_VALUE) {
  174. status = GetLastError();
  175. //ASSERT(status != ERROR_SUCCESS);
  176. DisplayError( status,
  177. "Error opening \"%s\"\n",
  178. volName );
  179. leave;
  180. }
  181. //
  182. // Get the reparse index name to open
  183. //
  184. bfSz = wcslen(volName) + wcslen(ReparseIndexName) + 1;
  185. idxName = malloc(bfSz * sizeof(wchar_t));
  186. if (idxName == NULL) {
  187. status = ERROR_NOT_ENOUGH_MEMORY;
  188. DisplayError( status,
  189. "Error allocating %d bytes of memory\n",
  190. (bfSz * sizeof(wchar_t)) );
  191. leave;
  192. }
  193. StringCchCopy( idxName, bfSz, volName );
  194. StringCchCat( idxName, bfSz, ReparseIndexName );
  195. //
  196. // Open the reparse index
  197. //
  198. *hReparseIndex = CreateFile( idxName,
  199. GENERIC_READ,
  200. FILE_SHARE_READ,
  201. NULL,
  202. OPEN_EXISTING,
  203. FILE_FLAG_BACKUP_SEMANTICS | SECURITY_IMPERSONATION,
  204. NULL );
  205. if (*hReparseIndex == INVALID_HANDLE_VALUE) {
  206. status = GetLastError();
  207. //ASSERT(status != ERROR_SUCCESS);
  208. DisplayError( status,
  209. "Error opening \"%s\"\n",
  210. idxName );
  211. leave;
  212. }
  213. } finally {
  214. //
  215. // cleanup
  216. //
  217. if (idxName) {
  218. free(idxName);
  219. }
  220. //
  221. // cleanup handles if the operation failed
  222. //
  223. if (status != STATUS_SUCCESS) {
  224. if (*hRootDirectory != INVALID_HANDLE_VALUE) {
  225. CloseHandle( *hRootDirectory );
  226. *hRootDirectory = INVALID_HANDLE_VALUE;
  227. }
  228. if (*hReparseIndex != INVALID_HANDLE_VALUE) {
  229. CloseHandle( *hReparseIndex );
  230. *hReparseIndex = INVALID_HANDLE_VALUE;
  231. }
  232. }
  233. }
  234. return status;
  235. }
  236. void
  237. CloseReparseInformation(
  238. IN HANDLE *hReparseIndex,
  239. IN HANDLE *hRootDirectory
  240. )
  241. /*++
  242. Routine Description:
  243. Arguments:
  244. Return Value:
  245. --*/
  246. {
  247. if (*hReparseIndex !=INVALID_HANDLE_VALUE)
  248. {
  249. CloseHandle( *hReparseIndex );
  250. *hReparseIndex = INVALID_HANDLE_VALUE;
  251. }
  252. if (*hRootDirectory !=INVALID_HANDLE_VALUE)
  253. {
  254. CloseHandle( *hRootDirectory );
  255. *hRootDirectory = INVALID_HANDLE_VALUE;
  256. }
  257. }
  258. DWORD
  259. GetNextReparseRecord(
  260. HANDLE hReparseIdx,
  261. PFILE_REPARSE_POINT_INFORMATION ReparseInfo
  262. )
  263. /*++
  264. Routine Description:
  265. Arguments:
  266. Return Value:
  267. --*/
  268. {
  269. DWORD status = ERROR_SUCCESS;
  270. NTSTATUS ntStatus;
  271. IO_STATUS_BLOCK ioStatus;
  272. ntStatus = NtQueryDirectoryFile( hReparseIdx,
  273. NULL,
  274. NULL,
  275. NULL,
  276. &ioStatus,
  277. ReparseInfo,
  278. sizeof(FILE_REPARSE_POINT_INFORMATION),
  279. FileReparsePointInformation,
  280. TRUE,
  281. NULL,
  282. FALSE );
  283. if (!NT_SUCCESS(ntStatus))
  284. {
  285. status = RtlNtStatusToDosError(ntStatus);
  286. SetLastError(status);
  287. if (status != ERROR_NO_MORE_FILES)
  288. {
  289. DisplayError(status,
  290. "Error reading reparse point index\n");
  291. }
  292. }
  293. return status;
  294. }
  295. wchar_t *
  296. GetCsFileName(
  297. IN GUID *Guid,
  298. IN wchar_t *Buffer,
  299. IN DWORD BufferSize //in bytes
  300. )
  301. /*++
  302. Routine Description:
  303. This routine will convert the given sis guid into the name of the
  304. common store file.
  305. Arguments:
  306. Return Value:
  307. --*/
  308. {
  309. LPWSTR guidString;
  310. if (StringFromIID( Guid, &guidString ) != S_OK) {
  311. (void)StringCbCopy( Buffer, BufferSize, L"<Invalid GUID>" );
  312. } else {
  313. //
  314. // I want to exclude the starting and ending brace
  315. //
  316. (void)StringCbCopyN( Buffer, BufferSize, guidString+1, (36 * sizeof(wchar_t)) );
  317. (void)StringCbCat( Buffer, BufferSize, L".sis" );
  318. CoTaskMemFree( guidString );
  319. }
  320. return Buffer;
  321. }
  322. void
  323. DisplayFileName(
  324. HANDLE hRootDir,
  325. wchar_t *VolPathName,
  326. LONGLONG FileId)
  327. /*++
  328. Routine Description:
  329. Arguments:
  330. Return Value:
  331. --*/
  332. {
  333. NTSTATUS ntStatus;
  334. UNICODE_STRING idName;
  335. OBJECT_ATTRIBUTES ObjectAttributes;
  336. HANDLE hFile = INVALID_HANDLE_VALUE;
  337. IO_STATUS_BLOCK ioStatusBlock;
  338. wchar_t csFileName[256];
  339. UCHAR reparseData[1024];
  340. PSIS_REPARSE_BUFFER sisReparseData;
  341. wchar_t *fname;
  342. struct {
  343. FILE_NAME_INFORMATION FileInformation;
  344. wchar_t FileName[MAX_PATH];
  345. } NameFile;
  346. //
  347. // Setup local parameters
  348. ZeroMemory( &NameFile, sizeof(NameFile) );
  349. idName.Length = sizeof(LONGLONG);
  350. idName.MaximumLength = sizeof(LONGLONG);
  351. idName.Buffer = (wchar_t *)&FileId;
  352. //
  353. // Open the given file by ID
  354. //
  355. InitializeObjectAttributes( &ObjectAttributes,
  356. &idName,
  357. OBJ_CASE_INSENSITIVE,
  358. hRootDir,
  359. NULL ); // security descriptor
  360. ntStatus = NtCreateFile( &hFile,
  361. FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  362. &ObjectAttributes,
  363. &ioStatusBlock,
  364. NULL, // allocation size
  365. FILE_ATTRIBUTE_NORMAL,
  366. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  367. FILE_OPEN,
  368. FILE_NON_DIRECTORY_FILE | FILE_OPEN_BY_FILE_ID | FILE_OPEN_REPARSE_POINT,
  369. NULL, // EA buffer
  370. 0 ); // EA length
  371. if (NT_SUCCESS(ntStatus)) {
  372. //
  373. // Try to get its file name
  374. //
  375. ntStatus = NtQueryInformationFile( hFile,
  376. &ioStatusBlock,
  377. &NameFile.FileInformation,
  378. sizeof(NameFile),
  379. FileNameInformation );
  380. if (NT_SUCCESS(ntStatus)) {
  381. //
  382. // Get the name to display, don't include the leading slash
  383. // (it is in the volume name)
  384. //
  385. fname = (NameFile.FileInformation.FileName + 1);
  386. //
  387. // Get reparse point information
  388. //
  389. ntStatus = NtFsControlFile( hFile,
  390. NULL,
  391. NULL,
  392. NULL,
  393. &ioStatusBlock,
  394. FSCTL_GET_REPARSE_POINT,
  395. NULL,
  396. 0,
  397. &reparseData,
  398. sizeof(reparseData) );
  399. if (NT_SUCCESS(ntStatus)) {
  400. //
  401. // We received the reparse point information, display
  402. // the name information
  403. //
  404. sisReparseData = (PSIS_REPARSE_BUFFER)&((PREPARSE_DATA_BUFFER)reparseData)->GenericReparseBuffer.DataBuffer;
  405. printf( "%S%S -> %SSIS Common Store\\%S\n",
  406. VolPathName,
  407. fname,
  408. VolPathName,
  409. GetCsFileName( &sisReparseData->CSid, csFileName, sizeof(csFileName)) );
  410. } else {
  411. //
  412. // Could not get REPARSE point information, just display name
  413. printf( "%S%S\n",
  414. VolPathName,
  415. fname );
  416. }
  417. } else {
  418. printf( "Unable to query file name for %S%04I64x.%012I64x (%d)\n",
  419. VolPathName,
  420. ((FileId >> 48) & 0xffff),
  421. FileId & 0x0000ffffffffffff,
  422. ntStatus );
  423. }
  424. CloseHandle(hFile);
  425. } else {
  426. printf( "Unable to open file by ID for %S%04I64x.%012I64x (%d)\n",
  427. VolPathName,
  428. ((FileId >> 48) & 0xffff),
  429. FileId & 0x0000ffffffffffff,
  430. ntStatus );
  431. }
  432. }
  433. void
  434. DisplaySisFiles(
  435. IN HANDLE hReparseIdx,
  436. IN HANDLE hRootDir,
  437. IN wchar_t *VolPathName
  438. )
  439. /*++
  440. Routine Description:
  441. Arguments:
  442. Return Value:
  443. --*/
  444. {
  445. DWORD status;
  446. DWORD tagCount = 0;
  447. FILE_REPARSE_POINT_INFORMATION reparseInfo;
  448. do {
  449. status = GetNextReparseRecord( hReparseIdx,
  450. &reparseInfo );
  451. if (status != ERROR_SUCCESS) {
  452. break;
  453. }
  454. if (reparseInfo.Tag == IO_REPARSE_TAG_SIS)
  455. {
  456. tagCount++;
  457. DisplayFileName( hRootDir,
  458. VolPathName,
  459. reparseInfo.FileReference );
  460. }
  461. } while (TRUE);
  462. printf( "\nThe volume \"%S\" contains %d SIS controled files.\n", VolPathName, tagCount );
  463. }
  464. void __cdecl
  465. wmain(
  466. int argc,
  467. wchar_t *argv[]
  468. )
  469. /*++
  470. Routine Description:
  471. Main program
  472. Arguments:
  473. argc - The count of arguments passed into the command line.
  474. argv - Array of arguments passed into the command line.
  475. Return Value:
  476. None.
  477. --*/
  478. {
  479. wchar_t *param;
  480. int i;
  481. DWORD status;
  482. HANDLE hReparseIdx = INVALID_HANDLE_VALUE;
  483. HANDLE hRootDir = INVALID_HANDLE_VALUE;
  484. wchar_t volPathName[256];
  485. BOOL didSomething = FALSE;
  486. //
  487. // Parase parameters then perform the operations that we can
  488. //
  489. for (i=1; i < argc; i++) {
  490. param = argv[i];
  491. //
  492. // See if a SWITCH
  493. //
  494. if ((param[0] == '-') || (param[0] == '/')) {
  495. //
  496. // We have a switch header, make sure it is 1 character long
  497. //
  498. if (param[2] != 0) {
  499. DisplayError(ERROR_INVALID_PARAMETER,
  500. "Parsing \"%s\", ",
  501. param);
  502. DisplayUsage();
  503. return;
  504. }
  505. //
  506. // Figure out the switch
  507. //
  508. switch (param[1]) {
  509. case '?':
  510. case 'h':
  511. case 'H':
  512. DisplayUsage();
  513. return;
  514. default:
  515. DisplayError(ERROR_INVALID_PARAMETER,
  516. "Parsing \"%s\", ",
  517. param);
  518. DisplayUsage();
  519. return;
  520. }
  521. } else {
  522. didSomething = TRUE;
  523. //
  524. // We had a parameter which should be a volume, handle it.
  525. //
  526. status = OpenReparseInformation( param,
  527. &hReparseIdx,
  528. &hRootDir,
  529. volPathName,
  530. (sizeof(volPathName)/sizeof(wchar_t)) );
  531. if (status != ERROR_SUCCESS) {
  532. return;
  533. }
  534. //
  535. // display the SIS files
  536. //
  537. DisplaySisFiles( hReparseIdx,
  538. hRootDir,
  539. volPathName );
  540. //
  541. // close the files
  542. //
  543. CloseReparseInformation( &hReparseIdx, &hRootDir );
  544. break;
  545. }
  546. }
  547. //
  548. // If it is still "1" then no parameter were given, display usage
  549. //
  550. if (!didSomething) {
  551. DisplayUsage();
  552. }
  553. }