Windows NT 4.0 source code leak
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.

491 lines
13 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. fat_rec.c
  5. Abstract:
  6. This module contains the mini-file system recognizer for FAT.
  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 "fat_rec.h"
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text(PAGE,FatRecFsControl)
  17. #pragma alloc_text(PAGE,IsFatVolume)
  18. #pragma alloc_text(PAGE,FatReadBlock)
  19. #pragma alloc_text(PAGE,UnpackBiosParameterBlock)
  20. #endif // ALLOC_PRAGMA
  21. NTSTATUS
  22. FatRecFsControl(
  23. IN PDEVICE_OBJECT DeviceObject,
  24. IN PIRP Irp
  25. )
  26. /*++
  27. Routine Description:
  28. This function performs the mount and driver reload functions for this mini-
  29. file system recognizer driver.
  30. Arguments:
  31. DeviceObject - Pointer to this driver's device object.
  32. Irp - Pointer to the I/O Request Packet (IRP) representing the function to
  33. be performed.
  34. Return Value:
  35. The function value is the final status of the operation.
  36. --*/
  37. {
  38. NTSTATUS status;
  39. PIO_STACK_LOCATION irpSp;
  40. PDEVICE_EXTENSION deviceExtension;
  41. PDEVICE_OBJECT targetDevice;
  42. PPACKED_BOOT_SECTOR buffer;
  43. LARGE_INTEGER byteOffset;
  44. UNICODE_STRING driverName;
  45. NTSTATUS extStatus;
  46. PAGED_CODE();
  47. //
  48. // Begin by determining what function that is to be performed.
  49. //
  50. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  51. irpSp = IoGetCurrentIrpStackLocation( Irp );
  52. switch ( irpSp->MinorFunction ) {
  53. case IRP_MN_MOUNT_VOLUME:
  54. //
  55. // Attempt to mount a volume: Determine whether or not the volume in
  56. // question is a FAT volume and, if so, let the I/O system know that it
  57. // is by returning a special status code so that this driver can get
  58. // called back to load the FAT file system.
  59. //
  60. //
  61. // Begin by making a special case test to determine whether or not this
  62. // driver has ever recognized a volume as being a FAT volume and the
  63. // attempt to load the driver failed. If so, then simply complete the
  64. // request with an error, indicating that the volume is not recognized
  65. // so that it gets mounted by the RAW file system.
  66. //
  67. status = STATUS_UNRECOGNIZED_VOLUME;
  68. if (deviceExtension->RealFsLoadFailed || irpSp->Flags) {
  69. break;
  70. }
  71. //
  72. // Attempt to determine whether or not the target volume being mounted
  73. // is a FAT volume. Note that if an error occurs, and this is a floppy
  74. // drive, and the error occurred on the actual read from the device,
  75. // then the FAT file system will actually be loaded to handle the
  76. // problem since this driver is a place holder and does not need to
  77. // know all of the protocols for handling floppy errors.
  78. //
  79. targetDevice = irpSp->Parameters.MountVolume.DeviceObject;
  80. byteOffset.QuadPart = 0;
  81. if (FatReadBlock( targetDevice, &byteOffset, 512, &extStatus, &buffer )) {
  82. if (IsFatVolume( buffer )) {
  83. status = STATUS_FS_DRIVER_REQUIRED;
  84. }
  85. ExFreePool( buffer );
  86. } else {
  87. if (!NT_SUCCESS( extStatus )) {
  88. if (targetDevice->Characteristics & FILE_FLOPPY_DISKETTE) {
  89. status = STATUS_FS_DRIVER_REQUIRED;
  90. }
  91. }
  92. }
  93. break;
  94. case IRP_MN_LOAD_FILE_SYSTEM:
  95. //
  96. // Attempt to load the FAT file system: A volume has been found that
  97. // appears to be a FAT volume, so attempt to load the FAT file system.
  98. // If it successfully loads, then
  99. //
  100. RtlInitUnicodeString( &driverName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Fastfat" );
  101. status = ZwLoadDriver( &driverName );
  102. if (!NT_SUCCESS( status )) {
  103. if (status != STATUS_IMAGE_ALREADY_LOADED) {
  104. deviceExtension->RealFsLoadFailed = TRUE;
  105. }
  106. } else {
  107. IoUnregisterFileSystem( DeviceObject );
  108. }
  109. break;
  110. default:
  111. status = STATUS_INVALID_DEVICE_REQUEST;
  112. }
  113. //
  114. // Finally, complete the request and return the same status code to the
  115. // caller.
  116. //
  117. Irp->IoStatus.Status = status;
  118. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  119. return status;
  120. }
  121. BOOLEAN
  122. IsFatVolume(
  123. IN PPACKED_BOOT_SECTOR Buffer
  124. )
  125. /*++
  126. Routine Description:
  127. This routine looks at the buffer passed in which contains the FAT boot
  128. sector and determines whether or not it represents an actual FAT boot
  129. sector.
  130. Arguments:
  131. Buffer - Pointer to buffer containing potential boot block.
  132. Return Value:
  133. The function returns TRUE if the buffer contains a recognizable FAT boot
  134. sector, otherwise it returns FALSE.
  135. --*/
  136. {
  137. BIOS_PARAMETER_BLOCK bios;
  138. BOOLEAN result;
  139. PAGED_CODE();
  140. //
  141. // Begin by unpacking the Bios Parameter Block that is packed in the boot
  142. // sector so that it can be examined without incurring alignment faults.
  143. //
  144. UnpackBiosParameterBlock( &Buffer->PackedBpb, &bios );
  145. //
  146. // Assume that the sector represents a FAT boot block and then determine
  147. // whether or not it really does.
  148. //
  149. result = TRUE;
  150. if (bios.Sectors) {
  151. bios.LargeSectors = 0;
  152. }
  153. // FMR Jul.11.1994 NaokiM - Fujitsu -
  154. // FMR boot sector has 'IPL1' string at the beginnig.
  155. if (Buffer->Jump[0] != 0x49 && /* FMR */
  156. Buffer->Jump[0] != 0xe9 &&
  157. Buffer->Jump[0] != 0xeb) {
  158. result = FALSE;
  159. // FMR Jul.11.1994 NaokiM - Fujitsu -
  160. // Sector size of FMR partition is 2048.
  161. } else if (bios.BytesPerSector != 128 &&
  162. bios.BytesPerSector != 256 &&
  163. bios.BytesPerSector != 512 &&
  164. bios.BytesPerSector != 1024 &&
  165. bios.BytesPerSector != 2048 && /* FMR */
  166. bios.BytesPerSector != 4096) {
  167. result = FALSE;
  168. } else if (bios.SectorsPerCluster != 1 &&
  169. bios.SectorsPerCluster != 2 &&
  170. bios.SectorsPerCluster != 4 &&
  171. bios.SectorsPerCluster != 8 &&
  172. bios.SectorsPerCluster != 16 &&
  173. bios.SectorsPerCluster != 32 &&
  174. bios.SectorsPerCluster != 64 &&
  175. bios.SectorsPerCluster != 128) {
  176. result = FALSE;
  177. } else if (!bios.ReservedSectors) {
  178. result = FALSE;
  179. } else if (!bios.Fats) {
  180. result = FALSE;
  181. } else if (!bios.RootEntries) {
  182. result = FALSE;
  183. //
  184. // Prior to DOS 3.2 might contains value in both of Sectors and
  185. // Sectors Large.
  186. //
  187. } else if (!bios.Sectors && !bios.LargeSectors) {
  188. result = FALSE;
  189. } else if (!bios.SectorsPerFat) {
  190. result = FALSE;
  191. // FMR Jul.11.1994 NaokiM - Fujitsu -
  192. // 1. Media descriptor of FMR partitions is 0xfa.
  193. // 2. Media descriptor of partitions formated by FMR OS/2 is 0x00.
  194. // 3. Media descriptor of floppy disks formated by FMR DOS is 0x01.
  195. } else if (bios.Media != 0x00 && /* FMR */
  196. bios.Media != 0x01 && /* FMR */
  197. bios.Media != 0xf0 &&
  198. bios.Media != 0xf8 &&
  199. bios.Media != 0xf9 &&
  200. bios.Media != 0xfa && /* FMR */
  201. bios.Media != 0xfb &&
  202. bios.Media != 0xfc &&
  203. bios.Media != 0xfd &&
  204. bios.Media != 0xfe &&
  205. bios.Media != 0xff) {
  206. result = FALSE;
  207. }
  208. return result;
  209. }
  210. BOOLEAN
  211. FatReadBlock(
  212. IN PDEVICE_OBJECT DeviceObject,
  213. IN PLARGE_INTEGER ByteOffset,
  214. IN ULONG MinimumBytes,
  215. OUT PNTSTATUS ExtendedStatus,
  216. OUT PPACKED_BOOT_SECTOR *Buffer
  217. )
  218. /*++
  219. Routine Description:
  220. This routine reads a minimum numbers of bytes into a buffer starting at
  221. the byte offset from the base of the device represented by the device
  222. object.
  223. Arguments:
  224. DeviceObject - Pointer to the device object from which to read.
  225. ByteOffset - Pointer to a 64-bit byte offset from the base of the device
  226. from which to start the read.
  227. MinimumBytes - Supplies the minimum number of bytes to be read.
  228. ExtendedStatus - Variable to receive extended status information about
  229. any I/O errors that occurred.
  230. Buffer - Variable to receive a pointer to the allocated buffer containing
  231. the bytes read.
  232. Return Value:
  233. The function value is TRUE if the bytes were read, otherwise FALSE.
  234. --*/
  235. {
  236. #define RoundUp( x, y ) ( ((x + (y-1)) / y) * y )
  237. DISK_GEOMETRY diskGeometry;
  238. IO_STATUS_BLOCK ioStatus;
  239. KEVENT event;
  240. PIRP irp;
  241. NTSTATUS status;
  242. PAGED_CODE();
  243. //
  244. // Begin by getting the disk geometry so that the number of bytes required
  245. // for a single read can be determined.
  246. //
  247. *ExtendedStatus = STATUS_SUCCESS;
  248. KeInitializeEvent( &event, SynchronizationEvent, FALSE );
  249. irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_GET_DRIVE_GEOMETRY,
  250. DeviceObject,
  251. (PVOID) NULL,
  252. 0,
  253. &diskGeometry,
  254. sizeof( diskGeometry ),
  255. FALSE,
  256. &event,
  257. &ioStatus );
  258. if (!irp) {
  259. return FALSE;
  260. }
  261. status = IoCallDriver( DeviceObject, irp );
  262. if (status == STATUS_PENDING) {
  263. (VOID) KeWaitForSingleObject( &event,
  264. Executive,
  265. KernelMode,
  266. FALSE,
  267. (PLARGE_INTEGER) NULL );
  268. status = ioStatus.Status;
  269. }
  270. if (!NT_SUCCESS( status )) {
  271. *ExtendedStatus = status;
  272. return FALSE;
  273. }
  274. //
  275. // Ensure that the drive actually knows how many bytes there are per
  276. // sector. Floppy drives do not know if the media is unformatted.
  277. //
  278. if (!diskGeometry.BytesPerSector) {
  279. return FALSE;
  280. }
  281. //
  282. // Set the minimum number of bytes to read to the maximum of the bytes that
  283. // the caller wants to read, and the number of bytes in a sector.
  284. //
  285. if (MinimumBytes < diskGeometry.BytesPerSector) {
  286. MinimumBytes = diskGeometry.BytesPerSector;
  287. } else {
  288. MinimumBytes = RoundUp( MinimumBytes, diskGeometry.BytesPerSector );
  289. }
  290. //
  291. // Allocate a buffer large enough to contain the bytes required, round the
  292. // request to a page boundary to solve any alignment requirements.
  293. //
  294. *Buffer = ExAllocatePool( NonPagedPool,
  295. (MinimumBytes + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1) );
  296. if (!*Buffer) {
  297. return FALSE;
  298. }
  299. //
  300. // Read the actual bytes off of the disk.
  301. //
  302. KeResetEvent( &event );
  303. irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ,
  304. DeviceObject,
  305. *Buffer,
  306. MinimumBytes,
  307. ByteOffset,
  308. &event,
  309. &ioStatus );
  310. if (!irp) {
  311. return FALSE;
  312. }
  313. status = IoCallDriver( DeviceObject, irp );
  314. if (status == STATUS_PENDING) {
  315. (VOID) KeWaitForSingleObject( &event,
  316. Executive,
  317. KernelMode,
  318. FALSE,
  319. (PLARGE_INTEGER) NULL );
  320. status = ioStatus.Status;
  321. }
  322. if (!NT_SUCCESS( status )) {
  323. *ExtendedStatus = status;
  324. ExFreePool( *Buffer );
  325. return FALSE;
  326. }
  327. return TRUE;
  328. }
  329. VOID
  330. UnpackBiosParameterBlock(
  331. IN PPACKED_BIOS_PARAMETER_BLOCK Bios,
  332. OUT PBIOS_PARAMETER_BLOCK UnpackedBios
  333. )
  334. /*++
  335. Routine Description:
  336. This routine copies a packed Bios Parameter Block to an unpacked Bios
  337. Parameter Block.
  338. Arguments:
  339. Bios - Pointer to the packed Bios Parameter Block.
  340. UnpackedBios - Pointer to the unpacked Bios Parameter Block.
  341. Return Value:
  342. None.
  343. --*/
  344. {
  345. PAGED_CODE();
  346. //
  347. // Unpack the Bios Parameter Block.
  348. //
  349. CopyUchar2( &UnpackedBios->BytesPerSector, &Bios->BytesPerSector[0] );
  350. CopyUchar2( &UnpackedBios->BytesPerSector, &Bios->BytesPerSector[0] );
  351. CopyUchar1( &UnpackedBios->SectorsPerCluster, &Bios->SectorsPerCluster[0] );
  352. CopyUchar2( &UnpackedBios->ReservedSectors, &Bios->ReservedSectors[0] );
  353. CopyUchar1( &UnpackedBios->Fats, &Bios->Fats[0] );
  354. CopyUchar2( &UnpackedBios->RootEntries, &Bios->RootEntries[0] );
  355. CopyUchar2( &UnpackedBios->Sectors, &Bios->Sectors[0] );
  356. CopyUchar1( &UnpackedBios->Media, &Bios->Media[0] );
  357. CopyUchar2( &UnpackedBios->SectorsPerFat, &Bios->SectorsPerFat[0] );
  358. CopyUchar2( &UnpackedBios->SectorsPerTrack, &Bios->SectorsPerTrack[0] );
  359. CopyUchar2( &UnpackedBios->Heads, &Bios->Heads[0] );
  360. CopyUchar4( &UnpackedBios->HiddenSectors, &Bios->HiddenSectors[0] );
  361. CopyUchar4( &UnpackedBios->LargeSectors, &Bios->LargeSectors[0] );
  362. }