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.

1365 lines
37 KiB

  1. /*++
  2. Copyright (c) 1998-2000 Microsoft Corporation
  3. Module Name:
  4. config.c
  5. Abstract:
  6. This is where we handle both our file based config and registry based
  7. config.
  8. most config is stored in the registry, with the file base config being
  9. reserved for config that must not be reverted during a restore.
  10. Author:
  11. Paul McDaniel (paulmcd) 27-Apr-2000
  12. Revision History:
  13. --*/
  14. #include "precomp.h"
  15. //
  16. // Private constants.
  17. //
  18. //
  19. // Private types.
  20. //
  21. //
  22. // Private prototypes.
  23. //
  24. NTSTATUS
  25. SrWriteLongParameter(
  26. IN HANDLE ParametersHandle,
  27. IN PWCHAR ValueName,
  28. IN LONG DefaultValue
  29. );
  30. LONG
  31. SrReadLongParameter(
  32. IN HANDLE ParametersHandle,
  33. IN PWCHAR ValueName,
  34. IN LONG DefaultValue
  35. );
  36. NTSTATUS
  37. SrReadGenericParameter(
  38. IN HANDLE ParametersHandle,
  39. IN PWCHAR ValueName,
  40. OUT PKEY_VALUE_PARTIAL_INFORMATION * Value
  41. );
  42. //
  43. // linker commands
  44. //
  45. #ifdef ALLOC_PRAGMA
  46. #pragma alloc_text( PAGE, SrWriteLongParameter )
  47. #pragma alloc_text( PAGE, SrReadLongParameter )
  48. #pragma alloc_text( PAGE, SrReadGenericParameter )
  49. #pragma alloc_text( PAGE, SrReadRegistry )
  50. #pragma alloc_text( PAGE, SrReadConfigFile )
  51. #pragma alloc_text( PAGE, SrWriteConfigFile )
  52. #pragma alloc_text( PAGE, SrReadBlobInfo )
  53. #pragma alloc_text( PAGE, SrReadBlobInfoWorker )
  54. #endif // ALLOC_PRAGMA
  55. /***************************************************************************++
  56. Routine Description:
  57. Writes a single (LONG/ULONG) value from the registry.
  58. Arguments:
  59. ParametersHandle - Supplies an open registry handle.
  60. ValueName - Supplies the name of the value to write.
  61. Value - Supplies the value.
  62. Return Value:
  63. LONG - The value read from the registry or the default if the
  64. registry data was unavailable or incorrect.
  65. --***************************************************************************/
  66. NTSTATUS
  67. SrWriteLongParameter(
  68. IN HANDLE ParametersHandle,
  69. IN PWCHAR ValueName,
  70. IN LONG DefaultValue
  71. )
  72. {
  73. UNICODE_STRING valueKeyName;
  74. NTSTATUS status;
  75. //
  76. // Sanity check.
  77. //
  78. PAGED_CODE();
  79. //
  80. // Build the value name, read it from the registry.
  81. //
  82. RtlInitUnicodeString( &valueKeyName,
  83. ValueName );
  84. status = ZwSetValueKey( ParametersHandle,
  85. &valueKeyName,
  86. 0,
  87. REG_DWORD,
  88. &DefaultValue,
  89. sizeof( LONG ) );
  90. return status;
  91. } // SrReadLongParameter
  92. /***************************************************************************++
  93. Routine Description:
  94. Reads a single (LONG/ULONG) value from the registry.
  95. Arguments:
  96. ParametersHandle - Supplies an open registry handle.
  97. ValueName - Supplies the name of the value to read.
  98. DefaultValue - Supplies the default value.
  99. Return Value:
  100. LONG - The value read from the registry or the default if the
  101. registry data was unavailable or incorrect.
  102. --***************************************************************************/
  103. LONG
  104. SrReadLongParameter(
  105. IN HANDLE ParametersHandle,
  106. IN PWCHAR ValueName,
  107. IN LONG DefaultValue
  108. )
  109. {
  110. PKEY_VALUE_PARTIAL_INFORMATION information;
  111. UNICODE_STRING valueKeyName;
  112. ULONG informationLength;
  113. LONG returnValue;
  114. NTSTATUS status;
  115. UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(LONG)];
  116. //
  117. // Sanity check.
  118. //
  119. PAGED_CODE();
  120. //
  121. // Build the value name, read it from the registry.
  122. //
  123. RtlInitUnicodeString( &valueKeyName,
  124. ValueName );
  125. information = (PKEY_VALUE_PARTIAL_INFORMATION)buffer;
  126. status = ZwQueryValueKey( ParametersHandle,
  127. &valueKeyName,
  128. KeyValuePartialInformation,
  129. (PVOID)information,
  130. sizeof(buffer),
  131. &informationLength );
  132. //
  133. // If the read succeeded, the type is DWORD and the length is
  134. // sane, use it. Otherwise, use the default.
  135. //
  136. if (status == STATUS_SUCCESS &&
  137. information->Type == REG_DWORD &&
  138. information->DataLength == sizeof(returnValue))
  139. {
  140. RtlCopyMemory( &returnValue, information->Data, sizeof(returnValue) );
  141. } else {
  142. returnValue = DefaultValue;
  143. }
  144. return returnValue;
  145. } // SrReadLongParameter
  146. /***************************************************************************++
  147. Routine Description:
  148. Reads a single free-form value from the registry.
  149. Arguments:
  150. ParametersHandle - Supplies an open registry handle.
  151. ValueName - Supplies the name of the value to read.
  152. Value - Receives the value read from the registry.
  153. Return Value:
  154. NTSTATUS - Completion status.
  155. --***************************************************************************/
  156. NTSTATUS
  157. SrReadGenericParameter(
  158. IN HANDLE ParametersHandle,
  159. IN PWCHAR ValueName,
  160. OUT PKEY_VALUE_PARTIAL_INFORMATION * Value
  161. )
  162. {
  163. KEY_VALUE_PARTIAL_INFORMATION partialInfo;
  164. UNICODE_STRING valueKeyName;
  165. ULONG informationLength;
  166. NTSTATUS status;
  167. PKEY_VALUE_PARTIAL_INFORMATION newValue;
  168. ULONG dataLength;
  169. //
  170. // Sanity check.
  171. //
  172. PAGED_CODE();
  173. //
  174. // Build the value name, then perform an initial read. The read
  175. // should fail with buffer overflow, but that's OK. We just want
  176. // to get the length of the data.
  177. //
  178. RtlInitUnicodeString( &valueKeyName, ValueName );
  179. status = ZwQueryValueKey( ParametersHandle,
  180. &valueKeyName,
  181. KeyValuePartialInformation,
  182. (PVOID)&partialInfo,
  183. sizeof(partialInfo),
  184. &informationLength );
  185. if (NT_ERROR(status))
  186. {
  187. return status;
  188. }
  189. //
  190. // Determine the data length. Ensure that strings and multi-sz get
  191. // properly terminated.
  192. //
  193. dataLength = partialInfo.DataLength - 1;
  194. if (partialInfo.Type == REG_SZ || partialInfo.Type == REG_EXPAND_SZ)
  195. {
  196. dataLength += 1;
  197. }
  198. if (partialInfo.Type == REG_MULTI_SZ)
  199. {
  200. dataLength += 2;
  201. }
  202. //
  203. // Allocate the buffer.
  204. //
  205. newValue = SR_ALLOCATE_STRUCT_WITH_SPACE( PagedPool,
  206. KEY_VALUE_PARTIAL_INFORMATION,
  207. dataLength,
  208. SR_REGISTRY_TAG );
  209. if (newValue == NULL)
  210. {
  211. return STATUS_INSUFFICIENT_RESOURCES;
  212. }
  213. //
  214. // update the actually allocated length for later use
  215. //
  216. dataLength += sizeof(KEY_VALUE_PARTIAL_INFORMATION);
  217. RtlZeroMemory( newValue, dataLength );
  218. //
  219. // Perform the actual read.
  220. //
  221. status = ZwQueryValueKey( ParametersHandle,
  222. &valueKeyName,
  223. KeyValuePartialInformation,
  224. (PVOID)(newValue),
  225. dataLength,
  226. &informationLength );
  227. if (NT_SUCCESS(status))
  228. {
  229. *Value = newValue;
  230. }
  231. else
  232. {
  233. SR_FREE_POOL( newValue, SR_REGISTRY_TAG );
  234. }
  235. RETURN(status);
  236. } // SrReadGenericParameter
  237. /***************************************************************************++
  238. Routine Description:
  239. Reads all of the config from the registry and stores it into global.
  240. Arguments:
  241. Return Value:
  242. NTSTATUS - completion code.
  243. --***************************************************************************/
  244. NTSTATUS
  245. SrReadRegistry(
  246. IN PUNICODE_STRING pRegistry,
  247. IN BOOLEAN InDriverEntry
  248. )
  249. {
  250. NTSTATUS Status;
  251. PWCHAR Buffer;
  252. USHORT BufferSize;
  253. UNICODE_STRING KeyName = {0,0,NULL};
  254. UNICODE_STRING SetupKeyName;
  255. OBJECT_ATTRIBUTES ObjectAttributes;
  256. HANDLE RegHandle = NULL;
  257. PKEY_VALUE_PARTIAL_INFORMATION pValue = NULL;
  258. ULONG ServiceStartType;
  259. PAGED_CODE();
  260. //
  261. // setup the defaults
  262. //
  263. global->DebugControl = SR_DEBUG_DEFAULTS;
  264. global->ProcNameOffset = PROCESS_NAME_OFFSET;
  265. global->Disabled = TRUE;
  266. global->DontBackup = FALSE;
  267. if (InDriverEntry)
  268. {
  269. #ifndef SYNC_LOG_WRITE
  270. global->LogBufferSize = SR_DEFAULT_LOG_BUFFER_SIZE;
  271. global->LogFlushFrequency = SR_DEFAULT_LOG_FLUSH_FREQUENCY;
  272. global->LogFlushDueTime.QuadPart = (LONGLONG)-1 * (global->LogFlushFrequency *
  273. NANO_FULL_SECOND);
  274. #endif
  275. global->LogAllocationUnit = SR_DEFAULT_LOG_ALLOCATION_UNIT;
  276. }
  277. //
  278. // We are going to use this buffer for all the key names we need to construct.
  279. // make sure that it is large enough to hold the larger of these two names.
  280. //
  281. if (sizeof(REGISTRY_PARAMETERS) > sizeof( REGISTRY_SRSERVICE ))
  282. {
  283. BufferSize = (USHORT) sizeof(REGISTRY_PARAMETERS);
  284. }
  285. else
  286. {
  287. BufferSize = (USHORT) sizeof( REGISTRY_SRSERVICE );
  288. }
  289. BufferSize += pRegistry->Length;
  290. Buffer = SR_ALLOCATE_ARRAY( PagedPool,
  291. WCHAR,
  292. BufferSize/sizeof( WCHAR ),
  293. SR_REGISTRY_TAG );
  294. if (Buffer == NULL)
  295. {
  296. Status = STATUS_INSUFFICIENT_RESOURCES;
  297. goto end;
  298. }
  299. //
  300. // Open the SR Service registry key
  301. //
  302. KeyName.Buffer = Buffer;
  303. KeyName.MaximumLength = BufferSize;
  304. {
  305. //
  306. // First we need to strip off the filter's service name from the
  307. // registry location.
  308. //
  309. PWCHAR ServiceName = NULL;
  310. ULONG ServiceNameLength = 0;
  311. Status = SrFindCharReverse( pRegistry->Buffer,
  312. pRegistry->Length,
  313. L'\\',
  314. &ServiceName,
  315. &ServiceNameLength );
  316. if (!NT_SUCCESS( Status ))
  317. {
  318. goto end;
  319. }
  320. ASSERT( ServiceName != NULL );
  321. ASSERT( ServiceNameLength > 0 );
  322. KeyName.Length = pRegistry->Length - ((USHORT)ServiceNameLength);
  323. RtlCopyMemory( KeyName.Buffer,
  324. pRegistry->Buffer,
  325. KeyName.Length );
  326. NULLPTR( ServiceName );
  327. //
  328. // Append SRService's name to the registry path.
  329. //
  330. Status = RtlAppendUnicodeToString( &KeyName, REGISTRY_SRSERVICE );
  331. if (!NT_SUCCESS( Status ))
  332. {
  333. goto end;
  334. }
  335. }
  336. //
  337. // We've built up the SR Service's name, so go open that registry location.
  338. //
  339. InitializeObjectAttributes( &ObjectAttributes,
  340. &KeyName,
  341. OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,
  342. NULL,
  343. NULL );
  344. Status = ZwOpenKey( &RegHandle, KEY_READ, &ObjectAttributes );
  345. if (!NT_SUCCESS( Status ))
  346. goto end;
  347. ServiceStartType = (ULONG)SrReadLongParameter( RegHandle,
  348. REGISTRY_SRSERVICE_START,
  349. SERVICE_DISABLED );
  350. ZwClose( RegHandle );
  351. NULLPTR( RegHandle );
  352. //
  353. // Now open the filter's registry parameters key.
  354. //
  355. KeyName.Length = 0;
  356. RtlCopyUnicodeString( &KeyName, pRegistry );
  357. Status = RtlAppendUnicodeToString( &KeyName, REGISTRY_PARAMETERS );
  358. if (!NT_SUCCESS( Status ))
  359. {
  360. goto end;
  361. }
  362. InitializeObjectAttributes( &ObjectAttributes, // ObjectAttributes
  363. &KeyName, // ObjectName
  364. OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, // Attributes
  365. NULL, // RootDirectory
  366. NULL ); // SecurityDescriptor
  367. Status = ZwOpenKey( &RegHandle, KEY_READ | KEY_WRITE, &ObjectAttributes );
  368. if (!NT_SUCCESS( Status ))
  369. {
  370. goto end;
  371. }
  372. //
  373. // If the usermode service is disabled, we want to set first run
  374. // and keep the filter disabled.
  375. //
  376. if (ServiceStartType == SERVICE_DISABLED)
  377. {
  378. Status = SrWriteLongParameter( RegHandle,
  379. REGISTRY_STARTDISABLED,
  380. 1 );
  381. CHECK_STATUS( Status );
  382. //
  383. // No matter what, accept the defaults and exit.
  384. //
  385. goto end;
  386. }
  387. //
  388. // The Usermode service is not disabled, so go ahead and read our
  389. // parameters to figure out the filter starting configuration.
  390. //
  391. #ifdef CONFIG_LOGGING_VIA_REGISTRY
  392. //
  393. // We will only read these globals from the registry if
  394. // CONFIG_LOGGING_VIA_REGISTRY is defined. This was added more for
  395. // initial tuning of these parameters to find a good place for the
  396. // default values to be set. We don't want to test all possible values
  397. // that could be set for the parameters, so we are disabling this
  398. // feature in the released version of sr.sys.
  399. //
  400. if (InDriverEntry)
  401. {
  402. #ifndef SYNC_LOG_WRITE
  403. global->LogBufferSize = (ULONG)SrReadLongParameter( RegHandle,
  404. REGISTRY_LOG_BUFFER_SIZE,
  405. global->LogBufferSize );
  406. global->LogFlushFrequency = (ULONG)SrReadLongParameter( RegHandle,
  407. REGISTRY_LOG_FLUSH_FREQUENCY,
  408. global->LogFlushFrequency );
  409. #endif
  410. global->LogAllocationUnit = (ULONG)SrReadLongParameter( RegHandle,
  411. REGISTRY_LOG_ALLOCATION_UNIT,
  412. global->LogAllocationUnit );
  413. }
  414. #endif
  415. #ifndef SYNC_LOG_WRITE
  416. global->LogFlushDueTime.QuadPart = (LONGLONG)-1 * (global->LogFlushFrequency *
  417. NANO_FULL_SECOND);
  418. #endif
  419. //
  420. // Read the debug flags.
  421. //
  422. global->DebugControl = (ULONG)SrReadLongParameter( RegHandle,
  423. REGISTRY_DEBUG_CONTROL,
  424. global->DebugControl );
  425. //
  426. // Read the processname offset from the registry
  427. //
  428. SrTrace(INIT, ("\tProcessNameOffset(Def) = %X\n", global->ProcNameOffset));
  429. global->ProcNameOffset = (ULONG)SrReadLongParameter( RegHandle,
  430. REGISTRY_PROCNAME_OFFSET,
  431. global->ProcNameOffset );
  432. //
  433. // read to see if we should startup disabled.
  434. //
  435. global->Disabled = (BOOLEAN)SrReadLongParameter( RegHandle,
  436. REGISTRY_STARTDISABLED,
  437. global->Disabled );
  438. //
  439. // read to see if we should make any copies
  440. //
  441. global->DontBackup = (BOOLEAN)SrReadLongParameter( RegHandle,
  442. REGISTRY_DONTBACKUP,
  443. global->DontBackup );
  444. //
  445. // read the machine guid
  446. //
  447. Status = SrReadGenericParameter( RegHandle,
  448. REGISTRY_MACHINE_GUID,
  449. &pValue );
  450. if (NT_SUCCESS(Status))
  451. {
  452. ASSERT(pValue != NULL);
  453. RtlZeroMemory( &global->MachineGuid[0],
  454. sizeof(global->MachineGuid) );
  455. if ( pValue->Type == REG_SZ &&
  456. pValue->DataLength < sizeof(global->MachineGuid) )
  457. {
  458. RtlCopyMemory( &global->MachineGuid[0],
  459. &pValue->Data[0],
  460. pValue->DataLength );
  461. }
  462. SR_FREE_POOL(pValue, SR_REGISTRY_TAG);
  463. pValue = NULL;
  464. }
  465. Status = STATUS_SUCCESS;
  466. //
  467. // close the old handle
  468. //
  469. ZwClose(RegHandle);
  470. NULLPTR( RegHandle );
  471. //
  472. // check if we are in the middle of gui mode setup
  473. //
  474. (VOID)RtlInitUnicodeString(&SetupKeyName, UPGRADE_CHECK_SETUP_KEY_NAME);
  475. InitializeObjectAttributes( &ObjectAttributes, // ObjectAttributes
  476. &SetupKeyName, // ObjectName
  477. OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, // Attributes
  478. NULL, // RootDirectory
  479. NULL ); // SecurityDescriptor
  480. Status = ZwOpenKey( &RegHandle, KEY_READ, &ObjectAttributes );
  481. if (Status == STATUS_SUCCESS && !global->Disabled)
  482. {
  483. global->Disabled = (BOOLEAN) SrReadLongParameter( RegHandle,
  484. UPGRADE_CHECK_SETUP_VALUE_NAME,
  485. global->Disabled );
  486. #if DBG
  487. if (global->Disabled)
  488. {
  489. SrTrace(INIT, ("sr!SrReadRegistry: disabled due to setup\n"));
  490. }
  491. #endif
  492. }
  493. Status = STATUS_SUCCESS;
  494. SrTrace(INIT, ("SR!SrReadRegistry(%wZ)\n", pRegistry));
  495. SrTrace(INIT, ("\tDisabled = %d\n", global->Disabled));
  496. SrTrace(INIT, ("\tDontBackup = %d\n", global->DontBackup));
  497. SrTrace(INIT, ("\tDebugControl = %X\n", global->DebugControl));
  498. SrTrace(INIT, ("\tProcessNameOffset = %X\n", global->ProcNameOffset));
  499. SrTrace(INIT, ("\tMachineGuid = %ws\n", &global->MachineGuid[0]));
  500. end:
  501. ASSERT(pValue == NULL);
  502. if (RegHandle != NULL)
  503. {
  504. ZwClose(RegHandle);
  505. RegHandle = NULL;
  506. }
  507. if (KeyName.Buffer != NULL)
  508. {
  509. SR_FREE_POOL(KeyName.Buffer, SR_REGISTRY_TAG);
  510. KeyName.Buffer = NULL;
  511. }
  512. //
  513. // no big deal if this fails... we default everything.
  514. //
  515. CHECK_STATUS(Status);
  516. return STATUS_SUCCESS;
  517. } // SrReadRegistry
  518. /***************************************************************************++
  519. Routine Description:
  520. Reads the file based config into global->FileConfig.
  521. Arguments:
  522. Return Value:
  523. NTSTATUS - completion code.
  524. --***************************************************************************/
  525. NTSTATUS
  526. SrReadConfigFile(
  527. )
  528. {
  529. NTSTATUS Status;
  530. HANDLE FileHandle = NULL;
  531. IO_STATUS_BLOCK IoStatusBlock;
  532. OBJECT_ATTRIBUTES ObjectAttributes;
  533. PUNICODE_STRING pFileName = NULL;
  534. ULONG CharCount;
  535. PSR_DEVICE_EXTENSION pSystemVolumeExtension = NULL;
  536. PAGED_CODE();
  537. ASSERT( IS_GLOBAL_LOCK_ACQUIRED() );
  538. //
  539. // allocate space for a filename
  540. //
  541. Status = SrAllocateFileNameBuffer(SR_MAX_FILENAME_LENGTH, &pFileName);
  542. if (!NT_SUCCESS( Status ))
  543. goto end;
  544. //
  545. // get the location of the system volume
  546. //
  547. Status = SrGetSystemVolume( pFileName,
  548. &pSystemVolumeExtension,
  549. SR_FILENAME_BUFFER_LENGTH );
  550. //
  551. // This should only happen if there was some problem with SR attaching
  552. // in the mount path. This check was added to make SR more robust to
  553. // busted filters above us. If other filters cause us to get mounted,
  554. // we won't have an extension to return here. While those filters are
  555. // broken, we don't want to AV.
  556. //
  557. if (pSystemVolumeExtension == NULL)
  558. {
  559. Status = STATUS_UNSUCCESSFUL;
  560. goto end;
  561. }
  562. if (!NT_SUCCESS( Status ))
  563. goto end;
  564. ASSERT( IS_VALID_SR_DEVICE_EXTENSION( pSystemVolumeExtension ) );
  565. //
  566. // now put the config file location in the string
  567. //
  568. CharCount = swprintf( &pFileName->Buffer[pFileName->Length/sizeof(WCHAR)],
  569. RESTORE_CONFIG_LOCATION,
  570. global->MachineGuid );
  571. pFileName->Length += (USHORT)CharCount * sizeof(WCHAR);
  572. //
  573. // attempt to open the file
  574. //
  575. InitializeObjectAttributes( &ObjectAttributes,
  576. pFileName,
  577. OBJ_KERNEL_HANDLE,
  578. NULL,
  579. NULL );
  580. Status = SrIoCreateFile( &FileHandle,
  581. FILE_GENERIC_READ, // DesiredAccess
  582. &ObjectAttributes,
  583. &IoStatusBlock,
  584. NULL, // AllocationSize
  585. FILE_ATTRIBUTE_NORMAL,
  586. FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
  587. FILE_OPEN, // OPEN_EXISTING
  588. FILE_SYNCHRONOUS_IO_NONALERT,
  589. NULL, // EaBuffer
  590. 0, // EaLength
  591. 0,
  592. pSystemVolumeExtension->pTargetDevice );
  593. if (Status == STATUS_OBJECT_NAME_NOT_FOUND ||
  594. Status == STATUS_OBJECT_PATH_NOT_FOUND)
  595. {
  596. //
  597. // not there? that's ok (firstrun)
  598. //
  599. RtlZeroMemory(&global->FileConfig, sizeof(global->FileConfig));
  600. global->FileConfig.Signature = SR_PERSISTENT_CONFIG_TAG;
  601. Status = STATUS_SUCCESS;
  602. goto end;
  603. }
  604. //
  605. // any other errors?
  606. //
  607. else if (!NT_SUCCESS( Status ))
  608. goto end;
  609. //
  610. // read the structure
  611. //
  612. Status = ZwReadFile( FileHandle,
  613. NULL, // Event
  614. NULL, // ApcRoutine OPTIONAL,
  615. NULL, // ApcContext OPTIONAL,
  616. &IoStatusBlock,
  617. &global->FileConfig,
  618. sizeof(global->FileConfig),
  619. NULL, // ByteOffset
  620. NULL ); // Key
  621. if (!NT_SUCCESS( Status ))
  622. goto end;
  623. if (IoStatusBlock.Information != sizeof(global->FileConfig))
  624. {
  625. Status = STATUS_DEVICE_CONFIGURATION_ERROR;
  626. goto end;
  627. }
  628. if (global->FileConfig.Signature != SR_PERSISTENT_CONFIG_TAG)
  629. {
  630. Status = STATUS_DEVICE_CONFIGURATION_ERROR;
  631. goto end;
  632. }
  633. //
  634. // close the file
  635. //
  636. ZwClose(FileHandle);
  637. FileHandle = NULL;
  638. //
  639. // now update our file number counters, use the stored next file number
  640. //
  641. global->LastFileNameNumber = global->FileConfig.FileNameNumber;
  642. //
  643. // update the saved file config by the increment to handle power
  644. // failures. when the machine recoveres from a power failure, we will
  645. // use +1000 for the next temp file numbers to avoid any accidental
  646. // overlap
  647. //
  648. global->FileConfig.FileNameNumber += SR_FILE_NUMBER_INCREMENT;
  649. //
  650. // now update our Seq number counters
  651. //
  652. global->LastSeqNumber = global->FileConfig.FileSeqNumber;
  653. //
  654. // update the saved file config by the increment to handle power
  655. // failures. when the machine recoveres from a power failure, we will
  656. // use +1000 for the next temp file numbers to avoid any accidental
  657. // overlap
  658. //
  659. global->FileConfig.FileSeqNumber += SR_SEQ_NUMBER_INCREMENT;
  660. //
  661. // temporarily write out this update
  662. //
  663. Status = SrWriteConfigFile();
  664. if (!NT_SUCCESS( Status ))
  665. goto end;
  666. SrTrace(INIT, ("SR!SrReadConfigFile()\n"));
  667. SrTrace(INIT, ("\tLastFileNameNumber = %d\n",
  668. global->LastFileNameNumber ));
  669. SrTrace(INIT, ("\tFileConfig.FileNameNumber = %d\n",
  670. global->FileConfig.FileNameNumber ));
  671. SrTrace(INIT, ("\tFileConfig.FileSeqNumber = %I64d\n",
  672. global->FileConfig.FileSeqNumber ));
  673. SrTrace(INIT, ("\tFileConfig.CurrentRestoreNumber = %d\n",
  674. global->FileConfig.CurrentRestoreNumber ));
  675. end:
  676. if (FileHandle != NULL)
  677. {
  678. ZwClose(FileHandle);
  679. FileHandle = NULL;
  680. }
  681. if (pFileName != NULL)
  682. {
  683. SrFreeFileNameBuffer(pFileName);
  684. pFileName = NULL;
  685. }
  686. RETURN(Status);
  687. } // SrReadConfigFile
  688. /***************************************************************************++
  689. Routine Description:
  690. Writes the contents of global->FileConfig to the file based config.
  691. Arguments:
  692. Return Value:
  693. NTSTATUS - completion code.
  694. --***************************************************************************/
  695. NTSTATUS
  696. SrWriteConfigFile(
  697. )
  698. {
  699. NTSTATUS Status;
  700. HANDLE FileHandle = NULL;
  701. IO_STATUS_BLOCK IoStatusBlock;
  702. OBJECT_ATTRIBUTES ObjectAttributes;
  703. PUNICODE_STRING pFileName = NULL;
  704. ULONG CharCount;
  705. PUCHAR pBuffer = NULL;
  706. PFILE_OBJECT pFileObject = NULL;
  707. PDEVICE_OBJECT pDeviceObject;
  708. PSR_DEVICE_EXTENSION pSystemVolumeExtension = NULL;
  709. FILE_END_OF_FILE_INFORMATION EndOfFileInformation;
  710. PAGED_CODE();
  711. ASSERT( IS_GLOBAL_LOCK_ACQUIRED() );
  712. try {
  713. //
  714. // make sure we have a semi-good global structure
  715. //
  716. if (global->FileConfig.Signature != SR_PERSISTENT_CONFIG_TAG)
  717. {
  718. Status = STATUS_DEVICE_CONFIGURATION_ERROR;
  719. leave;
  720. }
  721. //
  722. // allocate space for a filename
  723. //
  724. Status = SrAllocateFileNameBuffer(SR_MAX_FILENAME_LENGTH, &pFileName);
  725. if (!NT_SUCCESS( Status ))
  726. leave;
  727. //
  728. // get the location of the system volume
  729. //
  730. Status = SrGetSystemVolume( pFileName,
  731. &pSystemVolumeExtension,
  732. SR_FILENAME_BUFFER_LENGTH );
  733. if (!NT_SUCCESS( Status ))
  734. leave;
  735. //
  736. // and now append on the _restore location and the filename
  737. //
  738. CharCount = swprintf( &pFileName->Buffer[pFileName->Length/sizeof(WCHAR)],
  739. RESTORE_CONFIG_LOCATION,
  740. global->MachineGuid );
  741. pFileName->Length += (USHORT)CharCount * sizeof(WCHAR);
  742. //
  743. // attempt to open the file
  744. //
  745. InitializeObjectAttributes( &ObjectAttributes,
  746. pFileName,
  747. OBJ_KERNEL_HANDLE,
  748. NULL,
  749. NULL );
  750. if (pSystemVolumeExtension) {
  751. //
  752. // Most of the time when this routine is called, we are attached
  753. // to the system volume already, so just send all IO to the filters
  754. // below us by using SrIoCreateFile to get the file handle.
  755. //
  756. ASSERT( IS_VALID_SR_DEVICE_EXTENSION( pSystemVolumeExtension ) );
  757. Status = SrIoCreateFile( &FileHandle,
  758. FILE_GENERIC_WRITE, // DesiredAccess
  759. &ObjectAttributes,
  760. &IoStatusBlock,
  761. NULL, // AllocationSize
  762. FILE_ATTRIBUTE_NORMAL,
  763. FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
  764. FILE_OPEN_IF,
  765. FILE_SYNCHRONOUS_IO_NONALERT
  766. | FILE_NO_INTERMEDIATE_BUFFERING,
  767. NULL, // EaBuffer
  768. 0, // EaLength
  769. 0,
  770. pSystemVolumeExtension->pTargetDevice );
  771. } else {
  772. //
  773. // When this is called from SrUnload, we have already detached
  774. // our device from the filter stack, so just use the regular
  775. // ZwCreateFile to open the config file.
  776. //
  777. Status = ZwCreateFile( &FileHandle,
  778. FILE_GENERIC_WRITE, // DesiredAccess
  779. &ObjectAttributes,
  780. &IoStatusBlock,
  781. NULL, // AllocationSize
  782. FILE_ATTRIBUTE_NORMAL,
  783. FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
  784. FILE_OPEN_IF,
  785. FILE_SYNCHRONOUS_IO_NONALERT
  786. | FILE_NO_INTERMEDIATE_BUFFERING,
  787. NULL, // EaBuffer
  788. 0 ); // EaLength
  789. }
  790. //
  791. // it's possible for the path to have been deleted by the service
  792. // if we reported a volume error while processing. during shutdown
  793. // we will not be able to write our config file, that's ok to ignore,
  794. // we are shutting down.
  795. //
  796. if (Status == STATUS_OBJECT_PATH_NOT_FOUND)
  797. {
  798. Status = STATUS_SUCCESS;
  799. leave;
  800. }
  801. else if (!NT_SUCCESS( Status ))
  802. {
  803. leave;
  804. }
  805. //
  806. // get the file object
  807. //
  808. Status = ObReferenceObjectByHandle( FileHandle,
  809. 0,
  810. *IoFileObjectType,
  811. KernelMode,
  812. (PVOID *) &pFileObject,
  813. NULL );
  814. if (!NT_SUCCESS( Status ))
  815. leave;
  816. //
  817. // now the device so that we have the sector size
  818. //
  819. pDeviceObject = IoGetRelatedDeviceObject(pFileObject);
  820. ASSERT(IS_VALID_DEVICE_OBJECT(pDeviceObject));
  821. //
  822. // allocate a PAGE to use as a temp buffer for sector alignment.
  823. //
  824. pBuffer = SR_ALLOCATE_POOL( PagedPool,
  825. PAGE_SIZE,
  826. SR_PERSISTENT_CONFIG_TAG );
  827. if (pBuffer == NULL)
  828. {
  829. Status = STATUS_INSUFFICIENT_RESOURCES;
  830. leave;
  831. }
  832. //
  833. // copy just our bytes
  834. //
  835. RtlCopyMemory(pBuffer, &global->FileConfig, sizeof(global->FileConfig));
  836. //
  837. // uncached reads and writes need to be sector aligned, plus the data
  838. // being asked for needs to be sector padded. since PAGE_SIZE is a power
  839. // of 2, and sector sizes are powers of 2, then will always be aligned
  840. // (ExAllocatePool page aligns all allocations over a page).
  841. //
  842. // we need to also make sure it is also sector padded.
  843. //
  844. ASSERT(pDeviceObject->SectorSize >= sizeof(global->FileConfig));
  845. ASSERT(pDeviceObject->SectorSize <= PAGE_SIZE);
  846. //
  847. // write the sector
  848. //
  849. Status = ZwWriteFile( FileHandle,
  850. NULL, // Event
  851. NULL, // ApcRoutine OPTIONAL,
  852. NULL, // ApcContext OPTIONAL,
  853. &IoStatusBlock,
  854. pBuffer,
  855. pDeviceObject->SectorSize,
  856. NULL, // ByteOffset
  857. NULL ); // Key
  858. if (!NT_SUCCESS( Status ))
  859. leave;
  860. //
  861. // truncate the file
  862. //
  863. EndOfFileInformation.EndOfFile.QuadPart = sizeof(global->FileConfig);
  864. Status = ZwSetInformationFile( FileHandle,
  865. &IoStatusBlock,
  866. &EndOfFileInformation,
  867. sizeof(EndOfFileInformation),
  868. FileEndOfFileInformation );
  869. if (!NT_SUCCESS( Status ))
  870. leave;
  871. SrTrace(INIT, ("SR!SrWriteConfigFile()\n"));
  872. SrTrace(INIT, ("\tLastFileNameNumber = %d\n",
  873. global->LastFileNameNumber ));
  874. SrTrace(INIT, ("\tFileConfig.FileNameNumber = %d\n",
  875. global->FileConfig.FileNameNumber ));
  876. SrTrace(INIT, ("\tFileConfig.FileSeqNumber = %I64d\n",
  877. global->FileConfig.FileSeqNumber ));
  878. SrTrace(INIT, ("\tFileConfig.CurrentRestoreNumber = %d\n",
  879. global->FileConfig.CurrentRestoreNumber ));
  880. } finally {
  881. //
  882. // check for unhandled exceptions
  883. //
  884. Status = FinallyUnwind(SrWriteConfigFile, Status);
  885. if (pFileObject != NULL)
  886. {
  887. ObDereferenceObject(pFileObject);
  888. pFileObject = NULL;
  889. }
  890. if (FileHandle != NULL)
  891. {
  892. ZwClose(FileHandle);
  893. FileHandle = NULL;
  894. }
  895. if (pFileName != NULL)
  896. {
  897. SrFreeFileNameBuffer(pFileName);
  898. pFileName = NULL;
  899. }
  900. if (pBuffer != NULL)
  901. {
  902. SR_FREE_POOL(pBuffer, SR_PERSISTENT_CONFIG_TAG);
  903. pBuffer = NULL;
  904. }
  905. }
  906. RETURN(Status);
  907. } // SrWriteConfigFile
  908. /***************************************************************************++
  909. Routine Description:
  910. Queue the necessary work off to a worker thread to
  911. reads in the blob info for file list exclusions.
  912. Note: If an error is returned, a volume error has already been
  913. generated.
  914. Arguments:
  915. Return Value:
  916. NTSTATUS - completion code.
  917. --***************************************************************************/
  918. NTSTATUS
  919. SrReadBlobInfo(
  920. )
  921. {
  922. NTSTATUS Status;
  923. PAGED_CODE();
  924. if (_globals.HitErrorLoadingBlob)
  925. {
  926. Status = SR_STATUS_VOLUME_DISABLED;
  927. }
  928. else
  929. {
  930. Status = SrPostSyncOperation( SrReadBlobInfoWorker,
  931. NULL );
  932. }
  933. return Status;
  934. } // SrReadBlobInfo
  935. /***************************************************************************++
  936. Routine Description:
  937. Does the work to read in the blob info for file list exclusions.
  938. This work is done in a worker thread to avoid stack overflow when loading
  939. this information.
  940. If there is some problem loading the blob, a volume error is generated on
  941. the system volume so that the service knows to shut down all the other
  942. volumes.
  943. Arguments:
  944. pOpenContext -- All the necessary information to perform the work of
  945. loading the blob info structure.
  946. Return Value:
  947. NTSTATUS - the status of this operation.
  948. --***************************************************************************/
  949. NTSTATUS
  950. SrReadBlobInfoWorker(
  951. IN PVOID pOpenContext
  952. )
  953. {
  954. NTSTATUS Status;
  955. PUNICODE_STRING pFileName = NULL;
  956. ULONG CharCount;
  957. PSR_DEVICE_EXTENSION pSystemVolumeExtension = NULL;
  958. PAGED_CODE();
  959. UNREFERENCED_PARAMETER( pOpenContext );
  960. //
  961. // allocate space for a filename
  962. //
  963. Status = SrAllocateFileNameBuffer(SR_MAX_FILENAME_LENGTH, &pFileName);
  964. if (!NT_SUCCESS(Status))
  965. goto end;
  966. //
  967. // get the location of the system volume
  968. //
  969. Status = SrGetSystemVolume( pFileName,
  970. &pSystemVolumeExtension,
  971. SR_FILENAME_BUFFER_LENGTH );
  972. //
  973. // This should only happen if there was some problem with SR attaching
  974. // in the mount path. This check was added to make SR more robust to
  975. // busted filters above us. If other filters cause us to get mounted,
  976. // we won't have an extension to return here. While those filters are
  977. // broken, we don't want to AV.
  978. //
  979. if (pSystemVolumeExtension == NULL)
  980. {
  981. Status = STATUS_UNSUCCESSFUL;
  982. goto end;
  983. }
  984. if (!NT_SUCCESS(Status))
  985. goto end;
  986. ASSERT( IS_VALID_SR_DEVICE_EXTENSION( pSystemVolumeExtension ) );
  987. //
  988. // load the file list config data
  989. //
  990. CharCount = swprintf( &pFileName->Buffer[pFileName->Length/sizeof(WCHAR)],
  991. RESTORE_FILELIST_LOCATION,
  992. global->MachineGuid );
  993. pFileName->Length += (USHORT)CharCount * sizeof(WCHAR);
  994. Status = SrLoadLookupBlob( pFileName,
  995. pSystemVolumeExtension->pTargetDevice,
  996. &global->BlobInfo );
  997. if (!NT_SUCCESS(Status))
  998. {
  999. NTSTATUS TempStatus;
  1000. //
  1001. // We can't load the lookup blob, so set the global flag that we hit
  1002. // an error trying to load the blob so we don't keep trying then
  1003. // generate a volume error on the system volume so that all the volumes
  1004. // will get frozen.
  1005. //
  1006. _globals.HitErrorLoadingBlob = TRUE;
  1007. SrTrace( VERBOSE_ERRORS,
  1008. ( "sr!SrReadBlobInfoWorker: error loading blob%X!\n",
  1009. Status ));
  1010. TempStatus = SrNotifyVolumeError( pSystemVolumeExtension,
  1011. pFileName,
  1012. Status,
  1013. SrEventVolumeError );
  1014. CHECK_STATUS( TempStatus );
  1015. }
  1016. end:
  1017. if (pFileName != NULL)
  1018. {
  1019. SrFreeFileNameBuffer(pFileName);
  1020. pFileName = NULL;
  1021. }
  1022. RETURN(Status);
  1023. }