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.

778 lines
24 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. spdblfmt.c
  5. Abstract:
  6. This file contains the functions that format an existing compressed
  7. drive.
  8. To format a compressed drive we have to unmount the drive, map its
  9. cvf file in memory, initialize its varios regions, unmap the file
  10. from memory, and mount the drive.
  11. Author:
  12. Jaime Sasson (jaimes) 15-October-1993
  13. Revision History:
  14. --*/
  15. #include "spprecmp.h"
  16. #pragma hdrstop
  17. #include "cvf.h"
  18. #define MIN_CLUS_BIG 4085 // Minimum clustre for a big fat.
  19. //
  20. // This variable is needed since it contains a buffer that can
  21. // be used in kernel mode. The buffer is used by NtSetInformationFile,
  22. // since the Zw API is not exported
  23. //
  24. extern PSETUP_COMMUNICATION CommunicationParams;
  25. //
  26. // Global variables
  27. //
  28. HANDLE _FileHandle = NULL;
  29. HANDLE _SectionHandle = NULL;
  30. PVOID _FileBaseAddress = NULL;
  31. ULONG _ViewSize = 0;
  32. ULONG _Maximumcapacity = 0;
  33. NTSTATUS
  34. SpChangeFileAttribute(
  35. IN PWSTR FileName,
  36. IN ULONG FileAttributes
  37. )
  38. /*++
  39. Routine Description:
  40. Change the attributes of a file.
  41. Arguments:
  42. FileName - Contains the file's full path (NT name).
  43. FileAttributes - New desired file attributes.
  44. Return Value:
  45. NTSTATUS - Returns a NT status code indicating whether or not
  46. the operation succeeded.
  47. --*/
  48. {
  49. NTSTATUS Status;
  50. UNICODE_STRING UnicodeFileName;
  51. OBJECT_ATTRIBUTES ObjectAttributes;
  52. IO_STATUS_BLOCK IoStatusBlock;
  53. PIO_STATUS_BLOCK KernelModeIoStatusBlock;
  54. HANDLE Handle;
  55. PFILE_BASIC_INFORMATION KernelModeBasicInfo;
  56. // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Entering SpChangeFileAttribute() \n" ) );
  57. RtlInitUnicodeString( &UnicodeFileName,
  58. FileName );
  59. InitializeObjectAttributes( &ObjectAttributes,
  60. &UnicodeFileName,
  61. OBJ_CASE_INSENSITIVE,
  62. NULL,
  63. NULL );
  64. Status = ZwOpenFile( &Handle,
  65. FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
  66. &ObjectAttributes,
  67. &IoStatusBlock,
  68. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  69. FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT );
  70. if( !NT_SUCCESS( Status ) ) {
  71. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: ZwOpenFile() failed. Status = %x\n",Status ) );
  72. return( Status );
  73. }
  74. //
  75. // Set attributes.
  76. // Note that since we use the NtSetInformationFile API instead of the
  77. // Zw API (this one is not exported), we need a buffer for IoStatusBlock
  78. // and for FileBasicInformation, that can be used in kernel mode.
  79. // We use the the region of memory pointed by CommunicationParams for this
  80. // purpose.
  81. //
  82. KernelModeIoStatusBlock = ( PIO_STATUS_BLOCK )( &(CommunicationParams->Buffer[0]) );
  83. *KernelModeIoStatusBlock = IoStatusBlock;
  84. KernelModeBasicInfo = ( PFILE_BASIC_INFORMATION )( &(CommunicationParams->Buffer[128]) );
  85. RtlZeroMemory( KernelModeBasicInfo, sizeof( FILE_BASIC_INFORMATION ) );
  86. KernelModeBasicInfo->FileAttributes = ( FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS ) | FILE_ATTRIBUTE_NORMAL;
  87. Status = NtSetInformationFile( Handle,
  88. KernelModeIoStatusBlock,
  89. KernelModeBasicInfo,
  90. sizeof( FILE_BASIC_INFORMATION ),
  91. FileBasicInformation );
  92. if( !NT_SUCCESS( Status ) ) {
  93. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: NtSetInformationFile failed, Status = %x\n", Status) );
  94. }
  95. ZwClose( Handle );
  96. // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Exiting SpChangeFileAttribute() \n" ) );
  97. return( Status );
  98. }
  99. NTSTATUS
  100. SpMapCvfFileInMemory(
  101. IN PWSTR FileName
  102. )
  103. /*++
  104. Routine Description:
  105. Map a CVF file in memory.
  106. Arguments:
  107. FileName - Contains the file's full path (NT name).
  108. Return Value:
  109. NTSTATUS - Returns a NT status code indicating whether or not
  110. the operation succeeded.
  111. If the file is mapped successfully, this function will
  112. initialize the global variables _FileHandle, _SectionHandle,
  113. and _FileBaseAddress.
  114. --*/
  115. {
  116. NTSTATUS Status;
  117. UNICODE_STRING UnicodeFileName;
  118. OBJECT_ATTRIBUTES ObjectAttributes;
  119. IO_STATUS_BLOCK IoStatusBlock;
  120. LARGE_INTEGER SectionOffset;
  121. //
  122. // Open the CVF file for READ and WRITE access
  123. //
  124. RtlInitUnicodeString( &UnicodeFileName,
  125. FileName );
  126. InitializeObjectAttributes( &ObjectAttributes,
  127. &UnicodeFileName,
  128. OBJ_CASE_INSENSITIVE,
  129. NULL,
  130. NULL );
  131. Status = ZwOpenFile( &_FileHandle,
  132. FILE_GENERIC_READ | FILE_GENERIC_WRITE,
  133. &ObjectAttributes,
  134. &IoStatusBlock,
  135. 0,
  136. FILE_SYNCHRONOUS_IO_NONALERT );
  137. if( !NT_SUCCESS( Status ) ) {
  138. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: ZwOpenFile() failed. Status = %x\n",Status ) );
  139. return( Status );
  140. }
  141. //
  142. // Map the CVF file in memory
  143. //
  144. Status =
  145. ZwCreateSection( &_SectionHandle,
  146. STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ | SECTION_MAP_WRITE,
  147. NULL,
  148. NULL, // entire file.
  149. PAGE_READWRITE,
  150. SEC_COMMIT,
  151. _FileHandle
  152. );
  153. if(!NT_SUCCESS(Status)) {
  154. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: ZwCreateSection failed, Status = %x\n",Status));
  155. ZwClose( _FileHandle );
  156. _FileHandle = NULL;
  157. return(Status);
  158. }
  159. SectionOffset.LowPart = 0;
  160. SectionOffset.HighPart = 0;
  161. _ViewSize = 0;
  162. Status = ZwMapViewOfSection( _SectionHandle,
  163. NtCurrentProcess(),
  164. &_FileBaseAddress,
  165. 0,
  166. 0,
  167. &SectionOffset,
  168. &_ViewSize,
  169. ViewShare,
  170. 0,
  171. PAGE_READWRITE
  172. );
  173. // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "File size = %x\n", _ViewSize ) );
  174. if(!NT_SUCCESS(Status)) {
  175. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: ZwMapViewOfSection failed, Status = %x\n", Status));
  176. ZwClose( _SectionHandle );
  177. ZwClose( _FileHandle );
  178. _FileBaseAddress = NULL;
  179. _SectionHandle = NULL;
  180. _FileHandle = NULL;
  181. return(Status);
  182. }
  183. return( Status );
  184. }
  185. NTSTATUS
  186. SpUnmapCvfFileFromMemory(
  187. IN BOOLEAN SaveChanges
  188. )
  189. /*++
  190. Routine Description:
  191. Unmap the CFV file previously mapped in memory.
  192. Arguments:
  193. SaveChanges - Indicates whether or not the caller wants the changes made
  194. to the file flushed to disk.
  195. Return Value:
  196. NTSTATUS - Returns a NT status code indicating whether or not
  197. the operation succeeded.
  198. This function clears the global variables _FileHandle, _SectionHandle,
  199. and _FileBaseAddress.
  200. --*/
  201. {
  202. NTSTATUS Status;
  203. NTSTATUS PreviousStatus;
  204. // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Entering SpUnmapCvfFileFromMemory \n" ) );
  205. PreviousStatus = STATUS_SUCCESS;
  206. if( SaveChanges ) {
  207. Status = SpFlushVirtualMemory( _FileBaseAddress,
  208. _ViewSize );
  209. //
  210. // Status = NtFlushVirtualMemory( NtCurrentProcess(),
  211. // &_FileBaseAddress,
  212. // &_ViewSize,
  213. // &IoStatus );
  214. //
  215. if( !NT_SUCCESS( Status ) ) {
  216. PreviousStatus = Status;
  217. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpFlushVirtualMemory() failed, Status = %x\n", Status ) );
  218. }
  219. }
  220. Status = ZwUnmapViewOfSection( NtCurrentProcess(), _FileBaseAddress );
  221. if( !NT_SUCCESS( Status ) ) {
  222. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: ZwUnmapViewOfSection() failed, Status = %x \n", Status ) );
  223. }
  224. ZwClose( _SectionHandle );
  225. ZwClose( _FileHandle );
  226. _FileHandle = NULL;
  227. _SectionHandle = NULL;
  228. _FileBaseAddress = NULL;
  229. if( !NT_SUCCESS( PreviousStatus ) ) {
  230. return( PreviousStatus );
  231. }
  232. // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Exiting SpUnmapCvfFileFromMemory \n" ) );
  233. return( Status );
  234. }
  235. ULONG
  236. ComputeMaximumCapacity(
  237. IN ULONG HostDriveSize
  238. )
  239. /*++
  240. Routine Description:
  241. This function computes the maximum capacity for a compressed
  242. volume file on a host volume of a given size.
  243. Arguments:
  244. HostDriveSize -- Supplies the size in bytes of the host drive.
  245. Return Value:
  246. The appropriate Maximum Capacity.
  247. --*/
  248. {
  249. ULONG MaxCap;
  250. if( HostDriveSize < 20 * 1024L * 1024L ) {
  251. MaxCap = 16 * HostDriveSize;
  252. } else if ( HostDriveSize < 64 * 1024L * 1024L ) {
  253. MaxCap = 8 * HostDriveSize;
  254. } else {
  255. MaxCap = 4 * HostDriveSize;
  256. }
  257. if( MaxCap < 4 * 1024L * 1024L ) {
  258. MaxCap = 4 * 1024L * 1024L;
  259. } else if( MaxCap > 512 * 1024L * 1024L ) {
  260. MaxCap = 512 * 1024L * 1024L;
  261. }
  262. return MaxCap;
  263. }
  264. BOOLEAN
  265. CreateCvfHeader(
  266. OUT PCVF_HEADER CvfHeader,
  267. IN ULONG MaximumCapacity
  268. )
  269. /*++
  270. Routine Description:
  271. This function creates a Compressed Volume File and fills in
  272. the first sector with a valid CVF Header. The number of sectors
  273. in the DOS BPB is set to zero, to indicate that this volume
  274. file is not initialized.
  275. Arguments:
  276. CvfHeader -- Receives the created CVF header.
  277. MaximumCapacity -- Supplies the maximum capacity for the
  278. double-space volume, in bytes.
  279. Return Value:
  280. TRUE upon successful completion.
  281. --*/
  282. {
  283. ULONG Sectors, Clusters, Offset, SectorsInBitmap, SectorsInCvfFatExtension;
  284. if( MaximumCapacity % (8L * 1024L * 1024L) ) {
  285. // The volume maximum capacity must be a multiple of
  286. // eight megabytes.
  287. //
  288. return FALSE;
  289. }
  290. // Most of the fields in the DOS BPB have fixed values:
  291. //
  292. CvfHeader->Jump = 0xEB;
  293. CvfHeader->JmpOffset = 0x903c;
  294. memcpy( CvfHeader->Oem, "MSDSP6.0", 8 );
  295. CvfHeader->Bpb.BytesPerSector = DoubleSpaceBytesPerSector;
  296. CvfHeader->Bpb.SectorsPerCluster = DoubleSpaceSectorsPerCluster;
  297. // ReservedSectors computed below.
  298. CvfHeader->Bpb.Fats = DoubleSpaceFats;
  299. CvfHeader->Bpb.RootEntries = DoubleSpaceRootEntries;
  300. CvfHeader->Bpb.Sectors = 0;
  301. CvfHeader->Bpb.Media = DoubleSpaceMediaByte;
  302. // SectorsPerFat computed below.
  303. CvfHeader->Bpb.SectorsPerTrack = DoubleSpaceSectorsPerTrack;
  304. CvfHeader->Bpb.Heads = DoubleSpaceHeads;
  305. CvfHeader->Bpb.HiddenSectors = DoubleSpaceHiddenSectors;
  306. CvfHeader->Bpb.LargeSectors = 0;
  307. // Compute the number of sectors and clusters for the given
  308. // maximum capacity:
  309. //
  310. Sectors = MaximumCapacity / CvfHeader->Bpb.BytesPerSector;
  311. Clusters = Sectors / CvfHeader->Bpb.SectorsPerCluster;
  312. // Reserve space for a 16-bit FAT that's big enough for the
  313. // maximum number of clusters.
  314. //
  315. CvfHeader->Bpb.SectorsPerFat =
  316. ( USHORT )( (2 * Clusters + CvfHeader->Bpb.BytesPerSector - 1)/
  317. CvfHeader->Bpb.BytesPerSector );
  318. // DOS 6.2 requires that the first sector of the Sector Heap
  319. // be cluster aligned; since the Root Directory is one cluster,
  320. // this means that ReservedSectors plus SectorsPerFat must be
  321. // a multiple of SectorsPerCluster.
  322. //
  323. CvfHeader->Bpb.ReservedSectors = DoubleSpaceReservedSectors;
  324. Offset = (CvfHeader->Bpb.ReservedSectors + CvfHeader->Bpb.SectorsPerFat) %
  325. CvfHeader->Bpb.SectorsPerCluster;
  326. if( Offset != 0 ) {
  327. CvfHeader->Bpb.ReservedSectors +=
  328. ( USHORT )( CvfHeader->Bpb.SectorsPerCluster - Offset );
  329. }
  330. // So much for the DOS BPB. Now for the Double Space
  331. // BPB extensions. The location of the CVFFatExtension
  332. // table is preceded by sector zero, the bitmap, and
  333. // one reserved sector. Note that MaximumCapacity must
  334. // be a multiple of 8 Meg (8 * 1024 * 1024), which simplifies
  335. // calculation of SectorsInBitmap, SectorsInCvfFatExtension,
  336. // and CvfBitmap2KSize.
  337. //
  338. SectorsInBitmap = (Sectors / 8) / CvfHeader->Bpb.BytesPerSector;
  339. SectorsInCvfFatExtension = (Clusters * 4) / CvfHeader->Bpb.BytesPerSector;
  340. CvfHeader->CvfFatExtensionsLbnMinus1 = ( UCHAR )( SectorsInBitmap + 1 );
  341. CvfHeader->LogOfBytesPerSector = DoubleSpaceLog2BytesPerSector;
  342. CvfHeader->DosBootSectorLbn = ( USHORT )( DoubleSpaceReservedSectors2 +
  343. CvfHeader->CvfFatExtensionsLbnMinus1 + 1 +
  344. SectorsInCvfFatExtension );
  345. CvfHeader->DosRootDirectoryOffset =
  346. CvfHeader->Bpb.ReservedSectors + CvfHeader->Bpb.SectorsPerFat;
  347. CvfHeader->CvfHeapOffset =
  348. CvfHeader->DosRootDirectoryOffset + DoubleSpaceSectorsInRootDir;
  349. CvfHeader->CvfFatFirstDataEntry =
  350. CvfHeader->CvfHeapOffset / CvfHeader->Bpb.SectorsPerCluster - 2;
  351. CvfHeader->CvfBitmap2KSize = ( UCHAR )( SectorsInBitmap / DSSectorsPerBitmapPage );
  352. CvfHeader->LogOfSectorsPerCluster = DoubleSpaceLog2SectorsPerCluster;
  353. CvfHeader->Is12BitFat = 1;
  354. CvfHeader->MinFile = 32L * DoubleSpaceRootEntries +
  355. ( CvfHeader->DosBootSectorLbn +
  356. CvfHeader->Bpb.ReservedSectors +
  357. CvfHeader->Bpb.SectorsPerFat +
  358. CVF_MIN_HEAP_SECTORS ) *
  359. CvfHeader->Bpb.BytesPerSector;
  360. CvfHeader->CvfMaximumCapacity = (USHORT)(MaximumCapacity/(1024L * 1024L));
  361. return TRUE;
  362. }
  363. ULONG
  364. ComputeVirtualSectors(
  365. IN PCVF_HEADER CvfHeader,
  366. IN ULONG HostFileSize
  367. )
  368. /*++
  369. Routine Description:
  370. This function computes the appropriate number of virtual
  371. sectors for the given Compressed Volume File. Note that
  372. it always uses a ratio of 2.
  373. Arguments:
  374. CvfHeader -- Supplies the Compressed Volume File Header.
  375. HostFileSize -- Supplies the size of the host file in bytes.
  376. Return Value:
  377. The number of virtual sectors appropriate to this Compressed
  378. Volume File.
  379. --*/
  380. {
  381. CONST DefaultRatio = 2;
  382. ULONG SystemOverheadSectors, SectorsInFile,
  383. VirtualSectors, MaximumSectors, VirtualClusters;
  384. if( CvfHeader == NULL ||
  385. CvfHeader->Bpb.BytesPerSector == 0 ||
  386. CvfHeader->Bpb.SectorsPerCluster == 0 ) {
  387. return 0;
  388. }
  389. SystemOverheadSectors = CvfHeader->DosBootSectorLbn +
  390. CvfHeader->CvfHeapOffset +
  391. 2;
  392. SectorsInFile = HostFileSize / CvfHeader->Bpb.BytesPerSector;
  393. if( SectorsInFile < SystemOverheadSectors ) {
  394. return 0;
  395. }
  396. VirtualSectors = (SectorsInFile - SystemOverheadSectors) * DefaultRatio +
  397. CvfHeader->CvfHeapOffset;
  398. // VirtualSectors cannot result in more that 0xfff8 clusters on
  399. // the volume, nor can it be greater than the volume's maximum
  400. // capacity.
  401. //
  402. VirtualSectors = min( VirtualSectors,
  403. ( ULONG )( 0xfff8L * CvfHeader->Bpb.SectorsPerCluster ) );
  404. MaximumSectors = (CvfHeader->CvfMaximumCapacity * 1024L * 1024L) /
  405. CvfHeader->Bpb.BytesPerSector;
  406. VirtualSectors = min( VirtualSectors, MaximumSectors );
  407. // To avoid problems with DOS, do not create a volume with
  408. // a number-of-clusters value in the range [0xFEF, 0xFF7].
  409. //
  410. VirtualClusters = VirtualSectors / CvfHeader->Bpb.SectorsPerCluster;
  411. if( VirtualClusters >= 0xFEF && VirtualClusters <= 0xFF7 ) {
  412. VirtualSectors = 0xFEEL * CvfHeader->Bpb.SectorsPerCluster;
  413. }
  414. return VirtualSectors;
  415. }
  416. NTSTATUS
  417. SpDoubleSpaceFormat(
  418. IN PDISK_REGION Region
  419. )
  420. /*++
  421. Routine Description:
  422. This routine does a DoubleSpace format on the given partition.
  423. The caller should have cleared the screen and displayed
  424. any message in the upper portion; this routine will
  425. maintain the gas gauge in the lower portion of the screen.
  426. Arguments:
  427. Region - supplies the disk region descriptor for the
  428. partition to be formatted.
  429. Return Value:
  430. --*/
  431. {
  432. WCHAR CvfFileName[ 512 ];
  433. NTSTATUS Status;
  434. PUCHAR BaseAddress;
  435. ULONG BytesPerSector;
  436. PHARD_DISK pHardDisk;
  437. ULONG MaximumCapacity;
  438. CVF_HEADER CvfHeader;
  439. ULONG BitFatSize;
  440. ULONG MdFatSize;
  441. ULONG Reserved2Size;
  442. ULONG SuperAreaSize;
  443. UCHAR SystemId;
  444. ULONG max_sec_per_sa;
  445. ULONG FatSize;
  446. ULONG RootDirectorySize;
  447. ASSERT(Region->Filesystem == FilesystemDoubleSpace);
  448. // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Entering SpFormatDoubleSpace() \n") );
  449. SpNtNameFromRegion(
  450. Region,
  451. CvfFileName,
  452. sizeof(CvfFileName),
  453. PartitionOrdinalCurrent
  454. );
  455. CvfFileName[ wcslen( CvfFileName ) - (3+1+8+1) ] = ( WCHAR )'\\';
  456. //
  457. // Change the CVF file attribute to NORMAL
  458. //
  459. Status = SpChangeFileAttribute( CvfFileName, FILE_ATTRIBUTE_NORMAL );
  460. if( !NT_SUCCESS( Status ) ) {
  461. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to change attribute of %ls \n", CvfFileName ) );
  462. return( Status );
  463. }
  464. // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: CvfFileName = %ls \n", CvfFileName ) );
  465. Status = SpMapCvfFileInMemory( CvfFileName );
  466. if( !NT_SUCCESS( Status ) ) {
  467. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to map CVF file in memory \n" ) );
  468. SpChangeFileAttribute( CvfFileName,
  469. FILE_ATTRIBUTE_READONLY |
  470. FILE_ATTRIBUTE_HIDDEN |
  471. FILE_ATTRIBUTE_SYSTEM );
  472. return( Status );
  473. }
  474. // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: CVF file is mapped in memory \n" ) );
  475. //
  476. // Compute the maximum capacity of the compressed drive.
  477. // The capacity of the compressed drive is based on the
  478. // size of the host size.
  479. //
  480. // Note that MaximumCapacity is rounded up to the next
  481. // highest multiple of 8 Meg.
  482. //
  483. pHardDisk = &HardDisks[Region->HostRegion->DiskNumber];
  484. BytesPerSector = pHardDisk->Geometry.BytesPerSector;
  485. MaximumCapacity = ComputeMaximumCapacity( Region->HostRegion->SectorCount * BytesPerSector );
  486. MaximumCapacity = ( ( MaximumCapacity + EIGHT_MEG - 1 ) / EIGHT_MEG ) * EIGHT_MEG;
  487. // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: MaximumCapacity = %x\n", MaximumCapacity ));
  488. //
  489. // Create the Compressed Volume File Header:
  490. //
  491. CreateCvfHeader( &CvfHeader, MaximumCapacity );
  492. //
  493. // Now fill in the value of Virtual Sectors.
  494. //
  495. CvfHeader.Bpb.LargeSectors = ComputeVirtualSectors( &CvfHeader, _ViewSize );
  496. if( CvfHeader.Bpb.LargeSectors >= ( ULONG )( MIN_CLUS_BIG*DoubleSpaceSectorsPerCluster ) ) {
  497. CvfHeader.Is12BitFat = ( UCHAR )0;
  498. }
  499. BaseAddress = ( PUCHAR )_FileBaseAddress;
  500. memset( BaseAddress, 0, BytesPerSector );
  501. //
  502. // Write the CVF Header
  503. //
  504. CvfPackCvfHeader( ( PPACKED_CVF_HEADER )_FileBaseAddress, &CvfHeader );
  505. #if 0
  506. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: CalculatedMaximumCapacity = %x, MaximumCapacity = %x \n",
  507. (USHORT)CvfHeader.CvfMaximumCapacity,
  508. *((PUSHORT)((ULONG)_FileBaseAddress + 62))
  509. ) );
  510. #endif
  511. //
  512. // Initialize the BitFAT area
  513. //
  514. BaseAddress += BytesPerSector;
  515. BitFatSize = MaximumCapacity / ( BytesPerSector*8 );
  516. memset( BaseAddress, 0, BitFatSize );
  517. // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: BitFAT address = %x, BitFAT size = %x\n", BaseAddress, BitFatSize ));
  518. //
  519. // Initialize the 1st reserved area (Reserved1)
  520. //
  521. BaseAddress += BitFatSize;
  522. memset( BaseAddress, 0, BytesPerSector );
  523. // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Reserved1 address = %x, Reserved1 size = %x\n", BaseAddress, BytesPerSector ));
  524. //
  525. // Initialize MDFAT
  526. //
  527. BaseAddress += BytesPerSector;
  528. MdFatSize = 4*( MaximumCapacity/( BytesPerSector*CvfHeader.Bpb.SectorsPerCluster ) );
  529. memset( BaseAddress, 0, MdFatSize );
  530. // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: MDFAT address = %x, MDFAT size = %x\n", BaseAddress, MdFatSize ));
  531. //
  532. // Initialize the 2nd reserved area (Reserved2)
  533. //
  534. BaseAddress += MdFatSize;
  535. Reserved2Size = DoubleSpaceReservedSectors2*BytesPerSector;
  536. memset( BaseAddress, 0, Reserved2Size );
  537. // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Reserved2 address = %x, Reserved2 size = %x\n", BaseAddress, Reserved2Size ));
  538. //
  539. // Initialize Boot Sector
  540. //
  541. max_sec_per_sa = 1 +
  542. 2*((2*65536 - 1)/BytesPerSector + 1) +
  543. ((512*32 - 1)/BytesPerSector + 1);
  544. BaseAddress += Reserved2Size;
  545. FmtFillFormatBuffer( ( ULONG )CvfHeader.Bpb.LargeSectors,
  546. ( ULONG )( ( USHORT )CvfHeader.Bpb.BytesPerSector ),
  547. ( ULONG )( ( USHORT )CvfHeader.Bpb.SectorsPerTrack ),
  548. ( ULONG )( ( USHORT )CvfHeader.Bpb.Heads ),
  549. ( ULONG )CvfHeader.Bpb.HiddenSectors,
  550. BaseAddress,
  551. max_sec_per_sa,
  552. &SuperAreaSize,
  553. NULL,
  554. 0,
  555. &SystemId );
  556. //
  557. // Initialize the 3rd reserved area (Reserved3)
  558. //
  559. BaseAddress += BytesPerSector;
  560. memcpy( BaseAddress, FirstDbSignature, DbSignatureLength );
  561. //
  562. // Initialize the FAT area
  563. //
  564. BaseAddress += ( ( ULONG )CvfHeader.Bpb.ReservedSectors - 1 )*BytesPerSector;;
  565. FatSize = ( ULONG )CvfHeader.Bpb.SectorsPerFat * BytesPerSector;
  566. memset( BaseAddress, 0, FatSize );
  567. *BaseAddress = 0xF8;
  568. *( BaseAddress + 1 ) = 0xFF;
  569. *( BaseAddress + 2 ) = 0xFF;
  570. if( CvfHeader.Is12BitFat == 0 ) {
  571. *( BaseAddress + 3 ) = 0xFF;
  572. }
  573. // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: FAT address = %x, Fat size = %x\n", BaseAddress, FatSize ));
  574. //
  575. // Initialize the Root Directory area
  576. //
  577. BaseAddress += FatSize;
  578. RootDirectorySize = DoubleSpaceSectorsInRootDir*BytesPerSector;
  579. memset( BaseAddress, 0, RootDirectorySize );
  580. // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: RootDirectory address = %x, RootDirectory size = %x\n", BaseAddress, RootDirectorySize ));
  581. //
  582. // Initialization of the 4th reserved area (Reserved4) is not necessary
  583. //
  584. //
  585. // Initialization of the sector heap is not necessary
  586. //
  587. //
  588. // Initialize the 2nd stamp
  589. //
  590. BaseAddress = ( PUCHAR )(( ULONG )_FileBaseAddress + _ViewSize - BytesPerSector);
  591. memset( BaseAddress, 0, BytesPerSector );
  592. memcpy( BaseAddress, SecondDbSignature, DbSignatureLength );
  593. // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SecondStamp address = %x, SecondStamp size = %x\n", BaseAddress, BytesPerSector ));
  594. // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: _FileBaseAddress = %lx, _ViewSize = %lx\n", _FileBaseAddress, _ViewSize ) );
  595. SpUnmapCvfFileFromMemory( TRUE );
  596. SpChangeFileAttribute( CvfFileName,
  597. FILE_ATTRIBUTE_READONLY |
  598. FILE_ATTRIBUTE_HIDDEN |
  599. FILE_ATTRIBUTE_SYSTEM );
  600. return( Status );
  601. }