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.

1341 lines
42 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. NtfsInit.c
  5. Abstract:
  6. This module implements the DRIVER_INITIALIZATION routine for Ntfs
  7. Author:
  8. Gary Kimura [GaryKi] 21-May-1991
  9. Revision History:
  10. --*/
  11. #include "NtfsProc.h"
  12. #define Dbg (DEBUG_TRACE_FSP_DISPATCHER)
  13. //
  14. // Reference our local attribute definitions
  15. //
  16. extern ATTRIBUTE_DEFINITION_COLUMNS NtfsAttributeDefinitions[];
  17. NTSTATUS
  18. DriverEntry (
  19. IN PDRIVER_OBJECT DriverObject,
  20. IN PUNICODE_STRING RegistryPath
  21. );
  22. VOID
  23. NtfsInitializeNtfsData (
  24. IN PDRIVER_OBJECT DriverObject
  25. );
  26. NTSTATUS
  27. NtfsQueryValueKey (
  28. IN PUNICODE_STRING KeyName,
  29. IN PUNICODE_STRING ValueName,
  30. IN OUT PULONG ValueLength,
  31. IN OUT PKEY_VALUE_FULL_INFORMATION *KeyValueInformation,
  32. IN OUT PBOOLEAN DeallocateKeyValue
  33. );
  34. BOOLEAN
  35. NtfsRunningOnWhat(
  36. IN USHORT SuiteMask,
  37. IN UCHAR ProductType
  38. );
  39. #ifdef ALLOC_PRAGMA
  40. #pragma alloc_text(INIT, DriverEntry)
  41. #pragma alloc_text(INIT, NtfsInitializeNtfsData)
  42. #pragma alloc_text(INIT, NtfsQueryValueKey)
  43. #pragma alloc_text(INIT, NtfsRunningOnWhat)
  44. #endif
  45. #define UPGRADE_SETUPDD_KEY_NAME L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Setupdd"
  46. #define UPGRADE_SETUPDD_VALUE_NAME L"Start"
  47. #define UPGRADE_CHECK_SETUP_KEY_NAME L"\\Registry\\Machine\\System\\Setup"
  48. #define UPGRADE_CHECK_SETUP_VALUE_NAME L"SystemSetupInProgress"
  49. #define UPGRADE_CHECK_SETUP_CMDLINE_NAME L"CmdLine"
  50. #define UPGRADE_CHECK_SETUP_ASR L"-asr"
  51. #define UPGRADE_CHECK_SETUP_NEWSETUP L"-newsetup"
  52. #define COMPATIBILITY_MODE_KEY_NAME L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\FileSystem"
  53. #define COMPATIBILITY_MODE_VALUE_NAME L"NtfsDisable8dot3NameCreation"
  54. #define EXTENDED_CHAR_MODE_VALUE_NAME L"NtfsAllowExtendedCharacterIn8dot3Name"
  55. #define DISABLE_LAST_ACCESS_VALUE_NAME L"NtfsDisableLastAccessUpdate"
  56. #define QUOTA_NOTIFY_RATE L"NtfsQuotaNotifyRate"
  57. #define MFT_ZONE_SIZE_VALUE_NAME L"NtfsMftZoneReservation"
  58. #define KEY_WORK_AREA ((sizeof(KEY_VALUE_FULL_INFORMATION) + \
  59. sizeof(ULONG)) + 128)
  60. NTSTATUS
  61. DriverEntry(
  62. IN PDRIVER_OBJECT DriverObject,
  63. IN PUNICODE_STRING RegistryPath
  64. )
  65. /*++
  66. Routine Description:
  67. This is the initialization routine for the Ntfs file system
  68. device driver. This routine creates the device object for the FileSystem
  69. device and performs all other driver initialization.
  70. Arguments:
  71. DriverObject - Pointer to driver object created by the system.
  72. Return Value:
  73. NTSTATUS - The function value is the final status from the initialization
  74. operation.
  75. --*/
  76. {
  77. NTSTATUS Status;
  78. UNICODE_STRING UnicodeString;
  79. PDEVICE_OBJECT DeviceObject;
  80. UNICODE_STRING KeyName;
  81. UNICODE_STRING ValueName;
  82. ULONG Value;
  83. ULONG KeyValueLength;
  84. UCHAR Buffer[KEY_WORK_AREA];
  85. PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
  86. BOOLEAN DeallocateKeyValue;
  87. UNREFERENCED_PARAMETER( RegistryPath );
  88. PAGED_CODE();
  89. //
  90. // Check to make sure structure overlays are correct.
  91. //
  92. ASSERT( FIELD_OFFSET( FILE_NAME, ParentDirectory) == FIELD_OFFSET(OVERLAY_LCB, OverlayParentDirectory ));
  93. ASSERT( FIELD_OFFSET( FILE_NAME, FileNameLength) == FIELD_OFFSET(OVERLAY_LCB, OverlayFileNameLength ));
  94. ASSERT( FIELD_OFFSET( FILE_NAME, Flags) == FIELD_OFFSET(OVERLAY_LCB, OverlayFlags ));
  95. ASSERT( FIELD_OFFSET( FILE_NAME, FileName) == FIELD_OFFSET(OVERLAY_LCB, OverlayFileName ));
  96. ASSERT( sizeof( DUPLICATED_INFORMATION ) >= (sizeof( QUICK_INDEX ) + (sizeof( ULONG ) * 4) + sizeof( PFILE_NAME )));
  97. //
  98. // The open attribute table entries should be 64-bit aligned.
  99. //
  100. ASSERT( sizeof( OPEN_ATTRIBUTE_ENTRY ) == QuadAlign( sizeof( OPEN_ATTRIBUTE_ENTRY )));
  101. //
  102. // The first entry in an open attribute data should be the links.
  103. //
  104. ASSERT( FIELD_OFFSET( OPEN_ATTRIBUTE_DATA, Links ) == 0 );
  105. //
  106. // Compute the last access increment. We convert the number of
  107. // minutes to number of 1/100 of nanoseconds. We have to be careful
  108. // not to overrun 32 bits for any multiplier.
  109. //
  110. // To reach 1/100 of nanoseconds per minute we take
  111. //
  112. // 1/100 nanoseconds * 10 = 1 microsecond
  113. // * 1000 = 1 millesecond
  114. // * 1000 = 1 second
  115. // * 60 = 1 minute
  116. //
  117. // Then multiply this by the last access increment in minutes.
  118. //
  119. NtfsLastAccess = Int32x32To64( ( 10 * 1000 * 1000 * 60 ), LAST_ACCESS_INCREMENT_MINUTES );
  120. //
  121. // Allocate the reserved buffers for USA writes - do this early so we don't have any
  122. // teardown to do.
  123. //
  124. NtfsReserved1 = NtfsAllocatePoolNoRaise( NonPagedPool, LARGE_BUFFER_SIZE );
  125. if (NULL == NtfsReserved1) {
  126. return STATUS_INSUFFICIENT_RESOURCES;
  127. }
  128. //
  129. // Buffer 2 is used for the workspace. It may require a slightly larger buffer on
  130. // a Win64 system.
  131. //
  132. NtfsReserved2 = NtfsAllocatePoolNoRaise( NonPagedPool, WORKSPACE_BUFFER_SIZE );
  133. if (NULL == NtfsReserved2) {
  134. NtfsFreePool( NtfsReserved1 );
  135. return STATUS_INSUFFICIENT_RESOURCES;
  136. }
  137. NtfsReserved3 = NtfsAllocatePoolNoRaise( NonPagedPool, LARGE_BUFFER_SIZE );
  138. if (NULL == NtfsReserved3) {
  139. NtfsFreePool( NtfsReserved1 );
  140. NtfsFreePool( NtfsReserved2 );
  141. return STATUS_INSUFFICIENT_RESOURCES;
  142. }
  143. //
  144. // Create the device object.
  145. //
  146. RtlInitUnicodeString( &UnicodeString, L"\\Ntfs" );
  147. Status = IoCreateDevice( DriverObject,
  148. 0,
  149. &UnicodeString,
  150. FILE_DEVICE_DISK_FILE_SYSTEM,
  151. 0,
  152. FALSE,
  153. &DeviceObject );
  154. if (!NT_SUCCESS( Status )) {
  155. return Status;
  156. }
  157. //
  158. // Note that because of the way data caching is done, we set neither
  159. // the Direct I/O or Buffered I/O bit in DeviceObject->Flags. If
  160. // data is not in the cache, or the request is not buffered, we may,
  161. // set up for Direct I/O by hand.
  162. //
  163. //
  164. // Initialize the driver object with this driver's entry points.
  165. //
  166. DriverObject->MajorFunction[IRP_MJ_QUERY_EA] =
  167. DriverObject->MajorFunction[IRP_MJ_SET_EA] =
  168. DriverObject->MajorFunction[IRP_MJ_QUERY_QUOTA] =
  169. DriverObject->MajorFunction[IRP_MJ_SET_QUOTA] =
  170. DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = (PDRIVER_DISPATCH)NtfsFsdDispatchWait;
  171. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
  172. DriverObject->MajorFunction[IRP_MJ_QUERY_SECURITY] =
  173. DriverObject->MajorFunction[IRP_MJ_SET_SECURITY] =
  174. DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] =
  175. DriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION] = (PDRIVER_DISPATCH)NtfsFsdDispatch;
  176. DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL] = (PDRIVER_DISPATCH)NtfsFsdLockControl;
  177. DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] = (PDRIVER_DISPATCH)NtfsFsdDirectoryControl;
  178. DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = (PDRIVER_DISPATCH)NtfsFsdSetInformation;
  179. DriverObject->MajorFunction[IRP_MJ_CREATE] = (PDRIVER_DISPATCH)NtfsFsdCreate;
  180. DriverObject->MajorFunction[IRP_MJ_CLOSE] = (PDRIVER_DISPATCH)NtfsFsdClose;
  181. DriverObject->MajorFunction[IRP_MJ_READ] = (PDRIVER_DISPATCH)NtfsFsdRead;
  182. DriverObject->MajorFunction[IRP_MJ_WRITE] = (PDRIVER_DISPATCH)NtfsFsdWrite;
  183. DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = (PDRIVER_DISPATCH)NtfsFsdFlushBuffers;
  184. DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = (PDRIVER_DISPATCH)NtfsFsdFileSystemControl;
  185. DriverObject->MajorFunction[IRP_MJ_CLEANUP] = (PDRIVER_DISPATCH)NtfsFsdCleanup;
  186. DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = (PDRIVER_DISPATCH)NtfsFsdShutdown;
  187. DriverObject->MajorFunction[IRP_MJ_PNP] = (PDRIVER_DISPATCH)NtfsFsdPnp;
  188. DriverObject->FastIoDispatch = &NtfsFastIoDispatch;
  189. NtfsFastIoDispatch.SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH);
  190. NtfsFastIoDispatch.FastIoCheckIfPossible = NtfsFastIoCheckIfPossible; // CheckForFastIo
  191. NtfsFastIoDispatch.FastIoRead = NtfsCopyReadA; // Read
  192. NtfsFastIoDispatch.FastIoWrite = NtfsCopyWriteA; // Write
  193. NtfsFastIoDispatch.FastIoQueryBasicInfo = NtfsFastQueryBasicInfo; // QueryBasicInfo
  194. NtfsFastIoDispatch.FastIoQueryStandardInfo = NtfsFastQueryStdInfo; // QueryStandardInfo
  195. NtfsFastIoDispatch.FastIoLock = NtfsFastLock; // Lock
  196. NtfsFastIoDispatch.FastIoUnlockSingle = NtfsFastUnlockSingle; // UnlockSingle
  197. NtfsFastIoDispatch.FastIoUnlockAll = NtfsFastUnlockAll; // UnlockAll
  198. NtfsFastIoDispatch.FastIoUnlockAllByKey = NtfsFastUnlockAllByKey; // UnlockAllByKey
  199. NtfsFastIoDispatch.FastIoDeviceControl = NULL; // IoDeviceControl
  200. NtfsFastIoDispatch.FastIoDetachDevice = NULL;
  201. NtfsFastIoDispatch.FastIoQueryNetworkOpenInfo = NtfsFastQueryNetworkOpenInfo;
  202. NtfsFastIoDispatch.AcquireFileForNtCreateSection = NtfsAcquireForCreateSection;
  203. NtfsFastIoDispatch.ReleaseFileForNtCreateSection = NtfsReleaseForCreateSection;
  204. NtfsFastIoDispatch.AcquireForModWrite = NtfsAcquireFileForModWrite;
  205. NtfsFastIoDispatch.MdlRead = NtfsMdlReadA;
  206. NtfsFastIoDispatch.MdlReadComplete = FsRtlMdlReadCompleteDev;
  207. NtfsFastIoDispatch.PrepareMdlWrite = NtfsPrepareMdlWriteA;
  208. NtfsFastIoDispatch.MdlWriteComplete = FsRtlMdlWriteCompleteDev;
  209. #ifdef COMPRESS_ON_WIRE
  210. NtfsFastIoDispatch.FastIoReadCompressed = NtfsCopyReadC;
  211. NtfsFastIoDispatch.FastIoWriteCompressed = NtfsCopyWriteC;
  212. NtfsFastIoDispatch.MdlReadCompleteCompressed = NtfsMdlReadCompleteCompressed;
  213. NtfsFastIoDispatch.MdlWriteCompleteCompressed = NtfsMdlWriteCompleteCompressed;
  214. #endif
  215. NtfsFastIoDispatch.FastIoQueryOpen = NtfsNetworkOpenCreate;
  216. NtfsFastIoDispatch.AcquireForCcFlush = NtfsAcquireFileForCcFlush;
  217. NtfsFastIoDispatch.ReleaseForCcFlush = NtfsReleaseFileForCcFlush;
  218. //
  219. // Initialize the global ntfs data structure
  220. //
  221. NtfsInitializeNtfsData( DriverObject );
  222. if (NtfsRunningOnWhat( VER_SUITE_PERSONAL, VER_NT_WORKSTATION )) {
  223. SetFlag( NtfsData.Flags, NTFS_FLAGS_PERSONAL );
  224. }
  225. KeInitializeMutant( &StreamFileCreationMutex, FALSE );
  226. KeInitializeEvent( &NtfsEncryptionPendingEvent, NotificationEvent, TRUE );
  227. //
  228. // Initialize the Ntfs Mcb global data queue and variables
  229. //
  230. ExInitializeFastMutex( &NtfsMcbFastMutex );
  231. InitializeListHead( &NtfsMcbLruQueue );
  232. NtfsMcbCleanupInProgress = FALSE;
  233. switch ( MmQuerySystemSize() ) {
  234. case MmSmallSystem:
  235. NtfsMcbHighWaterMark = 1000;
  236. NtfsMcbLowWaterMark = 500;
  237. NtfsMcbCurrentLevel = 0;
  238. break;
  239. case MmMediumSystem:
  240. NtfsMcbHighWaterMark = 4000;
  241. NtfsMcbLowWaterMark = 2000;
  242. NtfsMcbCurrentLevel = 0;
  243. break;
  244. case MmLargeSystem:
  245. default:
  246. NtfsMcbHighWaterMark = 16000;
  247. NtfsMcbLowWaterMark = 8000;
  248. NtfsMcbCurrentLevel = 0;
  249. break;
  250. }
  251. //
  252. // Double the watermark levels for all
  253. // systems running data center or server appliance
  254. //
  255. if (NtfsRunningOnWhat( VER_SUITE_DATACENTER, VER_NT_SERVER ) ||
  256. NtfsRunningOnWhat( VER_SUITE_DATACENTER, VER_NT_DOMAIN_CONTROLLER )) {
  257. NtfsMcbHighWaterMark <<= 1;
  258. NtfsMcbLowWaterMark <<= 1;
  259. }
  260. //
  261. // Allocate and initialize the free Eresource array
  262. //
  263. if ((NtfsData.FreeEresourceArray =
  264. NtfsAllocatePoolWithTagNoRaise( NonPagedPool, (NtfsData.FreeEresourceTotal * sizeof(PERESOURCE)), 'rftN')) == NULL) {
  265. KeBugCheck( NTFS_FILE_SYSTEM );
  266. }
  267. RtlZeroMemory( NtfsData.FreeEresourceArray, NtfsData.FreeEresourceTotal * sizeof(PERESOURCE) );
  268. //
  269. // Keep a zeroed out object id extended info around for comparisons in objidsup.c.
  270. //
  271. RtlZeroMemory( NtfsZeroExtendedInfo, sizeof(NtfsZeroExtendedInfo) );
  272. //
  273. // Register the file system with the I/O system
  274. //
  275. IoRegisterFileSystem(DeviceObject);
  276. //
  277. // Initialize logging.
  278. //
  279. NtfsInitializeLogging();
  280. //
  281. // Initialize global variables. (ntfsdata.c assumes 2-digit value for
  282. // $FILE_NAME)
  283. //
  284. ASSERT(($FILE_NAME >= 0x10) && ($FILE_NAME < 0x100));
  285. ASSERT( ((BOOLEAN) IRP_CONTEXT_STATE_WAIT) != FALSE );
  286. //
  287. // Some big assumptions are made when these bits are set in create. Let's
  288. // make sure those assumptions are still valid.
  289. //
  290. ASSERT( (READ_DATA_ACCESS == FILE_READ_DATA) &&
  291. (WRITE_DATA_ACCESS == FILE_WRITE_DATA) &&
  292. (APPEND_DATA_ACCESS == FILE_APPEND_DATA) &&
  293. (WRITE_ATTRIBUTES_ACCESS == FILE_WRITE_ATTRIBUTES) &&
  294. (EXECUTE_ACCESS == FILE_EXECUTE) &&
  295. (BACKUP_ACCESS == (TOKEN_HAS_BACKUP_PRIVILEGE << 2)) &&
  296. (RESTORE_ACCESS == (TOKEN_HAS_RESTORE_PRIVILEGE << 2)) );
  297. //
  298. // Let's make sure the number of attributes in the table is correct.
  299. //
  300. #ifdef NTFSDBG
  301. {
  302. ULONG Count = 0;
  303. while (NtfsAttributeDefinitions[Count].AttributeTypeCode != $UNUSED) {
  304. Count += 1;
  305. }
  306. //
  307. // We want to add one for the empty end record.
  308. //
  309. Count += 1;
  310. ASSERTMSG( "Update NtfsAttributeDefinitionsCount in attrdata.c",
  311. (Count == NtfsAttributeDefinitionsCount) );
  312. }
  313. #endif
  314. //
  315. // Read the registry to determine if we should upgrade the volumes.
  316. //
  317. DeallocateKeyValue = FALSE;
  318. KeyValueLength = KEY_WORK_AREA;
  319. KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION) &Buffer;
  320. KeyName.Buffer = UPGRADE_CHECK_SETUP_KEY_NAME;
  321. KeyName.Length = sizeof( UPGRADE_CHECK_SETUP_KEY_NAME ) - sizeof( WCHAR );
  322. KeyName.MaximumLength = sizeof( UPGRADE_CHECK_SETUP_KEY_NAME );
  323. ValueName.Buffer = UPGRADE_CHECK_SETUP_VALUE_NAME;
  324. ValueName.Length = sizeof( UPGRADE_CHECK_SETUP_VALUE_NAME ) - sizeof( WCHAR );
  325. ValueName.MaximumLength = sizeof( UPGRADE_CHECK_SETUP_VALUE_NAME );
  326. //
  327. // Look for the SystemSetupInProgress flag.
  328. //
  329. Status = NtfsQueryValueKey( &KeyName, &ValueName, &KeyValueLength, &KeyValueInformation, &DeallocateKeyValue );
  330. if (NT_SUCCESS( Status )) {
  331. if (*((PULONG) Add2Ptr( KeyValueInformation, KeyValueInformation->DataOffset )) == 1) {
  332. SetFlag( NtfsData.Flags, NTFS_FLAGS_DISABLE_UPGRADE );
  333. }
  334. //
  335. // Otherwise look to see if the setupdd value is present.
  336. //
  337. } else {
  338. if (KeyValueInformation == NULL) {
  339. DeallocateKeyValue = FALSE;
  340. KeyValueLength = KEY_WORK_AREA;
  341. KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION) &Buffer;
  342. }
  343. KeyName.Buffer = UPGRADE_SETUPDD_KEY_NAME;
  344. KeyName.Length = sizeof( UPGRADE_SETUPDD_KEY_NAME ) - sizeof( WCHAR );
  345. KeyName.MaximumLength = sizeof( UPGRADE_SETUPDD_KEY_NAME );
  346. ValueName.Buffer = UPGRADE_SETUPDD_VALUE_NAME;
  347. ValueName.Length = sizeof( UPGRADE_SETUPDD_VALUE_NAME ) - sizeof( WCHAR );
  348. ValueName.MaximumLength = sizeof( UPGRADE_SETUPDD_VALUE_NAME );
  349. Status = NtfsQueryValueKey( &KeyName, &ValueName, &KeyValueLength, &KeyValueInformation, &DeallocateKeyValue );
  350. //
  351. // The presence of this flag says "Don't upgrade"
  352. //
  353. if (NT_SUCCESS( Status )) {
  354. SetFlag( NtfsData.Flags, NTFS_FLAGS_DISABLE_UPGRADE );
  355. }
  356. }
  357. //
  358. // Read the registry to determine if we are to create short names.
  359. //
  360. if (KeyValueInformation == NULL) {
  361. DeallocateKeyValue = FALSE;
  362. KeyValueLength = KEY_WORK_AREA;
  363. KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION) &Buffer;
  364. }
  365. KeyName.Buffer = COMPATIBILITY_MODE_KEY_NAME;
  366. KeyName.Length = sizeof( COMPATIBILITY_MODE_KEY_NAME ) - sizeof( WCHAR );
  367. KeyName.MaximumLength = sizeof( COMPATIBILITY_MODE_KEY_NAME );
  368. ValueName.Buffer = COMPATIBILITY_MODE_VALUE_NAME;
  369. ValueName.Length = sizeof( COMPATIBILITY_MODE_VALUE_NAME ) - sizeof( WCHAR );
  370. ValueName.MaximumLength = sizeof( COMPATIBILITY_MODE_VALUE_NAME );
  371. Status = NtfsQueryValueKey( &KeyName, &ValueName, &KeyValueLength, &KeyValueInformation, &DeallocateKeyValue );
  372. //
  373. // If we didn't find the value or the value is zero then create the 8.3
  374. // names.
  375. //
  376. if (!NT_SUCCESS( Status ) ||
  377. (*((PULONG) Add2Ptr( KeyValueInformation, KeyValueInformation->DataOffset )) == 0)) {
  378. SetFlag( NtfsData.Flags, NTFS_FLAGS_CREATE_8DOT3_NAMES );
  379. }
  380. //
  381. // Read the registry to determine if we allow extended character in short name.
  382. //
  383. if (KeyValueInformation == NULL) {
  384. DeallocateKeyValue = FALSE;
  385. KeyValueLength = KEY_WORK_AREA;
  386. KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION) &Buffer;
  387. }
  388. ValueName.Buffer = EXTENDED_CHAR_MODE_VALUE_NAME;
  389. ValueName.Length = sizeof( EXTENDED_CHAR_MODE_VALUE_NAME ) - sizeof( WCHAR );
  390. ValueName.MaximumLength = sizeof( EXTENDED_CHAR_MODE_VALUE_NAME );
  391. Status = NtfsQueryValueKey( &KeyName, &ValueName, &KeyValueLength, &KeyValueInformation, &DeallocateKeyValue );
  392. //
  393. // If we didn't find the value or the value is zero then do not allow
  394. // extended character in 8.3 names.
  395. //
  396. if (NT_SUCCESS( Status ) &&
  397. (*((PULONG) Add2Ptr( KeyValueInformation, KeyValueInformation->DataOffset )) == 1)) {
  398. SetFlag( NtfsData.Flags, NTFS_FLAGS_ALLOW_EXTENDED_CHAR );
  399. }
  400. //
  401. // Read the registry to determine if we should disable last access updates.
  402. //
  403. if (KeyValueInformation == NULL) {
  404. DeallocateKeyValue = FALSE;
  405. KeyValueLength = KEY_WORK_AREA;
  406. KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION) &Buffer;
  407. }
  408. ValueName.Buffer = DISABLE_LAST_ACCESS_VALUE_NAME;
  409. ValueName.Length = sizeof( DISABLE_LAST_ACCESS_VALUE_NAME ) - sizeof( WCHAR );
  410. ValueName.MaximumLength = sizeof( DISABLE_LAST_ACCESS_VALUE_NAME );
  411. Status = NtfsQueryValueKey( &KeyName, &ValueName, &KeyValueLength, &KeyValueInformation, &DeallocateKeyValue );
  412. //
  413. // If we didn't find the value or the value is zero then don't update last access times.
  414. //
  415. if (NT_SUCCESS( Status ) &&
  416. (*((PULONG) Add2Ptr( KeyValueInformation, KeyValueInformation->DataOffset )) == 1)) {
  417. SetFlag( NtfsData.Flags, NTFS_FLAGS_DISABLE_LAST_ACCESS );
  418. }
  419. //
  420. // Read the registry to determine if we should change the Mft
  421. // Zone reservation.
  422. //
  423. NtfsMftZoneMultiplier = 1;
  424. if (KeyValueInformation == NULL) {
  425. DeallocateKeyValue = FALSE;
  426. KeyValueLength = KEY_WORK_AREA;
  427. KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION) &Buffer;
  428. }
  429. ValueName.Buffer = MFT_ZONE_SIZE_VALUE_NAME;
  430. ValueName.Length = sizeof( MFT_ZONE_SIZE_VALUE_NAME ) - sizeof( WCHAR );
  431. ValueName.MaximumLength = sizeof( MFT_ZONE_SIZE_VALUE_NAME );
  432. Status = NtfsQueryValueKey( &KeyName, &ValueName, &KeyValueLength, &KeyValueInformation, &DeallocateKeyValue );
  433. //
  434. // If we didn't find the value or the value is zero or greater than 4 then
  435. // use the default.
  436. //
  437. if (NT_SUCCESS( Status )) {
  438. ULONG NewMultiplier = *((PULONG) Add2Ptr( KeyValueInformation, KeyValueInformation->DataOffset ));
  439. if ((NewMultiplier != 0) && (NewMultiplier <= 4)) {
  440. NtfsMftZoneMultiplier = NewMultiplier;
  441. }
  442. }
  443. //
  444. // Read the registry to determine if the quota notification rate has been
  445. // change from the default.
  446. //
  447. if (KeyValueInformation == NULL) {
  448. DeallocateKeyValue = FALSE;
  449. KeyValueLength = KEY_WORK_AREA;
  450. KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION) &Buffer;
  451. }
  452. ValueName.Buffer = QUOTA_NOTIFY_RATE;
  453. ValueName.Length = sizeof( QUOTA_NOTIFY_RATE ) - sizeof( WCHAR );
  454. ValueName.MaximumLength = sizeof( QUOTA_NOTIFY_RATE );
  455. Status = NtfsQueryValueKey( &KeyName, &ValueName, &KeyValueLength, &KeyValueInformation, &DeallocateKeyValue );
  456. if (NT_SUCCESS( Status )) {
  457. Value = *((PULONG) Add2Ptr( KeyValueInformation, KeyValueInformation->DataOffset ));
  458. //
  459. // Value is in second, convert it to 100ns.
  460. //
  461. NtfsMaxQuotaNotifyRate = (ULONGLONG) Value * 1000 * 1000 * 10;
  462. }
  463. //
  464. // Setup the CheckPointAllVolumes callback item, timer, dpc, and
  465. // status.
  466. //
  467. ExInitializeWorkItem( &NtfsData.VolumeCheckpointItem,
  468. NtfsCheckpointAllVolumes,
  469. (PVOID)NULL );
  470. KeInitializeTimer( &NtfsData.VolumeCheckpointTimer );
  471. NtfsData.VolumeCheckpointStatus = 0;
  472. KeInitializeDpc( &NtfsData.VolumeCheckpointDpc,
  473. NtfsVolumeCheckpointDpc,
  474. NULL );
  475. NtfsData.TimerStatus = TIMER_NOT_SET;
  476. //
  477. // Setup the UsnTimeout callback item, timer, dpc, and
  478. // status.
  479. //
  480. ExInitializeWorkItem( &NtfsData.UsnTimeOutItem,
  481. NtfsCheckUsnTimeOut,
  482. (PVOID)NULL );
  483. KeInitializeTimer( &NtfsData.UsnTimeOutTimer );
  484. KeInitializeDpc( &NtfsData.UsnTimeOutDpc,
  485. NtfsUsnTimeOutDpc,
  486. NULL );
  487. {
  488. LONGLONG FiveMinutesFromNow = -5*1000*1000*10;
  489. FiveMinutesFromNow *= 60;
  490. KeSetTimer( &NtfsData.UsnTimeOutTimer,
  491. *(PLARGE_INTEGER)&FiveMinutesFromNow,
  492. &NtfsData.UsnTimeOutDpc );
  493. }
  494. //
  495. // Initialize sync objects for reserved buffers
  496. //
  497. ExInitializeFastMutex( &NtfsReservedBufferMutex );
  498. ExInitializeResource( &NtfsReservedBufferResource );
  499. //
  500. // Zero out the global upcase table, that way we'll fill it in on
  501. // our first successful mount
  502. //
  503. NtfsData.UpcaseTable = NULL;
  504. NtfsData.UpcaseTableSize = 0;
  505. ExInitializeFastMutex( &NtfsScavengerLock );
  506. NtfsScavengerWorkList = NULL;
  507. NtfsScavengerRunning = FALSE;
  508. //
  509. // Initialize the EFS driver
  510. //
  511. IoRegisterDriverReinitialization( DriverObject, NtfsLoadAddOns, NULL );
  512. //
  513. // And return to our caller
  514. //
  515. return( STATUS_SUCCESS );
  516. }
  517. VOID
  518. NtfsInitializeNtfsData (
  519. IN PDRIVER_OBJECT DriverObject
  520. )
  521. /*++
  522. Routine Description:
  523. This routine initializes the global ntfs data record
  524. Arguments:
  525. DriverObject - Supplies the driver object for NTFS
  526. Return Value:
  527. None.
  528. --*/
  529. {
  530. USHORT FileLockMaxDepth;
  531. USHORT IoContextMaxDepth;
  532. USHORT IrpContextMaxDepth;
  533. USHORT KeventMaxDepth;
  534. USHORT ScbNonpagedMaxDepth;
  535. USHORT ScbSnapshotMaxDepth;
  536. USHORT CcbDataMaxDepth;
  537. USHORT CcbMaxDepth;
  538. USHORT DeallocatedRecordsMaxDepth;
  539. USHORT FcbDataMaxDepth;
  540. USHORT FcbIndexMaxDepth;
  541. USHORT IndexContextMaxDepth;
  542. USHORT LcbMaxDepth;
  543. USHORT NukemMaxDepth;
  544. USHORT ScbDataMaxDepth;
  545. USHORT CompSyncMaxDepth;
  546. PSECURITY_SUBJECT_CONTEXT SubjectContext = NULL;
  547. BOOLEAN CapturedSubjectContext = FALSE;
  548. PACL SystemDacl = NULL;
  549. ULONG SystemDaclLength;
  550. PSID AdminSid = NULL;
  551. PSID SystemSid = NULL;
  552. NTSTATUS Status = STATUS_SUCCESS;
  553. PAGED_CODE();
  554. //
  555. // Zero the record.
  556. //
  557. RtlZeroMemory( &NtfsData, sizeof(NTFS_DATA));
  558. //
  559. // Initialize the queue of mounted Vcbs
  560. //
  561. InitializeListHead(&NtfsData.VcbQueue);
  562. //
  563. // This list head keeps track of closes yet to be done.
  564. //
  565. InitializeListHead( &NtfsData.AsyncCloseList );
  566. InitializeListHead( &NtfsData.DelayedCloseList );
  567. ExInitializeWorkItem( &NtfsData.NtfsCloseItem,
  568. (PWORKER_THREAD_ROUTINE)NtfsFspClose,
  569. NULL );
  570. //
  571. // Set the driver object, device object, and initialize the global
  572. // resource protecting the file system
  573. //
  574. NtfsData.DriverObject = DriverObject;
  575. ExInitializeResource( &NtfsData.Resource );
  576. ExInitializeFastMutex( &NtfsData.NtfsDataLock );
  577. //
  578. // Now allocate and initialize the s-list structures used as our pool
  579. // of IRP context records. The size of the zone is based on the
  580. // system memory size. We also initialize the spin lock used to protect
  581. // the zone.
  582. //
  583. {
  584. switch ( MmQuerySystemSize() ) {
  585. case MmSmallSystem:
  586. NtfsData.FreeEresourceTotal = 14;
  587. //
  588. // Nonpaged Lookaside list maximum depths
  589. //
  590. FileLockMaxDepth = 8;
  591. IoContextMaxDepth = 8;
  592. IrpContextMaxDepth = 4;
  593. KeventMaxDepth = 8;
  594. ScbNonpagedMaxDepth = 8;
  595. ScbSnapshotMaxDepth = 8;
  596. CompSyncMaxDepth = 4;
  597. //
  598. // Paged Lookaside list maximum depths
  599. //
  600. CcbDataMaxDepth = 4;
  601. CcbMaxDepth = 4;
  602. DeallocatedRecordsMaxDepth = 8;
  603. FcbDataMaxDepth = 8;
  604. FcbIndexMaxDepth = 4;
  605. IndexContextMaxDepth = 8;
  606. LcbMaxDepth = 4;
  607. NukemMaxDepth = 8;
  608. ScbDataMaxDepth = 4;
  609. SetFlag( NtfsData.Flags, NTFS_FLAGS_SMALL_SYSTEM );
  610. NtfsMaxDelayedCloseCount = MAX_DELAYED_CLOSE_COUNT;
  611. NtfsAsyncPostThreshold = ASYNC_CLOSE_POST_THRESHOLD;
  612. break;
  613. case MmMediumSystem:
  614. NtfsData.FreeEresourceTotal = 30;
  615. //
  616. // Nonpaged Lookaside list maximum depths
  617. //
  618. FileLockMaxDepth = 8;
  619. IoContextMaxDepth = 8;
  620. IrpContextMaxDepth = 8;
  621. KeventMaxDepth = 8;
  622. ScbNonpagedMaxDepth = 30;
  623. ScbSnapshotMaxDepth = 8;
  624. CompSyncMaxDepth = 8;
  625. //
  626. // Paged Lookaside list maximum depths
  627. //
  628. CcbDataMaxDepth = 12;
  629. CcbMaxDepth = 6;
  630. DeallocatedRecordsMaxDepth = 8;
  631. FcbDataMaxDepth = 30;
  632. FcbIndexMaxDepth = 12;
  633. IndexContextMaxDepth = 8;
  634. LcbMaxDepth = 12;
  635. NukemMaxDepth = 8;
  636. ScbDataMaxDepth = 12;
  637. SetFlag( NtfsData.Flags, NTFS_FLAGS_MEDIUM_SYSTEM );
  638. NtfsMaxDelayedCloseCount = 4 * MAX_DELAYED_CLOSE_COUNT;
  639. NtfsAsyncPostThreshold = 4 * ASYNC_CLOSE_POST_THRESHOLD;
  640. break;
  641. case MmLargeSystem:
  642. SetFlag( NtfsData.Flags, NTFS_FLAGS_LARGE_SYSTEM );
  643. NtfsMaxDelayedCloseCount = 16 * MAX_DELAYED_CLOSE_COUNT;
  644. NtfsAsyncPostThreshold = 16 * ASYNC_CLOSE_POST_THRESHOLD;
  645. if (MmIsThisAnNtAsSystem()) {
  646. NtfsData.FreeEresourceTotal = 256;
  647. //
  648. // Nonpaged Lookaside list maximum depths
  649. //
  650. FileLockMaxDepth = 8;
  651. IoContextMaxDepth = 8;
  652. IrpContextMaxDepth = 256;
  653. KeventMaxDepth = 8;
  654. ScbNonpagedMaxDepth = 128;
  655. ScbSnapshotMaxDepth = 8;
  656. CompSyncMaxDepth = 32;
  657. //
  658. // Paged Lookaside list maximum depths
  659. //
  660. CcbDataMaxDepth = 40;
  661. CcbMaxDepth = 20;
  662. DeallocatedRecordsMaxDepth = 8;
  663. FcbDataMaxDepth = 128;
  664. FcbIndexMaxDepth = 40;
  665. IndexContextMaxDepth = 8;
  666. LcbMaxDepth = 40;
  667. NukemMaxDepth = 8;
  668. ScbDataMaxDepth = 40;
  669. } else {
  670. NtfsData.FreeEresourceTotal = 128;
  671. //
  672. // Nonpaged Lookaside list maximum depths
  673. //
  674. FileLockMaxDepth = 8;
  675. IoContextMaxDepth = 8;
  676. IrpContextMaxDepth = 64;
  677. KeventMaxDepth = 8;
  678. ScbNonpagedMaxDepth = 64;
  679. ScbSnapshotMaxDepth = 8;
  680. CompSyncMaxDepth = 16;
  681. //
  682. // Paged Lookaside list maximum depths
  683. //
  684. CcbDataMaxDepth = 20;
  685. CcbMaxDepth = 10;
  686. DeallocatedRecordsMaxDepth = 8;
  687. FcbDataMaxDepth = 64;
  688. FcbIndexMaxDepth = 20;
  689. IndexContextMaxDepth = 8;
  690. LcbMaxDepth = 20;
  691. NukemMaxDepth = 8;
  692. ScbDataMaxDepth = 20;
  693. }
  694. break;
  695. }
  696. NtfsMinDelayedCloseCount = NtfsMaxDelayedCloseCount * 4 / 5;
  697. NtfsThrottleCreates = NtfsMinDelayedCloseCount * 2;
  698. }
  699. //
  700. // Initialize our various lookaside lists. To make it a bit more readable we'll
  701. // define two quick macros to do the initialization
  702. //
  703. #if DBG && i386 && defined (NTFSPOOLCHECK)
  704. #define NPagedInit(L,S,T,D) { ExInitializeNPagedLookasideList( (L), NtfsDebugAllocatePoolWithTag, NtfsDebugFreePool, POOL_RAISE_IF_ALLOCATION_FAILURE, S, T, D); }
  705. #define PagedInit(L,S,T,D) { ExInitializePagedLookasideList( (L), NtfsDebugAllocatePoolWithTag, NtfsDebugFreePool, POOL_RAISE_IF_ALLOCATION_FAILURE, S, T, D); }
  706. #else // DBG && i386
  707. #define NPagedInit(L,S,T,D) { ExInitializeNPagedLookasideList( (L), NULL, NULL, POOL_RAISE_IF_ALLOCATION_FAILURE, S, T, D); }
  708. #define PagedInit(L,S,T,D) { ExInitializePagedLookasideList( (L), NULL, NULL, POOL_RAISE_IF_ALLOCATION_FAILURE, S, T, D); }
  709. #endif // DBG && i386
  710. NPagedInit( &NtfsIoContextLookasideList, sizeof(NTFS_IO_CONTEXT), 'IftN', IoContextMaxDepth );
  711. NPagedInit( &NtfsIrpContextLookasideList, sizeof(IRP_CONTEXT), 'iftN', IrpContextMaxDepth );
  712. NPagedInit( &NtfsKeventLookasideList, sizeof(KEVENT), 'KftN', KeventMaxDepth );
  713. NPagedInit( &NtfsScbNonpagedLookasideList, sizeof(SCB_NONPAGED), 'nftN', ScbNonpagedMaxDepth );
  714. NPagedInit( &NtfsScbSnapshotLookasideList, sizeof(SCB_SNAPSHOT), 'TftN', ScbSnapshotMaxDepth );
  715. //
  716. // The compresson sync routine needs its own allocate and free routine in order to initialize and
  717. // cleanup the embedded resource.
  718. //
  719. ExInitializeNPagedLookasideList( &NtfsCompressSyncLookasideList,
  720. NtfsAllocateCompressionSync,
  721. NtfsDeallocateCompressionSync,
  722. 0,
  723. sizeof( COMPRESSION_SYNC ),
  724. 'vftN',
  725. CompSyncMaxDepth );
  726. PagedInit( &NtfsCcbLookasideList, sizeof(CCB), 'CftN', CcbMaxDepth );
  727. PagedInit( &NtfsCcbDataLookasideList, sizeof(CCB_DATA), 'cftN', CcbDataMaxDepth );
  728. PagedInit( &NtfsDeallocatedRecordsLookasideList, sizeof(DEALLOCATED_RECORDS), 'DftN', DeallocatedRecordsMaxDepth );
  729. PagedInit( &NtfsFcbDataLookasideList, sizeof(FCB_DATA), 'fftN', FcbDataMaxDepth );
  730. PagedInit( &NtfsFcbIndexLookasideList, sizeof(FCB_INDEX), 'FftN', FcbIndexMaxDepth );
  731. PagedInit( &NtfsIndexContextLookasideList, sizeof(INDEX_CONTEXT), 'EftN', IndexContextMaxDepth );
  732. PagedInit( &NtfsLcbLookasideList, sizeof(LCB), 'lftN', LcbMaxDepth );
  733. PagedInit( &NtfsNukemLookasideList, sizeof(NUKEM), 'NftN', NukemMaxDepth );
  734. PagedInit( &NtfsScbDataLookasideList, SIZEOF_SCB_DATA, 'sftN', ScbDataMaxDepth );
  735. //
  736. // Initialize the cache manager callback routines, First are the routines
  737. // for normal file manipulations, followed by the routines for
  738. // volume manipulations.
  739. //
  740. {
  741. PCACHE_MANAGER_CALLBACKS Callbacks = &NtfsData.CacheManagerCallbacks;
  742. Callbacks->AcquireForLazyWrite = &NtfsAcquireScbForLazyWrite;
  743. Callbacks->ReleaseFromLazyWrite = &NtfsReleaseScbFromLazyWrite;
  744. Callbacks->AcquireForReadAhead = &NtfsAcquireScbForReadAhead;
  745. Callbacks->ReleaseFromReadAhead = &NtfsReleaseScbFromReadAhead;
  746. }
  747. {
  748. PCACHE_MANAGER_CALLBACKS Callbacks = &NtfsData.CacheManagerVolumeCallbacks;
  749. Callbacks->AcquireForLazyWrite = &NtfsAcquireVolumeFileForLazyWrite;
  750. Callbacks->ReleaseFromLazyWrite = &NtfsReleaseVolumeFileFromLazyWrite;
  751. Callbacks->AcquireForReadAhead = NULL;
  752. Callbacks->ReleaseFromReadAhead = NULL;
  753. }
  754. //
  755. // Initialize the queue of read ahead threads
  756. //
  757. InitializeListHead(&NtfsData.ReadAheadThreads);
  758. //
  759. // Set up global pointer to our process.
  760. //
  761. NtfsData.OurProcess = PsGetCurrentProcess();
  762. //
  763. // Use a try-finally to cleanup on errors.
  764. //
  765. try {
  766. SECURITY_DESCRIPTOR NewDescriptor;
  767. SID_IDENTIFIER_AUTHORITY Authority = SECURITY_NT_AUTHORITY;
  768. SubjectContext = NtfsAllocatePool( PagedPool, sizeof( SECURITY_SUBJECT_CONTEXT ));
  769. SeCaptureSubjectContext( SubjectContext );
  770. CapturedSubjectContext = TRUE;
  771. //
  772. // Build the default security descriptor which gives full access to
  773. // system and administrator.
  774. //
  775. AdminSid = (PSID) NtfsAllocatePool( PagedPool, RtlLengthRequiredSid( 2 ));
  776. RtlInitializeSid( AdminSid, &Authority, 2 );
  777. *(RtlSubAuthoritySid( AdminSid, 0 )) = SECURITY_BUILTIN_DOMAIN_RID;
  778. *(RtlSubAuthoritySid( AdminSid, 1 )) = DOMAIN_ALIAS_RID_ADMINS;
  779. SystemSid = (PSID) NtfsAllocatePool( PagedPool, RtlLengthRequiredSid( 1 ));
  780. RtlInitializeSid( SystemSid, &Authority, 1 );
  781. *(RtlSubAuthoritySid( SystemSid, 0 )) = SECURITY_LOCAL_SYSTEM_RID;
  782. SystemDaclLength = sizeof( ACL ) +
  783. (2 * sizeof( ACCESS_ALLOWED_ACE )) +
  784. SeLengthSid( AdminSid ) +
  785. SeLengthSid( SystemSid ) +
  786. 8; // The 8 is just for good measure
  787. SystemDacl = NtfsAllocatePool( PagedPool, SystemDaclLength );
  788. Status = RtlCreateAcl( SystemDacl, SystemDaclLength, ACL_REVISION2 );
  789. if (!NT_SUCCESS( Status )) { leave; }
  790. Status = RtlAddAccessAllowedAce( SystemDacl,
  791. ACL_REVISION2,
  792. GENERIC_ALL,
  793. SystemSid );
  794. if (!NT_SUCCESS( Status )) { leave; }
  795. Status = RtlAddAccessAllowedAce( SystemDacl,
  796. ACL_REVISION2,
  797. GENERIC_ALL,
  798. AdminSid );
  799. if (!NT_SUCCESS( Status )) { leave; }
  800. Status = RtlCreateSecurityDescriptor( &NewDescriptor,
  801. SECURITY_DESCRIPTOR_REVISION1 );
  802. if (!NT_SUCCESS( Status )) { leave; }
  803. Status = RtlSetDaclSecurityDescriptor( &NewDescriptor,
  804. TRUE,
  805. SystemDacl,
  806. FALSE );
  807. if (!NT_SUCCESS( Status )) { leave; }
  808. Status = SeAssignSecurity( NULL,
  809. &NewDescriptor,
  810. &NtfsData.DefaultDescriptor,
  811. FALSE,
  812. SubjectContext,
  813. IoGetFileObjectGenericMapping(),
  814. PagedPool );
  815. if (!NT_SUCCESS( Status )) { leave; }
  816. NtfsData.DefaultDescriptorLength = RtlLengthSecurityDescriptor( NtfsData.DefaultDescriptor );
  817. ASSERT( SeValidSecurityDescriptor( NtfsData.DefaultDescriptorLength,
  818. NtfsData.DefaultDescriptor ));
  819. } finally {
  820. if (CapturedSubjectContext) {
  821. SeReleaseSubjectContext( SubjectContext );
  822. }
  823. if (SubjectContext != NULL) { NtfsFreePool( SubjectContext ); }
  824. if (SystemDacl != NULL) { NtfsFreePool( SystemDacl ); }
  825. if (AdminSid != NULL) { NtfsFreePool( AdminSid ); }
  826. if (SystemSid != NULL) { NtfsFreePool( SystemSid ); }
  827. }
  828. //
  829. // Raise if we hit an error building the security descriptor.
  830. //
  831. if (!NT_SUCCESS( Status )) { ExRaiseStatus( Status ); }
  832. //
  833. // Set its node type code and size. We do this last as a flag to indicate that the structure is
  834. // initialized.
  835. //
  836. NtfsData.NodeTypeCode = NTFS_NTC_DATA_HEADER;
  837. NtfsData.NodeByteSize = sizeof(NTFS_DATA);
  838. #ifdef SYSCACHE_DEBUG
  839. {
  840. int Index;
  841. for (Index=0; Index < NUM_SC_LOGSETS; Index++) {
  842. NtfsSyscacheLogSet[Index].SyscacheLog = 0;
  843. NtfsSyscacheLogSet[Index].Scb = 0;
  844. }
  845. NtfsCurrentSyscacheLogSet = -1;
  846. NtfsCurrentSyscacheOnDiskEntry = -1;
  847. }
  848. #endif
  849. //
  850. // And return to our caller
  851. //
  852. return;
  853. }
  854. //
  855. // Local Support routine
  856. //
  857. NTSTATUS
  858. NtfsQueryValueKey (
  859. IN PUNICODE_STRING KeyName,
  860. IN PUNICODE_STRING ValueName,
  861. IN OUT PULONG ValueLength,
  862. IN OUT PKEY_VALUE_FULL_INFORMATION *KeyValueInformation,
  863. IN OUT PBOOLEAN DeallocateKeyValue
  864. )
  865. /*++
  866. Routine Description:
  867. Given a unicode value name this routine will return the registry
  868. information for the given key and value.
  869. Arguments:
  870. KeyName - the unicode name for the key being queried.
  871. ValueName - the unicode name for the registry value located in the registry.
  872. ValueLength - On input it is the length of the allocated buffer. On output
  873. it is the length of the buffer. It may change if the buffer is
  874. reallocated.
  875. KeyValueInformation - On input it points to the buffer to use to query the
  876. the value information. On output it points to the buffer used to
  877. perform the query. It may change if a larger buffer is needed.
  878. DeallocateKeyValue - Indicates if the KeyValueInformation buffer is on the
  879. stack or needs to be deallocated.
  880. Return Value:
  881. NTSTATUS - indicates the status of querying the registry.
  882. --*/
  883. {
  884. HANDLE Handle;
  885. NTSTATUS Status;
  886. ULONG RequestLength;
  887. ULONG ResultLength;
  888. OBJECT_ATTRIBUTES ObjectAttributes;
  889. PVOID NewKey;
  890. InitializeObjectAttributes( &ObjectAttributes,
  891. KeyName,
  892. OBJ_CASE_INSENSITIVE,
  893. NULL,
  894. NULL);
  895. Status = ZwOpenKey( &Handle,
  896. KEY_READ,
  897. &ObjectAttributes);
  898. if (!NT_SUCCESS( Status )) {
  899. return Status;
  900. }
  901. RequestLength = *ValueLength;
  902. while (TRUE) {
  903. Status = ZwQueryValueKey( Handle,
  904. ValueName,
  905. KeyValueFullInformation,
  906. *KeyValueInformation,
  907. RequestLength,
  908. &ResultLength);
  909. ASSERT( Status != STATUS_BUFFER_OVERFLOW );
  910. if (Status == STATUS_BUFFER_OVERFLOW) {
  911. //
  912. // Try to get a buffer big enough.
  913. //
  914. if (*DeallocateKeyValue) {
  915. NtfsFreePool( *KeyValueInformation );
  916. *ValueLength = 0;
  917. *KeyValueInformation = NULL;
  918. *DeallocateKeyValue = FALSE;
  919. }
  920. RequestLength += 256;
  921. NewKey = (PKEY_VALUE_FULL_INFORMATION)
  922. NtfsAllocatePoolWithTagNoRaise( PagedPool,
  923. RequestLength,
  924. 'xftN');
  925. if (NewKey == NULL) {
  926. return STATUS_NO_MEMORY;
  927. }
  928. *KeyValueInformation = NewKey;
  929. *ValueLength = RequestLength;
  930. *DeallocateKeyValue = TRUE;
  931. } else {
  932. break;
  933. }
  934. }
  935. ZwClose(Handle);
  936. if (NT_SUCCESS(Status)) {
  937. //
  938. // Treat as if no value was found if the data length is zero.
  939. //
  940. if ((*KeyValueInformation)->DataLength == 0) {
  941. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  942. }
  943. }
  944. return Status;
  945. }
  946. BOOLEAN
  947. NtfsRunningOnWhat(
  948. IN USHORT SuiteMask,
  949. IN UCHAR ProductType
  950. )
  951. /*++
  952. Routine Description:
  953. This function checks the system to see if
  954. NTFS is running on a specified version of
  955. the operating system.
  956. The different versions are denoted by the product
  957. id and the product suite.
  958. Arguments:
  959. SuiteMask - The mask that specifies the requested suite(s)
  960. ProductType - The product type that specifies the requested product type
  961. Return Value:
  962. TRUE if NTFS is running on the requested version
  963. FALSE otherwise.
  964. --*/
  965. {
  966. OSVERSIONINFOEXW OsVer = {0};
  967. ULONGLONG ConditionMask = 0;
  968. PAGED_CODE();
  969. OsVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  970. OsVer.wSuiteMask = SuiteMask;
  971. OsVer.wProductType = ProductType;
  972. VER_SET_CONDITION( ConditionMask, VER_PRODUCT_TYPE, VER_EQUAL );
  973. VER_SET_CONDITION( ConditionMask, VER_SUITENAME, VER_AND );
  974. return RtlVerifyVersionInfo( &OsVer,
  975. VER_PRODUCT_TYPE | VER_SUITENAME,
  976. ConditionMask) == STATUS_SUCCESS;
  977. }