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.

360 lines
10 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. ntfs_rec.c
  5. Abstract:
  6. This module contains the mini-file system recognizer for NTFS.
  7. Author:
  8. Darryl E. Havens (darrylh) 8-dec-1992
  9. Environment:
  10. Kernel mode, local to I/O system
  11. Revision History:
  12. --*/
  13. #include "fs_rec.h"
  14. #include "ntfs_rec.h"
  15. //
  16. // The local debug trace level
  17. //
  18. #define Dbg (FSREC_DEBUG_LEVEL_NTFS)
  19. #ifdef ALLOC_PRAGMA
  20. #pragma alloc_text(PAGE,NtfsRecFsControl)
  21. #pragma alloc_text(PAGE,IsNtfsVolume)
  22. #endif // ALLOC_PRAGMA
  23. NTSTATUS
  24. NtfsRecFsControl(
  25. IN PDEVICE_OBJECT DeviceObject,
  26. IN PIRP Irp
  27. )
  28. /*++
  29. Routine Description:
  30. This function performs the mount and driver reload functions for this mini-
  31. file system recognizer driver.
  32. Arguments:
  33. DeviceObject - Pointer to this driver's device object.
  34. Irp - Pointer to the I/O Request Packet (IRP) representing the function to
  35. be performed.
  36. Return Value:
  37. The function value is the final status of the operation.
  38. --*/
  39. {
  40. NTSTATUS status;
  41. PIO_STACK_LOCATION irpSp;
  42. PDEVICE_EXTENSION deviceExtension;
  43. PDEVICE_OBJECT targetDevice;
  44. PPACKED_BOOT_SECTOR buffer;
  45. LARGE_INTEGER byteOffset;
  46. LARGE_INTEGER secondByteOffset;
  47. LARGE_INTEGER lastByteOffset;
  48. UNICODE_STRING driverName;
  49. ULONG bytesPerSector;
  50. LARGE_INTEGER numberOfSectors;
  51. PAGED_CODE();
  52. //
  53. // Begin by determining what function that is to be performed.
  54. //
  55. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  56. irpSp = IoGetCurrentIrpStackLocation( Irp );
  57. switch ( irpSp->MinorFunction ) {
  58. case IRP_MN_MOUNT_VOLUME:
  59. //
  60. // Attempt to mount a volume: Determine whether or not the volume in
  61. // question is an NTFS volume and, if so, let the I/O system know that it
  62. // is by returning a special status code so that this driver can get
  63. // called back to load the NTFS file system.
  64. //
  65. status = STATUS_UNRECOGNIZED_VOLUME;
  66. //
  67. // Attempt to determine whether or not the target volume being mounted
  68. // is an NTFS volume.
  69. //
  70. targetDevice = irpSp->Parameters.MountVolume.DeviceObject;
  71. if (FsRecGetDeviceSectorSize( targetDevice,
  72. &bytesPerSector ) &&
  73. FsRecGetDeviceSectors( targetDevice,
  74. bytesPerSector,
  75. &numberOfSectors )) {
  76. byteOffset.QuadPart = 0;
  77. buffer = NULL;
  78. secondByteOffset.QuadPart = numberOfSectors.QuadPart >> 1;
  79. secondByteOffset.QuadPart *= (LONG) bytesPerSector;
  80. lastByteOffset.QuadPart = (numberOfSectors.QuadPart - 1) * (LONG) bytesPerSector;
  81. if (FsRecReadBlock( targetDevice,
  82. &byteOffset,
  83. sizeof( PACKED_BOOT_SECTOR ),
  84. bytesPerSector,
  85. (PVOID *)&buffer,
  86. NULL ))
  87. {
  88. if (IsNtfsVolume( buffer, bytesPerSector, &numberOfSectors )) {
  89. status = STATUS_FS_DRIVER_REQUIRED;
  90. }
  91. } else {
  92. if (FsRecReadBlock( targetDevice,
  93. &secondByteOffset,
  94. sizeof( PACKED_BOOT_SECTOR ),
  95. bytesPerSector,
  96. (PVOID *)&buffer,
  97. NULL ) &&
  98. IsNtfsVolume( buffer, bytesPerSector, &numberOfSectors )) {
  99. status = STATUS_FS_DRIVER_REQUIRED;
  100. } else {
  101. if (FsRecReadBlock( targetDevice,
  102. &lastByteOffset,
  103. sizeof( PACKED_BOOT_SECTOR ),
  104. bytesPerSector,
  105. (PVOID *)&buffer,
  106. NULL ) &&
  107. IsNtfsVolume( buffer, bytesPerSector, &numberOfSectors )) {
  108. status = STATUS_FS_DRIVER_REQUIRED;
  109. }
  110. }
  111. }
  112. if (buffer != NULL) {
  113. ExFreePool( buffer );
  114. }
  115. }
  116. break;
  117. case IRP_MN_LOAD_FILE_SYSTEM:
  118. status = FsRecLoadFileSystem( DeviceObject,
  119. L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Ntfs" );
  120. break;
  121. default:
  122. status = STATUS_INVALID_DEVICE_REQUEST;
  123. }
  124. //
  125. // Finally, complete the request and return the same status code to the
  126. // caller.
  127. //
  128. Irp->IoStatus.Status = status;
  129. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  130. return status;
  131. }
  132. BOOLEAN
  133. IsNtfsVolume(
  134. IN PPACKED_BOOT_SECTOR BootSector,
  135. IN ULONG BytesPerSector,
  136. IN PLARGE_INTEGER NumberOfSectors
  137. )
  138. /*++
  139. Routine Description:
  140. This routine looks at the buffer passed in which contains the NTFS boot
  141. sector and determines whether or not it represents an NTFS volume.
  142. Arguments:
  143. BootSector - Pointer to buffer containing a potential NTFS boot sector.
  144. BytesPerSector - Supplies the number of bytes per sector for the drive.
  145. NumberOfSectors - Supplies the number of sectors on the partition.
  146. Return Value:
  147. The function returns TRUE if the buffer contains a recognizable NTFS boot
  148. sector, otherwise it returns FALSE.
  149. --*/
  150. {
  151. PAGED_CODE();
  152. //
  153. // Now perform all the checks, starting with the Name and Checksum.
  154. // The remaining checks should be obvious, including some fields which
  155. // must be 0 and other fields which must be a small power of 2.
  156. //
  157. if (BootSector->Oem[0] == 'N' &&
  158. BootSector->Oem[1] == 'T' &&
  159. BootSector->Oem[2] == 'F' &&
  160. BootSector->Oem[3] == 'S' &&
  161. BootSector->Oem[4] == ' ' &&
  162. BootSector->Oem[5] == ' ' &&
  163. BootSector->Oem[6] == ' ' &&
  164. BootSector->Oem[7] == ' '
  165. &&
  166. //
  167. // Check number of bytes per sector. The low order byte of this
  168. // number must be zero (smallest sector size = 0x100) and the
  169. // high order byte shifted must equal the bytes per sector gotten
  170. // from the device and stored in the Vcb. And just to be sure,
  171. // sector size must be less than page size.
  172. //
  173. BootSector->PackedBpb.BytesPerSector[0] == 0
  174. &&
  175. ((ULONG) (BootSector->PackedBpb.BytesPerSector[1] << 8) == BytesPerSector)
  176. &&
  177. BootSector->PackedBpb.BytesPerSector[1] << 8 <= PAGE_SIZE
  178. &&
  179. //
  180. // Sectors per cluster must be a power of 2.
  181. //
  182. (BootSector->PackedBpb.SectorsPerCluster[0] == 0x1 ||
  183. BootSector->PackedBpb.SectorsPerCluster[0] == 0x2 ||
  184. BootSector->PackedBpb.SectorsPerCluster[0] == 0x4 ||
  185. BootSector->PackedBpb.SectorsPerCluster[0] == 0x8 ||
  186. BootSector->PackedBpb.SectorsPerCluster[0] == 0x10 ||
  187. BootSector->PackedBpb.SectorsPerCluster[0] == 0x20 ||
  188. BootSector->PackedBpb.SectorsPerCluster[0] == 0x40 ||
  189. BootSector->PackedBpb.SectorsPerCluster[0] == 0x80)
  190. &&
  191. //
  192. // These fields must all be zero. For both Fat and HPFS, some of
  193. // these fields must be nonzero.
  194. //
  195. BootSector->PackedBpb.ReservedSectors[0] == 0 &&
  196. BootSector->PackedBpb.ReservedSectors[1] == 0 &&
  197. BootSector->PackedBpb.Fats[0] == 0 &&
  198. BootSector->PackedBpb.RootEntries[0] == 0 &&
  199. BootSector->PackedBpb.RootEntries[1] == 0 &&
  200. BootSector->PackedBpb.Sectors[0] == 0 &&
  201. BootSector->PackedBpb.Sectors[1] == 0 &&
  202. BootSector->PackedBpb.SectorsPerFat[0] == 0 &&
  203. BootSector->PackedBpb.SectorsPerFat[1] == 0 &&
  204. BootSector->PackedBpb.LargeSectors[0] == 0 &&
  205. BootSector->PackedBpb.LargeSectors[1] == 0 &&
  206. BootSector->PackedBpb.LargeSectors[2] == 0 &&
  207. BootSector->PackedBpb.LargeSectors[3] == 0
  208. &&
  209. //
  210. // Number of Sectors cannot be greater than the number of sectors
  211. // on the partition.
  212. //
  213. !( BootSector->NumberSectors.QuadPart > NumberOfSectors->QuadPart )
  214. &&
  215. //
  216. // Check that both Lcn values are for sectors within the partition.
  217. //
  218. !( BootSector->MftStartLcn.QuadPart *
  219. BootSector->PackedBpb.SectorsPerCluster[0] >
  220. NumberOfSectors->QuadPart )
  221. &&
  222. !( BootSector->Mft2StartLcn.QuadPart *
  223. BootSector->PackedBpb.SectorsPerCluster[0] >
  224. NumberOfSectors->QuadPart )
  225. &&
  226. //
  227. // Clusters per file record segment and default clusters for Index
  228. // Allocation Buffers must be a power of 2. A negative number indicates
  229. // a shift value to get the actual size of the structure.
  230. //
  231. ((BootSector->ClustersPerFileRecordSegment >= -31 &&
  232. BootSector->ClustersPerFileRecordSegment <= -9) ||
  233. BootSector->ClustersPerFileRecordSegment == 0x1 ||
  234. BootSector->ClustersPerFileRecordSegment == 0x2 ||
  235. BootSector->ClustersPerFileRecordSegment == 0x4 ||
  236. BootSector->ClustersPerFileRecordSegment == 0x8 ||
  237. BootSector->ClustersPerFileRecordSegment == 0x10 ||
  238. BootSector->ClustersPerFileRecordSegment == 0x20 ||
  239. BootSector->ClustersPerFileRecordSegment == 0x40)
  240. &&
  241. ((BootSector->DefaultClustersPerIndexAllocationBuffer >= -31 &&
  242. BootSector->DefaultClustersPerIndexAllocationBuffer <= -9) ||
  243. BootSector->DefaultClustersPerIndexAllocationBuffer == 0x1 ||
  244. BootSector->DefaultClustersPerIndexAllocationBuffer == 0x2 ||
  245. BootSector->DefaultClustersPerIndexAllocationBuffer == 0x4 ||
  246. BootSector->DefaultClustersPerIndexAllocationBuffer == 0x8 ||
  247. BootSector->DefaultClustersPerIndexAllocationBuffer == 0x10 ||
  248. BootSector->DefaultClustersPerIndexAllocationBuffer == 0x20 ||
  249. BootSector->DefaultClustersPerIndexAllocationBuffer == 0x40)) {
  250. return TRUE;
  251. } else {
  252. //
  253. // This does not appear to be an NTFS volume.
  254. //
  255. return FALSE;
  256. }
  257. }