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.

2868 lines
80 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. ioctl.c
  5. Abstract:
  6. This file contains RAM disk driver code for processing IOCTLs.
  7. Author:
  8. Chuck Lenzmeier (ChuckL) 2001
  9. Environment:
  10. Kernel mode only.
  11. Notes:
  12. Revision History:
  13. --*/
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. #include <ntverp.h>
  17. #if !DBG
  18. #define PRINT_CODE( _code )
  19. #else
  20. #define PRINT_CODE( _code ) \
  21. if ( print ) { \
  22. DBGPRINT( DBG_IOCTL, DBG_VERBOSE, ("%s", " " #_code "\n") ); \
  23. } \
  24. print = FALSE;
  25. #endif
  26. //
  27. // Local functions.
  28. //
  29. NTSTATUS
  30. RamdiskQueryProperty (
  31. IN PDEVICE_OBJECT DeviceObject,
  32. IN OUT PIRP Irp
  33. );
  34. //
  35. // Declare pageable routines.
  36. //
  37. #ifdef ALLOC_PRAGMA
  38. #pragma alloc_text( PAGE, RamdiskDeviceControl )
  39. #pragma alloc_text( PAGE, RamdiskCreateRamDisk )
  40. #pragma alloc_text( PAGE, RamdiskCreateDiskDevice )
  41. #pragma alloc_text( PAGE, RamdiskGetDriveLayout )
  42. #pragma alloc_text( PAGE, RamdiskGetPartitionInfo )
  43. #pragma alloc_text( PAGE, RamdiskSetPartitionInfo )
  44. #pragma alloc_text( PAGE, RamdiskQueryProperty )
  45. #endif // ALLOC_PRAGMA
  46. NTSTATUS
  47. RamdiskDeviceControl (
  48. IN PDEVICE_OBJECT DeviceObject,
  49. IN PIRP Irp
  50. )
  51. /*++
  52. Routine Description:
  53. This routine is called by the I/O system to perform a device I/O
  54. control function.
  55. Arguments:
  56. DeviceObject - a pointer to the object that represents the device on which
  57. I/O is to be performed
  58. Irp - a pointer to the I/O Request Packet for this request
  59. Return Value:
  60. NTSTATUS - the status of the operation
  61. --*/
  62. {
  63. //PBIOS_PARAMETER_BLOCK bios;
  64. PCOMMON_EXTENSION commonExtension;
  65. PBUS_EXTENSION busExtension;
  66. PDISK_EXTENSION diskExtension;
  67. PIO_STACK_LOCATION irpSp;
  68. PRAMDISK_QUERY_INPUT queryInput;
  69. PRAMDISK_QUERY_OUTPUT queryOutput;
  70. PRAMDISK_MARK_FOR_DELETION_INPUT markInput;
  71. PLIST_ENTRY listEntry;
  72. NTSTATUS status;
  73. ULONG_PTR info;
  74. BOOLEAN lockHeld = FALSE;
  75. BOOLEAN calleeWillComplete = FALSE;
  76. #if DBG
  77. BOOLEAN print = TRUE;
  78. #endif
  79. PAGED_CODE();
  80. //
  81. // Set up device extension and IRP pointers.
  82. //
  83. commonExtension = DeviceObject->DeviceExtension;
  84. busExtension = DeviceObject->DeviceExtension;
  85. diskExtension = DeviceObject->DeviceExtension;
  86. irpSp = IoGetCurrentIrpStackLocation( Irp );
  87. //
  88. // ISSUE: what about BiosParameters?
  89. //
  90. //bios = &diskExtension->BiosParameters;
  91. //
  92. // Acquire the remove lock. If this fails, fail the I/O.
  93. //
  94. status = IoAcquireRemoveLock( &commonExtension->RemoveLock, Irp );
  95. if ( !NT_SUCCESS(status) ) {
  96. COMPLETE_REQUEST( status, 0, Irp );
  97. return status;
  98. }
  99. //
  100. // Indicate that the remove lock is held.
  101. //
  102. lockHeld = TRUE;
  103. //
  104. // Assume failure.
  105. //
  106. status = STATUS_INVALID_DEVICE_REQUEST;
  107. info = 0;
  108. //
  109. // Dispatch based on the device type (bus or disk).
  110. //
  111. switch ( commonExtension->DeviceType ) {
  112. case RamdiskDeviceTypeBusFdo:
  113. //
  114. // The target is the bus FDO.
  115. //
  116. // Dispatch based on the IOCTL code.
  117. //
  118. switch ( irpSp->Parameters.DeviceIoControl.IoControlCode ) {
  119. case FSCTL_CREATE_RAM_DISK:
  120. PRINT_CODE( FSCTL_DISK_CREATE_RAM_DISK );
  121. //
  122. // Creation of a RAM disk must be handled in thread context. But
  123. // before sending it off to the thread, we need to verify that
  124. // the caller has access to the backing file.
  125. //
  126. status = RamdiskCreateRamDisk( DeviceObject, Irp, TRUE );
  127. if ( NT_SUCCESS(status) ) {
  128. status = SendIrpToThread( DeviceObject, Irp );
  129. }
  130. break;
  131. case FSCTL_QUERY_RAM_DISK:
  132. PRINT_CODE( FSCTL_QUERY_RAM_DISK );
  133. //
  134. // Lock the disk PDO list and look for a disk with the specified
  135. // disk GUID.
  136. //
  137. // Verify that the input parameter buffer is big enough.
  138. //
  139. if ( irpSp->Parameters.DeviceIoControl.InputBufferLength <
  140. sizeof(RAMDISK_QUERY_INPUT) ) {
  141. status = STATUS_INVALID_PARAMETER;
  142. break;
  143. }
  144. queryInput = (PRAMDISK_QUERY_INPUT)Irp->AssociatedIrp.SystemBuffer;
  145. if ( queryInput->Version != sizeof(RAMDISK_QUERY_INPUT) ) {
  146. status = STATUS_INVALID_PARAMETER;
  147. break;
  148. }
  149. KeEnterCriticalRegion();
  150. ExAcquireFastMutex( &busExtension->Mutex );
  151. diskExtension = NULL;
  152. for ( listEntry = busExtension->DiskPdoList.Flink;
  153. listEntry != &busExtension->DiskPdoList;
  154. listEntry = listEntry->Flink ) {
  155. diskExtension = CONTAINING_RECORD( listEntry, DISK_EXTENSION, DiskPdoListEntry );
  156. if ( memcmp(
  157. &diskExtension->DiskGuid,
  158. &queryInput->DiskGuid,
  159. sizeof(diskExtension->DiskGuid)
  160. ) == 0 ) {
  161. break;
  162. }
  163. diskExtension = NULL;
  164. }
  165. if ( diskExtension == NULL ) {
  166. //
  167. // Couldn't find a matching device.
  168. //
  169. status = STATUS_NO_SUCH_DEVICE;
  170. } else {
  171. //
  172. // Found a matching device. Return the requested information.
  173. //
  174. status = STATUS_SUCCESS;
  175. info = sizeof(RAMDISK_QUERY_OUTPUT);
  176. if ( RAMDISK_IS_FILE_BACKED(diskExtension->DiskType) ) {
  177. // NB: struct size already includes space for one wchar.
  178. info += wcslen(diskExtension->FileName) * sizeof(WCHAR);
  179. }
  180. if ( irpSp->Parameters.DeviceIoControl.OutputBufferLength < info ) {
  181. status = STATUS_BUFFER_TOO_SMALL;
  182. info = 0;
  183. } else {
  184. queryOutput = (PRAMDISK_QUERY_OUTPUT)Irp->AssociatedIrp.SystemBuffer;
  185. queryOutput->Version = sizeof(RAMDISK_QUERY_OUTPUT);
  186. queryOutput->DiskGuid = diskExtension->DiskGuid;
  187. queryOutput->DiskType = diskExtension->DiskType;
  188. queryOutput->Options = diskExtension->Options;
  189. queryOutput->DiskLength = diskExtension->DiskLength;
  190. queryOutput->DiskOffset = diskExtension->DiskOffset;
  191. queryOutput->ViewCount = diskExtension->ViewCount;
  192. queryOutput->ViewLength = diskExtension->ViewLength;
  193. if ( diskExtension->DiskType == RAMDISK_TYPE_BOOT_DISK ) {
  194. queryOutput->BasePage = diskExtension->BasePage;
  195. queryOutput->DriveLetter = diskExtension->DriveLetter;
  196. } else if ( diskExtension->DiskType == RAMDISK_TYPE_VIRTUAL_FLOPPY ) {
  197. queryOutput->BaseAddress = diskExtension->BaseAddress;
  198. } else {
  199. size_t remainingLength;
  200. HRESULT result;
  201. remainingLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  202. remainingLength -= FIELD_OFFSET( RAMDISK_QUERY_OUTPUT, FileName );
  203. result = StringCbCopyW(
  204. queryOutput->FileName,
  205. remainingLength,
  206. diskExtension->FileName
  207. );
  208. ASSERT( result == S_OK );
  209. }
  210. }
  211. }
  212. ExReleaseFastMutex( &commonExtension->Mutex );
  213. KeLeaveCriticalRegion();
  214. break;
  215. case FSCTL_MARK_RAM_DISK_FOR_DELETION:
  216. PRINT_CODE( FSCTL_MARK_RAM_DISK_FOR_DELETION );
  217. //
  218. // Lock the disk PDO list and look for a disk with the specified
  219. // disk GUID.
  220. //
  221. // Verify that the input parameter buffer is big enough.
  222. //
  223. if ( irpSp->Parameters.DeviceIoControl.InputBufferLength <
  224. sizeof(RAMDISK_MARK_FOR_DELETION_INPUT) ) {
  225. status = STATUS_INVALID_PARAMETER;
  226. break;
  227. }
  228. markInput = (PRAMDISK_MARK_FOR_DELETION_INPUT)Irp->AssociatedIrp.SystemBuffer;
  229. if ( markInput->Version != sizeof(RAMDISK_MARK_FOR_DELETION_INPUT) ) {
  230. status = STATUS_INVALID_PARAMETER;
  231. break;
  232. }
  233. KeEnterCriticalRegion();
  234. ExAcquireFastMutex( &busExtension->Mutex );
  235. diskExtension = NULL;
  236. for ( listEntry = busExtension->DiskPdoList.Flink;
  237. listEntry != &busExtension->DiskPdoList;
  238. listEntry = listEntry->Flink ) {
  239. diskExtension = CONTAINING_RECORD( listEntry, DISK_EXTENSION, DiskPdoListEntry );
  240. if ( memcmp(
  241. &diskExtension->DiskGuid,
  242. &markInput->DiskGuid,
  243. sizeof(diskExtension->DiskGuid)
  244. ) == 0 ) {
  245. break;
  246. }
  247. diskExtension = NULL;
  248. }
  249. if ( diskExtension == NULL ) {
  250. //
  251. // Couldn't find a matching device.
  252. //
  253. status = STATUS_NO_SUCH_DEVICE;
  254. } else {
  255. //
  256. // Found a matching device. Mark it for deletion.
  257. //
  258. diskExtension->MarkedForDeletion = TRUE;
  259. status = STATUS_SUCCESS;
  260. }
  261. ExReleaseFastMutex( &commonExtension->Mutex );
  262. KeLeaveCriticalRegion();
  263. break;
  264. case IOCTL_STORAGE_QUERY_PROPERTY:
  265. PRINT_CODE( IOCTL_STORAGE_QUERY_PROPERTY );
  266. //
  267. // Call RamdiskQueryProperty() to handle the request. This routine
  268. // releases the lock. It also takes care of IRP completion.
  269. //
  270. status = RamdiskQueryProperty( DeviceObject, Irp );
  271. lockHeld = FALSE;
  272. calleeWillComplete = TRUE;
  273. break;
  274. default:
  275. //
  276. // The specified I/O control code is unrecognized by this driver.
  277. // The I/O status field in the IRP has already been set, so just
  278. // terminate the switch.
  279. //
  280. DBGPRINT( DBG_IOCTL, DBG_ERROR, ("Ramdisk: ERROR: unrecognized IOCTL %x\n",
  281. irpSp->Parameters.DeviceIoControl.IoControlCode) );
  282. UNRECOGNIZED_IOCTL_BREAK;
  283. break;
  284. }
  285. break;
  286. case RamdiskDeviceTypeDiskPdo:
  287. //
  288. // The target is a disk PDO.
  289. //
  290. // Dispatch based on the IOCTL code.
  291. //
  292. switch ( irpSp->Parameters.DeviceIoControl.IoControlCode ) {
  293. case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME:
  294. PRINT_CODE( IOCTL_MOUNTDEV_QUERY_DEVICE_NAME );
  295. {
  296. PMOUNTDEV_NAME mountName;
  297. ULONG outputLength;
  298. outputLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  299. //
  300. // The output buffer must be at least big enough to hold the
  301. // length of the device name.
  302. //
  303. if ( outputLength < sizeof(mountName->NameLength) ) {
  304. status = STATUS_INVALID_PARAMETER;
  305. break;
  306. }
  307. //
  308. // Write the length of the device name into the output buffer.
  309. // If the buffer is big enough, write the name, too.
  310. //
  311. mountName = Irp->AssociatedIrp.SystemBuffer;
  312. mountName->NameLength = diskExtension->DeviceName.Length;
  313. if ( outputLength < (sizeof(mountName->NameLength) + mountName->NameLength) ) {
  314. status = STATUS_BUFFER_OVERFLOW;
  315. info = sizeof(mountName->NameLength);
  316. break;
  317. }
  318. RtlCopyMemory(
  319. mountName->Name,
  320. diskExtension->DeviceName.Buffer,
  321. mountName->NameLength
  322. );
  323. status = STATUS_SUCCESS;
  324. info = sizeof(mountName->NameLength) + mountName->NameLength;
  325. }
  326. break;
  327. case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID:
  328. PRINT_CODE( IOCTL_MOUNTDEV_QUERY_UNIQUE_ID );
  329. {
  330. PMOUNTDEV_UNIQUE_ID uniqueId;
  331. ULONG outputLength;
  332. outputLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  333. //
  334. // The output buffer must be at least big enough to hold the
  335. // length of the unique ID.
  336. //
  337. if ( outputLength < sizeof(uniqueId->UniqueIdLength) ) {
  338. status = STATUS_INVALID_PARAMETER;
  339. break;
  340. }
  341. //
  342. // Write the length of the unique ID into the output buffer.
  343. // If the buffer is big enough, write the unique ID, too.
  344. //
  345. uniqueId = Irp->AssociatedIrp.SystemBuffer;
  346. uniqueId->UniqueIdLength = sizeof(diskExtension->DiskGuid);
  347. if ( outputLength <
  348. (sizeof(uniqueId->UniqueIdLength) + uniqueId->UniqueIdLength) ) {
  349. status = STATUS_BUFFER_OVERFLOW;
  350. info = sizeof(uniqueId->UniqueIdLength);
  351. break;
  352. }
  353. RtlCopyMemory(
  354. uniqueId->UniqueId,
  355. &diskExtension->DiskGuid,
  356. uniqueId->UniqueIdLength
  357. );
  358. status = STATUS_SUCCESS;
  359. info = sizeof(uniqueId->UniqueIdLength) + uniqueId->UniqueIdLength;
  360. }
  361. break;
  362. case IOCTL_MOUNTDEV_QUERY_STABLE_GUID:
  363. PRINT_CODE( IOCTL_MOUNTDEV_QUERY_STABLE_GUID );
  364. {
  365. PMOUNTDEV_STABLE_GUID stableGuid;
  366. ULONG outputLength;
  367. outputLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  368. //
  369. // The output buffer must be at big enough to hold the GUID.
  370. //
  371. if ( outputLength < sizeof(MOUNTDEV_STABLE_GUID) ) {
  372. status = STATUS_INVALID_PARAMETER;
  373. break;
  374. }
  375. //
  376. // Write the GUID to the output buffer;
  377. //
  378. stableGuid = Irp->AssociatedIrp.SystemBuffer;
  379. stableGuid->StableGuid = diskExtension->DiskGuid;
  380. status = STATUS_SUCCESS;
  381. info = sizeof(MOUNTDEV_STABLE_GUID);
  382. }
  383. break;
  384. case IOCTL_DISK_GET_MEDIA_TYPES:
  385. PRINT_CODE( IOCTL_DISK_GET_MEDIA_TYPES );
  386. // Fall through.
  387. case IOCTL_STORAGE_GET_MEDIA_TYPES:
  388. PRINT_CODE( IOCTL_STORAGE_GET_MEDIA_TYPES );
  389. // Fall through.
  390. case IOCTL_DISK_GET_DRIVE_GEOMETRY:
  391. PRINT_CODE( IOCTL_DISK_GET_DRIVE_GEOMETRY );
  392. //
  393. // Return the drive geometry for the virtual disk. Note that
  394. // we return values which were made up to suit the disk size.
  395. //
  396. if ( irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY) ) {
  397. status = STATUS_INVALID_PARAMETER;
  398. } else {
  399. PDISK_GEOMETRY outputBuffer;
  400. outputBuffer = (PDISK_GEOMETRY)Irp->AssociatedIrp.SystemBuffer;
  401. outputBuffer->MediaType = diskExtension->Options.Fixed ?
  402. FixedMedia : RemovableMedia;
  403. outputBuffer->Cylinders.QuadPart = diskExtension->NumberOfCylinders;
  404. outputBuffer->TracksPerCylinder = diskExtension->TracksPerCylinder;
  405. outputBuffer->SectorsPerTrack = diskExtension->SectorsPerTrack;
  406. outputBuffer->BytesPerSector = diskExtension->BytesPerSector;
  407. DBGPRINT( DBG_IOCTL, DBG_PAINFUL,
  408. (" MediaType = %x\n", outputBuffer->MediaType) );
  409. DBGPRINT( DBG_IOCTL, DBG_VERBOSE,
  410. (" Cylinders = %x\n", outputBuffer->Cylinders) );
  411. DBGPRINT( DBG_IOCTL, DBG_VERBOSE,
  412. (" Tracks/cyl = %x\n", outputBuffer->TracksPerCylinder) );
  413. DBGPRINT( DBG_IOCTL, DBG_VERBOSE,
  414. (" Sector/track = %x\n", outputBuffer->SectorsPerTrack) );
  415. DBGPRINT( DBG_IOCTL, DBG_VERBOSE,
  416. (" Bytes/sector = %x\n", outputBuffer->BytesPerSector) );
  417. status = STATUS_SUCCESS;
  418. info = sizeof( DISK_GEOMETRY );
  419. }
  420. break;
  421. case IOCTL_DISK_IS_WRITABLE:
  422. PRINT_CODE( IOCTL_DISK_IS_WRITABLE );
  423. //
  424. // Indicate whether the disk is write protected.
  425. //
  426. status = diskExtension->Options.Readonly ?
  427. STATUS_MEDIA_WRITE_PROTECTED : STATUS_SUCCESS;
  428. break;
  429. case IOCTL_DISK_VERIFY:
  430. PRINT_CODE( IOCTL_DISK_VERIFY );
  431. {
  432. PVERIFY_INFORMATION verifyInformation;
  433. ULONG inputLength;
  434. ULONGLONG ioOffset;
  435. ULONG ioLength;
  436. inputLength = irpSp->Parameters.DeviceIoControl.InputBufferLength;
  437. if ( inputLength < sizeof(VERIFY_INFORMATION) ) {
  438. status = STATUS_INVALID_PARAMETER;
  439. break;
  440. }
  441. verifyInformation = Irp->AssociatedIrp.SystemBuffer;
  442. ioOffset = verifyInformation->StartingOffset.QuadPart;
  443. ioLength = verifyInformation->Length;
  444. //
  445. // If the requested length is 0, we have nothing to do.
  446. // Otherwise, verify that the request is sector aligned,
  447. // doesn't wrap, and doesn't extend beyond the length of
  448. // the disk. If the request is valid, just return success.
  449. //
  450. if ( ioLength == 0 ) {
  451. status = STATUS_SUCCESS;
  452. } else if ( ((ioOffset + ioLength) < ioOffset) ||
  453. ((ioOffset | ioLength) & (diskExtension->BytesPerSector - 1)) != 0 ) {
  454. status = STATUS_INVALID_PARAMETER;
  455. } else if ( (ioOffset + ioLength) > diskExtension->DiskLength ) {
  456. status = STATUS_NONEXISTENT_SECTOR;
  457. } else {
  458. status = STATUS_SUCCESS;
  459. }
  460. }
  461. break;
  462. case IOCTL_DISK_GET_DRIVE_LAYOUT:
  463. PRINT_CODE( IOCTL_DISK_GET_DRIVE_LAYOUT );
  464. if ( irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  465. sizeof(DRIVE_LAYOUT_INFORMATION) ) {
  466. status = STATUS_INVALID_PARAMETER;
  467. } else {
  468. //
  469. // If the RAM disk is file-backed, we must send this off to
  470. // the thread for processing, because it requires reading
  471. // from the disk image.
  472. //
  473. if ( !RAMDISK_IS_FILE_BACKED(diskExtension->DiskType) ) {
  474. status = RamdiskGetDriveLayout( Irp, diskExtension );
  475. info = Irp->IoStatus.Information;
  476. } else {
  477. status = SendIrpToThread( DeviceObject, Irp );
  478. }
  479. }
  480. break;
  481. case IOCTL_DISK_GET_PARTITION_INFO:
  482. PRINT_CODE( IOCTL_DISK_GET_PARTITION_INFO );
  483. if ( irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  484. sizeof(PARTITION_INFORMATION) ) {
  485. status = STATUS_INVALID_PARAMETER;
  486. } else {
  487. //
  488. // If the RAM disk is file-backed, we must send this off to
  489. // the thread for processing, because it requires reading
  490. // from the disk image.
  491. //
  492. if ( !RAMDISK_IS_FILE_BACKED(diskExtension->DiskType) ) {
  493. status = RamdiskGetPartitionInfo( Irp, diskExtension );
  494. info = Irp->IoStatus.Information;
  495. } else {
  496. status = SendIrpToThread( DeviceObject, Irp );
  497. }
  498. }
  499. break;
  500. case IOCTL_DISK_GET_LENGTH_INFO:
  501. PRINT_CODE( IOCTL_DISK_GET_LENGTH_INFO );
  502. if ( irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  503. sizeof(GET_LENGTH_INFORMATION) ) {
  504. status = STATUS_INVALID_PARAMETER;
  505. } else {
  506. PGET_LENGTH_INFORMATION outputBuffer;
  507. outputBuffer = (PGET_LENGTH_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
  508. outputBuffer->Length.QuadPart =
  509. diskExtension->NumberOfCylinders *
  510. diskExtension->TracksPerCylinder *
  511. diskExtension->SectorsPerTrack *
  512. diskExtension->BytesPerSector;
  513. status = STATUS_SUCCESS;
  514. info = sizeof(GET_LENGTH_INFORMATION);
  515. }
  516. break;
  517. case IOCTL_STORAGE_GET_DEVICE_NUMBER:
  518. PRINT_CODE( IOCTL_STORAGE_GET_DEVICE_NUMBER );
  519. #if SUPPORT_DISK_NUMBERS
  520. if ( irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  521. sizeof(STORAGE_DEVICE_NUMBER) ) {
  522. status = STATUS_INVALID_PARAMETER;
  523. } else {
  524. PSTORAGE_DEVICE_NUMBER outputBuffer;
  525. outputBuffer = (PSTORAGE_DEVICE_NUMBER)Irp->AssociatedIrp.SystemBuffer;
  526. //outputBuffer->DeviceType = FILE_DEVICE_VIRTUAL_DISK;
  527. outputBuffer->DeviceType = FILE_DEVICE_DISK;
  528. outputBuffer->DeviceNumber = diskExtension->DiskNumber;
  529. outputBuffer->PartitionNumber = -1;
  530. status = STATUS_SUCCESS;
  531. info = sizeof(STORAGE_DEVICE_NUMBER);
  532. }
  533. #endif // SUPPORT_DISK_NUMBERS
  534. break;
  535. case IOCTL_DISK_SET_PARTITION_INFO:
  536. PRINT_CODE( IOCTL_DISK_SET_PARTITION_INFO );
  537. //
  538. // Set information about the partition.
  539. //
  540. if ( irpSp->Parameters.DeviceIoControl.InputBufferLength <
  541. sizeof(SET_PARTITION_INFORMATION) ) {
  542. status = STATUS_INVALID_PARAMETER;
  543. } else {
  544. //
  545. // If the RAM disk is file-backed, we must send this off to
  546. // the thread for processing, because it requires writing
  547. // to the disk image.
  548. //
  549. if ( !RAMDISK_IS_FILE_BACKED(diskExtension->DiskType) ) {
  550. status = RamdiskSetPartitionInfo( Irp, diskExtension );
  551. info = Irp->IoStatus.Information;
  552. } else {
  553. status = SendIrpToThread( DeviceObject, Irp );
  554. }
  555. }
  556. break;
  557. case IOCTL_DISK_SET_DRIVE_LAYOUT:
  558. PRINT_CODE( IOCTL_DISK_SET_DRIVE_LAYOUT );
  559. //
  560. // Haven't seen this one come down yet. Set a breakpoint so that
  561. // if it does come down, we can verify that this code works.
  562. //
  563. UNRECOGNIZED_IOCTL_BREAK;
  564. //
  565. // Return the default error.
  566. //
  567. break;
  568. case IOCTL_STORAGE_QUERY_PROPERTY:
  569. PRINT_CODE( IOCTL_STORAGE_QUERY_PROPERTY );
  570. //
  571. // Call RamdiskQueryProperty() to handle the request. This routine
  572. // releases the lock. It also takes care of IRP completion.
  573. //
  574. status = RamdiskQueryProperty( DeviceObject, Irp );
  575. lockHeld = FALSE;
  576. calleeWillComplete = TRUE;
  577. break;
  578. case IOCTL_VOLUME_GET_GPT_ATTRIBUTES:
  579. PRINT_CODE( IOCTL_VOLUME_GET_GPT_ATTRIBUTES );
  580. //
  581. // Return disk attributes.
  582. //
  583. if ( irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  584. sizeof(VOLUME_GET_GPT_ATTRIBUTES_INFORMATION) ) {
  585. status = STATUS_INVALID_PARAMETER;
  586. } else {
  587. PVOLUME_GET_GPT_ATTRIBUTES_INFORMATION outputBuffer;
  588. outputBuffer = (PVOLUME_GET_GPT_ATTRIBUTES_INFORMATION)
  589. Irp->AssociatedIrp.SystemBuffer;
  590. outputBuffer->GptAttributes = 0;
  591. if ( diskExtension->Options.Readonly ) {
  592. outputBuffer->GptAttributes |= GPT_BASIC_DATA_ATTRIBUTE_READ_ONLY;
  593. }
  594. if ( diskExtension->Options.NoDriveLetter ) {
  595. outputBuffer->GptAttributes |= GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER;
  596. }
  597. if ( diskExtension->Options.Hidden ) {
  598. outputBuffer->GptAttributes |= GPT_BASIC_DATA_ATTRIBUTE_HIDDEN;
  599. }
  600. status = STATUS_SUCCESS;
  601. info = sizeof(VOLUME_GET_GPT_ATTRIBUTES_INFORMATION);
  602. }
  603. break;
  604. case IOCTL_VOLUME_SET_GPT_ATTRIBUTES:
  605. PRINT_CODE( IOCTL_VOLUME_SET_GPT_ATTRIBUTES );
  606. //
  607. // Set disk attributes.
  608. //
  609. if ( irpSp->Parameters.DeviceIoControl.InputBufferLength <
  610. sizeof(VOLUME_SET_GPT_ATTRIBUTES_INFORMATION) ) {
  611. status = STATUS_INVALID_PARAMETER;
  612. } else {
  613. PVOLUME_SET_GPT_ATTRIBUTES_INFORMATION inputBuffer;
  614. inputBuffer = (PVOLUME_SET_GPT_ATTRIBUTES_INFORMATION)
  615. Irp->AssociatedIrp.SystemBuffer;
  616. if ( diskExtension->Options.Hidden ) {
  617. if ( (inputBuffer->GptAttributes & GPT_BASIC_DATA_ATTRIBUTE_HIDDEN) == 0 ) {
  618. diskExtension->Options.Hidden = FALSE;
  619. status = IoSetDeviceInterfaceState(
  620. &diskExtension->InterfaceString,
  621. TRUE
  622. );
  623. }
  624. } else {
  625. if ( (inputBuffer->GptAttributes & GPT_BASIC_DATA_ATTRIBUTE_HIDDEN) != 0 ) {
  626. diskExtension->Options.Hidden = TRUE;
  627. status = IoSetDeviceInterfaceState(
  628. &diskExtension->InterfaceString,
  629. FALSE
  630. );
  631. }
  632. }
  633. status = STATUS_SUCCESS;
  634. }
  635. break;
  636. case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS:
  637. PRINT_CODE( IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS );
  638. //
  639. // We only support this for volume-emulating RAM disks. For
  640. // disk-emulating RAM disks, this IOCTL should be handled by
  641. // higher layers.
  642. //
  643. if ( diskExtension->DiskType == RAMDISK_TYPE_FILE_BACKED_DISK ) {
  644. status = STATUS_INVALID_PARAMETER;
  645. } else if ( irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  646. sizeof(VOLUME_DISK_EXTENTS) ) {
  647. status = STATUS_BUFFER_TOO_SMALL;
  648. } else {
  649. PVOLUME_DISK_EXTENTS inputBuffer;
  650. inputBuffer = (PVOLUME_DISK_EXTENTS)Irp->AssociatedIrp.SystemBuffer;
  651. inputBuffer->NumberOfDiskExtents = 1;
  652. inputBuffer->Extents[0].DiskNumber = (ULONG)-1;
  653. inputBuffer->Extents[0].StartingOffset.QuadPart = 0;
  654. inputBuffer->Extents[0].ExtentLength.QuadPart = diskExtension->DiskLength;
  655. status = STATUS_SUCCESS;
  656. info = sizeof(VOLUME_DISK_EXTENTS);
  657. }
  658. break;
  659. //
  660. // The following codes return success without doing anything.
  661. //
  662. case IOCTL_DISK_CHECK_VERIFY:
  663. PRINT_CODE( IOCTL_DISK_CHECK_VERIFY );
  664. // Fall through.
  665. case IOCTL_STORAGE_CHECK_VERIFY:
  666. PRINT_CODE( IOCTL_STORAGE_CHECK_VERIFY );
  667. // Fall through.
  668. case IOCTL_STORAGE_CHECK_VERIFY2:
  669. PRINT_CODE( IOCTL_STORAGE_CHECK_VERIFY2 );
  670. // Fall through.
  671. case IOCTL_VOLUME_ONLINE:
  672. PRINT_CODE( IOCTL_VOLUME_ONLINE );
  673. //
  674. // Return STATUS_SUCCESS without actually doing anything.
  675. //
  676. status = STATUS_SUCCESS;
  677. break;
  678. //
  679. // The following codes return the default error.
  680. //
  681. case FT_BALANCED_READ_MODE:
  682. PRINT_CODE( FT_BALANCED_READ_MODE );
  683. // Fall through.
  684. case FT_PRIMARY_READ:
  685. PRINT_CODE( FT_PRIMARY_READ );
  686. // Fall through.
  687. case IOCTL_DISK_GET_DRIVE_LAYOUT_EX:
  688. PRINT_CODE( IOCTL_DISK_GET_DRIVE_LAYOUT_EX );
  689. // Fall through.
  690. case IOCTL_DISK_GET_PARTITION_INFO_EX:
  691. PRINT_CODE( IOCTL_DISK_GET_PARTITION_INFO_EX );
  692. // Fall through.
  693. case IOCTL_DISK_MEDIA_REMOVAL:
  694. PRINT_CODE( IOCTL_DISK_MEDIA_REMOVAL );
  695. // Fall through.
  696. case IOCTL_MOUNTDEV_LINK_CREATED:
  697. PRINT_CODE( IOCTL_MOUNTDEV_LINK_CREATED );
  698. // Fall through.
  699. case IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME:
  700. PRINT_CODE( IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME );
  701. // Fall through.
  702. case IOCTL_MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY:
  703. PRINT_CODE( IOCTL_MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY );
  704. // Fall through.
  705. case IOCTL_SCSI_GET_ADDRESS:
  706. PRINT_CODE( IOCTL_SCSI_GET_ADDRESS );
  707. // Fall through.
  708. case IOCTL_VOLSNAP_QUERY_NAMES_OF_SNAPSHOTS:
  709. PRINT_CODE( IOCTL_VOLSNAP_QUERY_NAMES_OF_SNAPSHOTS );
  710. // Fall through.
  711. case IOCTL_STORAGE_GET_HOTPLUG_INFO:
  712. PRINT_CODE( IOCTL_STORAGE_GET_HOTPLUG_INFO );
  713. //
  714. // Return the default error.
  715. //
  716. break;
  717. default:
  718. //
  719. // The specified I/O control code is unrecognized by this driver.
  720. // The I/O status field in the IRP has already been set, so just
  721. // terminate the switch.
  722. //
  723. DBGPRINT( DBG_IOCTL, DBG_ERROR, ("Ramdisk: ERROR: unrecognized IOCTL %x\n",
  724. irpSp->Parameters.DeviceIoControl.IoControlCode) );
  725. UNRECOGNIZED_IOCTL_BREAK;
  726. break;
  727. }
  728. break;
  729. default:
  730. //
  731. // Can't get here. Return the default error if the impossible occurs.
  732. //
  733. break;
  734. }
  735. //
  736. // Release the remove lock, if it's still held.
  737. //
  738. if ( lockHeld ) {
  739. IoReleaseRemoveLock( &commonExtension->RemoveLock, Irp );
  740. }
  741. //
  742. // If we didn't call another routine that owns completing the IRP, and
  743. // we didn't send the IRP off to the thread for processing, complete the
  744. // IRP now.
  745. //
  746. if ( !calleeWillComplete && (status != STATUS_PENDING) ) {
  747. COMPLETE_REQUEST( status, info, Irp );
  748. }
  749. return status;
  750. } // RamdiskDeviceControl
  751. NTSTATUS
  752. RamdiskCreateRamDisk (
  753. IN PDEVICE_OBJECT DeviceObject,
  754. IN PIRP Irp,
  755. IN BOOLEAN AccessCheckOnly
  756. )
  757. /*++
  758. Routine Description:
  759. This routine is called to handle an FSCTL_CREATE_RAM_DISK IRP. It is called
  760. in thread context.
  761. Arguments:
  762. DeviceObject - a pointer to the object that represents the device on which
  763. I/O is to be performed
  764. Irp - a pointer to the I/O Request Packet for this request
  765. AccessCheckOnly - If FALSE, create the RAM disk. Otherwise, just check
  766. whether the caller has the necessary access rights to create the disk.
  767. Return Value:
  768. NTSTATUS - the status of the operation
  769. --*/
  770. {
  771. ULONG status;
  772. PBUS_EXTENSION busExtension;
  773. PDISK_EXTENSION diskExtension;
  774. PIO_STACK_LOCATION irpSp;
  775. PRAMDISK_CREATE_INPUT createInput;
  776. ULONG inputLength;
  777. PWCHAR p;
  778. PWCHAR pMax;
  779. PLOADER_PARAMETER_BLOCK loaderBlock;
  780. PAGED_CODE();
  781. //
  782. // The target device object for the I/O is our bus FDO.
  783. //
  784. busExtension = DeviceObject->DeviceExtension;
  785. irpSp = IoGetCurrentIrpStackLocation( Irp );
  786. //
  787. // Verify that the input parameter buffer is big enough.
  788. //
  789. inputLength = irpSp->Parameters.DeviceIoControl.InputBufferLength;
  790. createInput = (PRAMDISK_CREATE_INPUT)Irp->AssociatedIrp.SystemBuffer;
  791. if ( inputLength < sizeof(RAMDISK_CREATE_INPUT) ) {
  792. return STATUS_INVALID_PARAMETER;
  793. }
  794. if ( createInput->Version != sizeof(RAMDISK_CREATE_INPUT) ) {
  795. return STATUS_INVALID_PARAMETER;
  796. }
  797. //
  798. // Verify that the disk type is valid. VIRTUAL_FLOPPY disks can only be
  799. // created via the registry, and then only during textmode setup.
  800. // A BOOT_DISK can only be created by the kernel early in the boot
  801. // process -- when the loader block still exists.
  802. //
  803. // ISSUE: If the kernel/driver interface for creating the boot disk is
  804. // changed, change this test to disallow RAMDISK_TYPE_BOOT_DISK.
  805. //
  806. if ( createInput->DiskType == RAMDISK_TYPE_VIRTUAL_FLOPPY ) {
  807. return STATUS_INVALID_PARAMETER;
  808. } else if ( createInput->DiskType == RAMDISK_TYPE_BOOT_DISK ) {
  809. loaderBlock = *(PLOADER_PARAMETER_BLOCK *)KeLoaderBlock;
  810. if ( loaderBlock == NULL ) {
  811. return STATUS_INVALID_PARAMETER;
  812. }
  813. }
  814. //
  815. // Verify that file name string (if present) is properly terminated.
  816. //
  817. if ( RAMDISK_IS_FILE_BACKED(createInput->DiskType) ) {
  818. pMax = (PWCHAR)((PUCHAR)createInput + inputLength);
  819. p = createInput->FileName;
  820. while ( p < pMax ) {
  821. if ( *p == 0 ) {
  822. break;
  823. }
  824. p++;
  825. }
  826. if ( p == pMax ) {
  827. return STATUS_INVALID_PARAMETER;
  828. }
  829. }
  830. //
  831. // Call RamdiskCreateDiskDevice to create the device. If successful, this
  832. // returns a pointer to the new disk PDO's device extension.
  833. //
  834. status = RamdiskCreateDiskDevice( busExtension, createInput, AccessCheckOnly, &diskExtension );
  835. if ( NT_SUCCESS(status) ) {
  836. //
  837. // Tell PnP that we need to reenumerate our bus.
  838. //
  839. IoInvalidateDeviceRelations( busExtension->Pdo, BusRelations );
  840. Irp->IoStatus.Information = 0;
  841. }
  842. return status;
  843. } // RamdiskCreateRamDisk
  844. NTSTATUS
  845. RamdiskCreateDiskDevice (
  846. IN PBUS_EXTENSION BusExtension,
  847. IN PRAMDISK_CREATE_INPUT CreateInput,
  848. IN BOOLEAN AccessCheckOnly,
  849. OUT PDISK_EXTENSION *DiskExtension
  850. )
  851. /*++
  852. Routine Description:
  853. This routine does the work to create a new RAM disk device. It is called
  854. in thread context.
  855. Arguments:
  856. BusExtension - a pointer to the device extension for the bus FDO
  857. CreateInput - a pointer to the desired parameters for the new RAM disk
  858. AccessCheckOnly - If FALSE, create the RAM disk. Otherwise, just check
  859. whether the caller has the necessary access rights to create the disk.
  860. DiskExtension - returns a pointer to the new disk PDO's device extension
  861. Return Value:
  862. NTSTATUS - the status of the operation
  863. --*/
  864. {
  865. ULONG status;
  866. ULONG_PTR basePage;
  867. PVOID baseAddress;
  868. ULONG i;
  869. ULONG deviceExtensionSize;
  870. PDEVICE_OBJECT newDeviceObject;
  871. WCHAR buffer[15];
  872. UNICODE_STRING guidString;
  873. UNICODE_STRING realDeviceName;
  874. PDISK_EXTENSION diskExtension;
  875. HANDLE fileHandle;
  876. HANDLE sectionHandle;
  877. PVOID sectionObject;
  878. NTSTATUS ntStatus;
  879. PVOID viewBase;
  880. SIZE_T viewSize;
  881. LARGE_INTEGER sectionOffset;
  882. UNICODE_STRING string;
  883. OBJECT_ATTRIBUTES obja;
  884. IO_STATUS_BLOCK iosb;
  885. UNICODE_STRING dosSymLink;
  886. FILE_STANDARD_INFORMATION fileInfo;
  887. PVIEW viewDescriptors = NULL;
  888. HRESULT result;
  889. #if SUPPORT_DISK_NUMBERS
  890. ULONG diskNumber;
  891. #endif // SUPPORT_DISK_NUMBERS
  892. PAGED_CODE();
  893. //
  894. // Initialize local variables to prepare for exit cleanup.
  895. //
  896. #if SUPPORT_DISK_NUMBERS
  897. diskNumber = 0xffffffff;
  898. #endif // SUPPORT_DISK_NUMBERS
  899. fileHandle = NULL;
  900. sectionHandle = NULL;
  901. sectionObject = NULL;
  902. viewDescriptors = NULL;
  903. guidString.Buffer = NULL;
  904. realDeviceName.Buffer = NULL;
  905. dosSymLink.Buffer = NULL;
  906. #if SUPPORT_DISK_NUMBERS
  907. if ( !AccessCheckOnly ) {
  908. //
  909. // Allocate a disk number.
  910. //
  911. KeEnterCriticalRegion();
  912. ExAcquireFastMutex( &BusExtension->Mutex );
  913. diskNumber = RtlFindClearBitsAndSet( &BusExtension->DiskNumbersBitmap, 1, 0 );
  914. ExReleaseFastMutex( &BusExtension->Mutex );
  915. KeLeaveCriticalRegion();
  916. if ( diskNumber == 0xffffffff ) {
  917. status = STATUS_INSUFFICIENT_RESOURCES;
  918. goto exit;
  919. }
  920. //
  921. // Convert the zero-based bit number to a one-based disk number.
  922. //
  923. diskNumber++;
  924. }
  925. #endif // SUPPORT_DISK_NUMBERS
  926. //
  927. // Initialize based on the disk type (file-backed or in-memory).
  928. //
  929. DBGPRINT( DBG_IOCTL, DBG_INFO,
  930. ("RamdiskCreateDiskDevice: Creating disk with length 0x%08x\n",
  931. CreateInput->DiskLength) );
  932. sectionObject = NULL;
  933. basePage = 0;
  934. baseAddress = NULL;
  935. if ( RAMDISK_IS_FILE_BACKED(CreateInput->DiskType) ) {
  936. //
  937. // This is a file-backed RAM disk. Open the backing file. Note that
  938. // we do NOT create the file here if it doesn't exist. It is up to
  939. // the caller to handle that.
  940. //
  941. RtlInitUnicodeString( &string, CreateInput->FileName );
  942. InitializeObjectAttributes( &obja, &string, OBJ_CASE_INSENSITIVE, NULL, NULL );
  943. status = IoCreateFile(
  944. &fileHandle,
  945. SYNCHRONIZE | FILE_READ_DATA | FILE_READ_ATTRIBUTES |
  946. (CreateInput->Options.Readonly ? 0 : FILE_WRITE_DATA),
  947. &obja,
  948. &iosb,
  949. NULL,
  950. 0,
  951. FILE_SHARE_READ,
  952. FILE_OPEN,
  953. 0,
  954. NULL,
  955. 0,
  956. CreateFileTypeNone,
  957. NULL,
  958. (AccessCheckOnly ? IO_FORCE_ACCESS_CHECK | IO_NO_PARAMETER_CHECKING : 0)
  959. );
  960. if ( !NT_SUCCESS(status) ) {
  961. DBGPRINT( DBG_IOCTL, DBG_ERROR,
  962. ("RamdiskCreateDiskDevice: Can't open target file %ws: %x\n",
  963. CreateInput->FileName, status) );
  964. goto exit;
  965. }
  966. if ( AccessCheckOnly ) {
  967. goto exit;
  968. }
  969. //
  970. // Get the size of the file.
  971. //
  972. status = ZwQueryInformationFile(
  973. fileHandle,
  974. &iosb,
  975. &fileInfo,
  976. sizeof(fileInfo),
  977. FileStandardInformation
  978. );
  979. if ( !NT_SUCCESS(status) ) {
  980. DBGPRINT( DBG_IOCTL, DBG_ERROR,
  981. ("RamdiskCreateDiskDevice: Can't query info for file %ws: %x\n",
  982. CreateInput->FileName, status) );
  983. goto exit;
  984. }
  985. //
  986. // Verify that the file is long enough for the specified DiskOffset
  987. // and DiskLength.
  988. //
  989. DBGPRINT( DBG_IOCTL, DBG_INFO, ("RamdiskCreateDiskDevice: file size = %I64x\n",
  990. fileInfo.EndOfFile.QuadPart) );
  991. if ( (CreateInput->DiskOffset + CreateInput->DiskLength) >
  992. (ULONGLONG)fileInfo.EndOfFile.QuadPart ) {
  993. DBGPRINT( DBG_IOCTL, DBG_ERROR,
  994. ("RamdiskCreateDiskDevice: specified offset and length too big for file:"
  995. " 0x%x + 0x%I64x > 0x%I64x\n",
  996. CreateInput->DiskOffset, CreateInput->DiskLength,
  997. fileInfo.EndOfFile.QuadPart) );
  998. status = STATUS_INVALID_PARAMETER;
  999. goto exit;
  1000. }
  1001. //
  1002. // Create a section for the file. Close the file handle.
  1003. //
  1004. status = ZwCreateSection(
  1005. &sectionHandle,
  1006. SECTION_ALL_ACCESS,
  1007. NULL,
  1008. 0,
  1009. (CreateInput->Options.Readonly ? PAGE_READONLY : PAGE_READWRITE),
  1010. SEC_COMMIT,
  1011. fileHandle
  1012. );
  1013. if ( !NT_SUCCESS(status) ) {
  1014. DBGPRINT( DBG_IOCTL, DBG_ERROR,
  1015. ("RamdiskCreateDiskDevice: Can't create section for %ws: %x\n",
  1016. CreateInput->FileName, status) );
  1017. goto exit;
  1018. }
  1019. NtClose( fileHandle );
  1020. fileHandle = NULL;
  1021. //
  1022. // Get a referenced pointer to the section object. Close the section.
  1023. //
  1024. status = ObReferenceObjectByHandle(
  1025. sectionHandle,
  1026. SECTION_ALL_ACCESS,
  1027. *(POBJECT_TYPE *)MmSectionObjectType,
  1028. KernelMode,
  1029. &sectionObject,
  1030. NULL
  1031. );
  1032. if ( !NT_SUCCESS(status) ) {
  1033. DBGPRINT( DBG_IOCTL, DBG_ERROR,
  1034. ("RamdiskCreateDiskDevice: Can't reference section for %ws: %x\n",
  1035. CreateInput->FileName, status) );
  1036. goto exit;
  1037. }
  1038. NtClose( sectionHandle );
  1039. sectionHandle = NULL;
  1040. //
  1041. // Allocate space for view descriptors. First, get the number of views
  1042. // to use and the size of each view.
  1043. //
  1044. if ( CreateInput->ViewCount == 0 ) {
  1045. CreateInput->ViewCount = DefaultViewCount;
  1046. } else if ( CreateInput->ViewCount < MinimumViewCount ) {
  1047. CreateInput->ViewCount = MinimumViewCount;
  1048. } else if ( CreateInput->ViewCount > MaximumViewCount ) {
  1049. CreateInput->ViewCount = MaximumViewCount;
  1050. }
  1051. if ( CreateInput->ViewLength == 0 ) {
  1052. CreateInput->ViewLength = DefaultViewLength;
  1053. } else if ( CreateInput->ViewLength < MinimumViewLength ) {
  1054. CreateInput->ViewLength = MinimumViewLength;
  1055. } else if ( CreateInput->ViewLength > MaximumViewLength ) {
  1056. CreateInput->ViewLength = MaximumViewLength;
  1057. }
  1058. //
  1059. // Ensure that the total view length is not greater than the maximum
  1060. // per-disk view length. If necessary, decrease the view count until
  1061. // the total view length is low enough. If the view count reaches the
  1062. // configured minimum, reduce the length of each view until the total
  1063. // view length is low enough.
  1064. //
  1065. // It is possible for the administrator to configure the minimum view
  1066. // count, minimum view length, and maximum per-disk view length such
  1067. // that it's impossible for the minimum total view length to be less
  1068. // than the maximum per-disk view length. (That is, the miinimum view
  1069. // count and minimum view length are configured to high relative to
  1070. // the configured maximum per-disk view length.) If this occurs, we
  1071. // create the disk with the compile-time defaults instead.
  1072. //
  1073. while ( ((ULONGLONG)CreateInput->ViewCount * CreateInput->ViewLength) >
  1074. MaximumPerDiskViewLength ) {
  1075. //
  1076. // The total view length is too big. If possible, cut the number of
  1077. // views in half.
  1078. //
  1079. if ( CreateInput->ViewCount > MinimumViewCount ) {
  1080. //
  1081. // The view count isn't at the minimum. Cut in half, but don't
  1082. // go below the minimum.
  1083. //
  1084. CreateInput->ViewCount /= 2;
  1085. if ( CreateInput->ViewCount < MinimumViewCount ) {
  1086. CreateInput->ViewCount = MinimumViewCount;
  1087. }
  1088. } else {
  1089. //
  1090. // The view count is already at the minimum. If possible,
  1091. // cut the view length in half.
  1092. //
  1093. if ( CreateInput->ViewLength > MinimumViewLength ) {
  1094. //
  1095. // The view length isn't at the minimum. Cut in half, but
  1096. // don't go below the minimum.
  1097. //
  1098. CreateInput->ViewLength /= 2;
  1099. if ( CreateInput->ViewLength < MinimumViewLength ) {
  1100. CreateInput->ViewLength = MinimumViewLength;
  1101. }
  1102. } else {
  1103. //
  1104. // At this point, the view count and the view length are
  1105. // both at the minimum allowed values, but the total view
  1106. // length is beyond the maximum per-disk value. Use the
  1107. // compile-time default values instead. Note that this will
  1108. // result in a total view length that is equal to the
  1109. // minimum allowed maximum per-disk view length, at least
  1110. // given the compile-time values as of this writing.
  1111. //
  1112. CreateInput->ViewCount = DEFAULT_DEFAULT_VIEW_COUNT;
  1113. CreateInput->ViewLength = DEFAULT_DEFAULT_VIEW_LENGTH;
  1114. ASSERT( ((ULONGLONG)CreateInput->ViewCount * CreateInput->ViewLength) <=
  1115. MaximumPerDiskViewLength );
  1116. break;
  1117. }
  1118. }
  1119. }
  1120. viewDescriptors = ALLOCATE_POOL(
  1121. PagedPool,
  1122. CreateInput->ViewCount * sizeof(VIEW),
  1123. TRUE );
  1124. if ( viewDescriptors == NULL ) {
  1125. DBGPRINT( DBG_IOCTL, DBG_ERROR,
  1126. ("%s", "RamdiskCreateDiskDevice: Can't allocate pool for view descriptors\n") );
  1127. status = STATUS_INSUFFICIENT_RESOURCES;
  1128. goto exit;
  1129. }
  1130. RtlZeroMemory( viewDescriptors, CreateInput->ViewCount * sizeof(VIEW) );
  1131. } else if ( CreateInput->DiskType == RAMDISK_TYPE_BOOT_DISK ) {
  1132. //
  1133. // For a boot disk, the input parameter buffer tells us where the
  1134. // image is in physical memory, and how big the image is.
  1135. //
  1136. basePage = CreateInput->BasePage;
  1137. if ( basePage == 0 ) {
  1138. DBGPRINT( DBG_IOCTL, DBG_ERROR,
  1139. ("%s", "RamdiskCreateDiskDevice: Base page for boot disk is 0?!?\n") );
  1140. ASSERT( FALSE );
  1141. status = STATUS_INVALID_PARAMETER;
  1142. goto exit;
  1143. }
  1144. //
  1145. // Force options to the appropriate values for a boot disk.
  1146. //
  1147. CreateInput->Options.Fixed = TRUE;
  1148. CreateInput->Options.Readonly = FALSE;
  1149. CreateInput->Options.NoDriveLetter = FALSE;
  1150. CreateInput->Options.NoDosDevice = FALSE;
  1151. CreateInput->Options.Hidden = FALSE;
  1152. } else if ( CreateInput->DiskType == RAMDISK_TYPE_VIRTUAL_FLOPPY ) {
  1153. //
  1154. // For a virtual floppy, the input parameter buffer tells us where the
  1155. // image is in virtual memory, and how big the image is.
  1156. //
  1157. baseAddress = CreateInput->BaseAddress;
  1158. ASSERT( baseAddress != NULL );
  1159. //
  1160. // Force options to the appropriate values for a virtual floppy.
  1161. //
  1162. CreateInput->Options.Fixed = TRUE;
  1163. CreateInput->Options.Readonly = FALSE;
  1164. CreateInput->Options.NoDriveLetter = TRUE;
  1165. CreateInput->Options.NoDosDevice = FALSE;
  1166. CreateInput->Options.Hidden = FALSE;
  1167. } else {
  1168. DBGPRINT( DBG_IOCTL, DBG_ERROR,
  1169. ("RamdiskCreateDiskDevice: Bad disk type %d\n", CreateInput->DiskType) );
  1170. status = STATUS_INVALID_PARAMETER;
  1171. goto exit;
  1172. }
  1173. if ( AccessCheckOnly ) {
  1174. status = STATUS_SUCCESS;
  1175. goto exit;
  1176. }
  1177. ASSERT( (basePage != 0) || (sectionObject != NULL) || (baseAddress != NULL) );
  1178. //
  1179. // Create a name for the disk, based on the disk GUID. For all disk types
  1180. // except VIRTUAL_FLOPPY, the name is of the form \Device\Ramdisk{guid}.
  1181. // For VIRTUAL_FLOPPY, the name is of the form \Device\RamdiskN, when N is
  1182. // specified by the Data1 field of the GUID.
  1183. //
  1184. if ( CreateInput->DiskType != RAMDISK_TYPE_VIRTUAL_FLOPPY ) {
  1185. status = RtlStringFromGUID( &CreateInput->DiskGuid, &guidString );
  1186. } else {
  1187. // This variable is here to keep PREfast quiet (PREfast warning 209).
  1188. size_t size = sizeof(buffer);
  1189. result = StringCbPrintfW( buffer, size, L"%u", CreateInput->DiskGuid.Data1 );
  1190. ASSERT( result == S_OK );
  1191. status = RtlCreateUnicodeString( &guidString, buffer );
  1192. }
  1193. if ( !NT_SUCCESS(status) || (guidString.Buffer == NULL) ) {
  1194. DBGPRINT( DBG_IOCTL, DBG_ERROR,
  1195. ("%s", "RamdiskCreateDiskDevice: can't allocate pool for pretty GUID\n") );
  1196. status = STATUS_INSUFFICIENT_RESOURCES;
  1197. goto exit;
  1198. }
  1199. i = sizeof(RAMDISK_DEVICENAME) + guidString.Length;
  1200. realDeviceName.Buffer = ALLOCATE_POOL( NonPagedPool, i, TRUE );
  1201. if ( (realDeviceName.Buffer == NULL) ) {
  1202. DBGPRINT( DBG_IOCTL, DBG_ERROR,
  1203. ("%s", "RamdiskCreateDiskDevice: can't allocate pool for device name\n") );
  1204. status = STATUS_INSUFFICIENT_RESOURCES;
  1205. goto exit;
  1206. }
  1207. realDeviceName.MaximumLength = (USHORT)i;
  1208. realDeviceName.Length = realDeviceName.MaximumLength - sizeof(WCHAR);
  1209. result = StringCbCopyW( realDeviceName.Buffer, i, RAMDISK_DEVICENAME );
  1210. ASSERT( result == S_OK );
  1211. result = StringCbCatW( realDeviceName.Buffer, i, guidString.Buffer );
  1212. ASSERT( result == S_OK );
  1213. ASSERT( (wcslen(realDeviceName.Buffer) * sizeof(WCHAR)) == realDeviceName.Length );
  1214. DBGPRINT( DBG_IOCTL, DBG_INFO,
  1215. ("RamdiskCreateDiskDevice: Device name is %wZ\n", &realDeviceName) );
  1216. //
  1217. // Create the RAM disk device.
  1218. //
  1219. // ISSUE: Apply an ACL to the disk device object. (Or does the next issue obviate this?)
  1220. // ISSUE: Should we use an autogenerated name for the PDO? This would mean
  1221. // that we'd have to return the device name as the IOCTL output,
  1222. // not just the disk number.
  1223. //
  1224. deviceExtensionSize = sizeof(DISK_EXTENSION);
  1225. if ( RAMDISK_IS_FILE_BACKED(CreateInput->DiskType) ) {
  1226. deviceExtensionSize += wcslen( CreateInput->FileName ) * sizeof(WCHAR);
  1227. }
  1228. status = IoCreateDevice(
  1229. BusExtension->Fdo->DriverObject,
  1230. deviceExtensionSize,
  1231. &realDeviceName,
  1232. FILE_DEVICE_DISK,
  1233. CreateInput->Options.Fixed ? 0 : FILE_REMOVABLE_MEDIA, // | FILE_VIRTUAL_VOLUME,
  1234. FALSE,
  1235. &newDeviceObject
  1236. );
  1237. if ( !NT_SUCCESS(status) ) {
  1238. DBGPRINT( DBG_IOCTL, DBG_ERROR,
  1239. ("RamdiskCreateDiskDevice: IoCreateDevice failed: %x\n", status) );
  1240. goto exit;
  1241. }
  1242. diskExtension = newDeviceObject->DeviceExtension;
  1243. //
  1244. // Create a DosDevices link for the device.
  1245. //
  1246. if ( !CreateInput->Options.NoDosDevice ) {
  1247. //
  1248. // Create a DosDevices symbolic link. Ignore errors.
  1249. //
  1250. i = sizeof(RAMDISK_FULL_DOSNAME) + guidString.Length;
  1251. dosSymLink.MaximumLength = (USHORT)i;
  1252. dosSymLink.Length = dosSymLink.MaximumLength - sizeof(WCHAR);
  1253. dosSymLink.Buffer = ALLOCATE_POOL( NonPagedPool, i, TRUE );
  1254. if ( dosSymLink.Buffer == NULL ) {
  1255. DBGPRINT( DBG_IOCTL, DBG_ERROR,
  1256. ("%s", "RamdiskCreateDiskDevice: can't allocate pool for DosDevices name\n") );
  1257. CreateInput->Options.NoDosDevice = TRUE;
  1258. } else {
  1259. result = StringCbCopyW( dosSymLink.Buffer, i, RAMDISK_FULL_DOSNAME );
  1260. ASSERT( result == S_OK );
  1261. result = StringCbCatW( dosSymLink.Buffer, i, guidString.Buffer );
  1262. ASSERT( result == S_OK );
  1263. ASSERT( (wcslen(dosSymLink.Buffer) * sizeof(WCHAR)) == dosSymLink.Length );
  1264. status = IoCreateSymbolicLink( &dosSymLink, &realDeviceName );
  1265. if ( !NT_SUCCESS(status) ) {
  1266. DBGPRINT( DBG_IOCTL, DBG_ERROR,
  1267. ("RamdiskCreateDiskDevice: IoCreateSymbolicLink failed: %x\n", status) );
  1268. CreateInput->Options.NoDosDevice = TRUE;
  1269. FREE_POOL( dosSymLink.Buffer, TRUE );
  1270. dosSymLink.Buffer = NULL;
  1271. }
  1272. }
  1273. //
  1274. // If creating the boot disk, create a drive letter.
  1275. //
  1276. if ( CreateInput->DiskType == RAMDISK_TYPE_BOOT_DISK ) {
  1277. // This variable is here to keep PREfast quiet (PREfast warning 209).
  1278. size_t size = sizeof(buffer);
  1279. result = StringCbPrintfW(
  1280. buffer,
  1281. size,
  1282. L"\\DosDevices\\%wc:",
  1283. CreateInput->DriveLetter
  1284. );
  1285. ASSERT( result == S_OK );
  1286. RtlInitUnicodeString( &string, buffer );
  1287. IoDeleteSymbolicLink( &string );
  1288. IoCreateSymbolicLink( &string, &realDeviceName );
  1289. diskExtension->DriveLetter = CreateInput->DriveLetter;
  1290. }
  1291. }
  1292. //
  1293. // Initialize device object and extension.
  1294. //
  1295. //
  1296. // Our device does direct I/O, is XIP-capable, and is power pageable.
  1297. // We require word alignment for I/O.
  1298. //
  1299. newDeviceObject->Flags |= DO_DIRECT_IO | DO_XIP | DO_POWER_PAGABLE;
  1300. newDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
  1301. //
  1302. // Return a pointer to the device extension to the caller.
  1303. //
  1304. *DiskExtension = diskExtension;
  1305. //
  1306. // Set the device type and state in the device extension. Initialize the
  1307. // fast mutex and the remove lock. Save the device name string.
  1308. //
  1309. diskExtension->DeviceType = RamdiskDeviceTypeDiskPdo;
  1310. diskExtension->DeviceState = RamdiskDeviceStateStopped;
  1311. ExInitializeFastMutex( &diskExtension->Mutex );
  1312. IoInitializeRemoveLock( &diskExtension->RemoveLock, 'dmaR', 1, 0 );
  1313. diskExtension->DeviceName = realDeviceName;
  1314. realDeviceName.Buffer = NULL;
  1315. diskExtension->DosSymLink = dosSymLink;
  1316. dosSymLink.Buffer = NULL;
  1317. diskExtension->DiskGuid = CreateInput->DiskGuid;
  1318. diskExtension->DiskGuidFormatted = guidString;
  1319. guidString.Buffer = NULL;
  1320. #if SUPPORT_DISK_NUMBERS
  1321. //
  1322. // Save the disk number.
  1323. //
  1324. diskExtension->DiskNumber = diskNumber;
  1325. diskNumber = 0xffffffff;
  1326. #endif // SUPPORT_DISK_NUMBERS
  1327. //
  1328. // Save object pointers. The PDO for this extension is the device
  1329. // extension is the device object that we just created. The FDO and
  1330. // the lower device object are the bus FDO.
  1331. //
  1332. diskExtension->Pdo = newDeviceObject;
  1333. diskExtension->Fdo = RamdiskBusFdo;
  1334. diskExtension->LowerDeviceObject = RamdiskBusFdo;
  1335. //
  1336. // ISSUE: What about BiosParameters?
  1337. //
  1338. //bios = &diskExtension->BiosParameters;
  1339. //
  1340. //diskExtension->BootParameters = xipbootparameters;
  1341. //status = RamdDispatch(XIPCMD_GETBIOSPARAMETERS, bios, sizeof(*bios));
  1342. //
  1343. // Save pointers to the disk image.
  1344. //
  1345. diskExtension->BasePage = basePage;
  1346. diskExtension->SectionObject = sectionObject;
  1347. sectionObject = NULL;
  1348. diskExtension->BaseAddress = baseAddress;
  1349. if ( RAMDISK_IS_FILE_BACKED(CreateInput->DiskType) ) {
  1350. result = StringCbCopyW(
  1351. diskExtension->FileName,
  1352. deviceExtensionSize,
  1353. CreateInput->FileName
  1354. );
  1355. ASSERT( result == S_OK );
  1356. }
  1357. //
  1358. // Save the disk type (disk or volume) and disk options.
  1359. //
  1360. diskExtension->DiskType = CreateInput->DiskType;
  1361. diskExtension->Options = CreateInput->Options;
  1362. //
  1363. // For a file-backed disk image, set up the view descriptors.
  1364. //
  1365. // ISSUE: Need to consider whether to permanently map the first few pages
  1366. // of the image. The first sector on the disk is accessed frequently, so
  1367. // there is some value in keeping it mapped. But it might not be worth it
  1368. // to waste a view descriptor on this. And the LRU nature of the view
  1369. // replacement algorithm will keep the first sector mapped when necessary.
  1370. //
  1371. if ( viewDescriptors != NULL ) {
  1372. PVIEW view;
  1373. //
  1374. // Initialize windowing fields in the disk extension.
  1375. //
  1376. diskExtension->ViewCount = CreateInput->ViewCount;
  1377. diskExtension->ViewLength = CreateInput->ViewLength;
  1378. diskExtension->ViewDescriptors = viewDescriptors;
  1379. KeInitializeSemaphore( &diskExtension->ViewSemaphore, 0, MAXLONG );
  1380. diskExtension->ViewWaiterCount = 0;
  1381. //
  1382. // Initialize the view lists, then insert in each view descriptor
  1383. // in order. The result is a list of descriptors, each unmapped
  1384. // (offset and length both 0).
  1385. //
  1386. InitializeListHead( &diskExtension->ViewsByOffset );
  1387. InitializeListHead( &diskExtension->ViewsByMru );
  1388. view = viewDescriptors;
  1389. for ( i = 0; i < diskExtension->ViewCount; i++ ) {
  1390. InsertTailList( &diskExtension->ViewsByOffset, &view->ByOffsetListEntry );
  1391. InsertTailList( &diskExtension->ViewsByMru, &view->ByMruListEntry );
  1392. view++;
  1393. }
  1394. viewDescriptors = NULL;
  1395. }
  1396. diskExtension->DiskLength = CreateInput->DiskLength;
  1397. diskExtension->DiskOffset = CreateInput->DiskOffset;
  1398. diskExtension->FileRelativeEndOfDisk = diskExtension->DiskOffset + diskExtension->DiskLength;
  1399. //
  1400. // Set the disk geometry. The basic geometry is constant for new disks.
  1401. // For RAMDISK_TYPE_BOOT_DISK type volume geometry can be obtained from the partition boot sector.
  1402. //
  1403. if ( RAMDISK_TYPE_BOOT_DISK != CreateInput->DiskType ) {
  1404. diskExtension->BytesPerSector = 0x200;
  1405. diskExtension->SectorsPerTrack = 0x80;
  1406. diskExtension->TracksPerCylinder = 0x10;
  1407. }
  1408. else {
  1409. //
  1410. // 2002/04/19-SaadSyed (Saad Syed)
  1411. // Added generic geometry support to support SDI files
  1412. //
  1413. PPACKED_EXTENDED_BIOS_PARAMETER_BLOCK BootSector = NULL;
  1414. ULONG mappedLength;
  1415. BIOS_PARAMETER_BLOCK Bpb;
  1416. //
  1417. // Map boot sector of boot ramdisk
  1418. //
  1419. BootSector = ( PPACKED_EXTENDED_BIOS_PARAMETER_BLOCK ) RamdiskMapPages( diskExtension, 0, PAGE_SIZE, &mappedLength );
  1420. if ( NULL != BootSector ) {
  1421. ASSERT( mappedLength == PAGE_SIZE );
  1422. UnpackBios( &Bpb, &BootSector->Bpb );
  1423. //
  1424. // Extract geometry from boot sector bios parameter block
  1425. //
  1426. diskExtension->BytesPerSector = Bpb.BytesPerSector;
  1427. diskExtension->SectorsPerTrack = Bpb.SectorsPerTrack;
  1428. diskExtension->TracksPerCylinder = Bpb.Heads;
  1429. RamdiskUnmapPages(diskExtension, (PUCHAR) BootSector, 0, mappedLength);
  1430. BootSector = NULL;
  1431. }
  1432. else {
  1433. status = STATUS_INSUFFICIENT_RESOURCES;
  1434. goto exit;
  1435. }
  1436. }
  1437. diskExtension->BytesPerCylinder = diskExtension->BytesPerSector *
  1438. diskExtension->SectorsPerTrack *
  1439. diskExtension->TracksPerCylinder;
  1440. diskExtension->NumberOfCylinders =
  1441. (ULONG)(CreateInput->DiskLength / diskExtension->BytesPerCylinder);
  1442. //
  1443. // A partition/volume does not often map to a geometry completely, the file system driver limits the
  1444. // volume to a capacity determined by the NumberOfSectors (in the Boot Sector) * BytesPerSector (in BPB).
  1445. // The FS driver uses the this geometry to determine if the NumberOfSectors is less than or
  1446. // equal to the total number of sectors reported by the geometry, otherwise it fails to mount the volume.
  1447. // Here we check if the length of disk as obtained from the ramdisk image is less than or equal to the length
  1448. // obtained by the geometry. We increment the number of cylinders if this check fails. This keeps the FS driver
  1449. // happy. A simple ceil operation would yield the same results.
  1450. //
  1451. if ( ( diskExtension->BytesPerCylinder *
  1452. diskExtension->NumberOfCylinders ) < CreateInput->DiskLength) {
  1453. diskExtension->NumberOfCylinders++;
  1454. }
  1455. //
  1456. // Link the new disk into the bus FDO's list of disks.
  1457. //
  1458. KeEnterCriticalRegion();
  1459. ExAcquireFastMutex( &BusExtension->Mutex );
  1460. InsertTailList( &BusExtension->DiskPdoList, &diskExtension->DiskPdoListEntry );
  1461. ExReleaseFastMutex( &BusExtension->Mutex );
  1462. KeLeaveCriticalRegion();
  1463. //
  1464. // Indicate that we're done initializing the device.
  1465. //
  1466. newDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  1467. status = STATUS_SUCCESS;
  1468. goto exit_exit;
  1469. exit:
  1470. if ( dosSymLink.Buffer != NULL ) {
  1471. FREE_POOL( dosSymLink.Buffer, TRUE );
  1472. dosSymLink.Buffer = NULL;
  1473. }
  1474. if ( realDeviceName.Buffer != NULL ) {
  1475. FREE_POOL( realDeviceName.Buffer, TRUE );
  1476. realDeviceName.Buffer = NULL;
  1477. }
  1478. if ( guidString.Buffer != NULL ) {
  1479. FREE_POOL( guidString.Buffer, FALSE );
  1480. guidString.Buffer = NULL;
  1481. }
  1482. if ( viewDescriptors != NULL ) {
  1483. FREE_POOL( viewDescriptors, TRUE );
  1484. viewDescriptors = NULL;
  1485. }
  1486. if ( sectionObject != NULL ) {
  1487. ObDereferenceObject( sectionObject );
  1488. sectionObject = NULL;
  1489. }
  1490. if ( sectionHandle != NULL ) {
  1491. NtClose( sectionHandle );
  1492. sectionHandle = NULL;
  1493. }
  1494. if ( fileHandle != NULL ) {
  1495. NtClose( fileHandle );
  1496. fileHandle = NULL;
  1497. }
  1498. #if SUPPORT_DISK_NUMBERS
  1499. if ( diskNumber != 0xffffffff ) {
  1500. KeEnterCriticalRegion();
  1501. ExAcquireFastMutex( &BusExtension->Mutex );
  1502. RtlClearBit( &BusExtension->DiskNumbersBitmap, diskNumber - 1 );
  1503. ExReleaseFastMutex( &BusExtension->Mutex );
  1504. KeLeaveCriticalRegion();
  1505. diskNumber = 0xffffffff;
  1506. }
  1507. #endif // SUPPORT_DISK_NUMBERS
  1508. exit_exit:
  1509. ASSERT( fileHandle == NULL );
  1510. ASSERT( sectionHandle == NULL );
  1511. ASSERT( sectionObject == NULL );
  1512. ASSERT( viewDescriptors == NULL );
  1513. ASSERT( guidString.Buffer == NULL );
  1514. ASSERT( realDeviceName.Buffer == NULL );
  1515. ASSERT( dosSymLink.Buffer == NULL );
  1516. return status;
  1517. } // RamdiskCreateDiskDevice
  1518. NTSTATUS
  1519. RamdiskGetDriveLayout (
  1520. PIRP Irp,
  1521. PDISK_EXTENSION DiskExtension
  1522. )
  1523. /*++
  1524. Routine Description:
  1525. This routine is called to handle an IOCTL_GET_DRIVE_LAYOUT IRP. It is
  1526. called in thread context iff the disk is file-backed.
  1527. Arguments:
  1528. Irp - a pointer to the I/O Request Packet for this request
  1529. DiskExtension - a pointer to the device extension for the target disk
  1530. Return Value:
  1531. NTSTATUS - the status of the operation
  1532. --*/
  1533. {
  1534. PIO_STACK_LOCATION irpSp;
  1535. PDRIVE_LAYOUT_INFORMATION driveLayout;
  1536. PPARTITION_INFORMATION partInfo;
  1537. PPARTITION_DESCRIPTOR partitionTableEntry;
  1538. PUCHAR va;
  1539. ULONG mappedLength;
  1540. PAGED_CODE();
  1541. irpSp = IoGetCurrentIrpStackLocation( Irp );
  1542. if ( irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  1543. sizeof(DRIVE_LAYOUT_INFORMATION) ) {
  1544. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  1545. Irp->IoStatus.Information = 0;
  1546. return STATUS_INVALID_PARAMETER;
  1547. }
  1548. //
  1549. // Map the first page of the image.
  1550. //
  1551. va = RamdiskMapPages( DiskExtension, 0, PAGE_SIZE, &mappedLength );
  1552. if ( va == NULL ) {
  1553. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  1554. Irp->IoStatus.Information = 0;
  1555. return STATUS_INSUFFICIENT_RESOURCES;
  1556. }
  1557. ASSERT( mappedLength == PAGE_SIZE );
  1558. //
  1559. // Get a pointer to the output buffer. Fill in the header.
  1560. //
  1561. driveLayout = (PDRIVE_LAYOUT_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
  1562. //
  1563. // ISSUE: Is this right for an emulated disk? Or is this routine never
  1564. // called for emulated disks?
  1565. //
  1566. driveLayout->PartitionCount = 1;
  1567. driveLayout->Signature = 0;
  1568. partInfo = driveLayout->PartitionEntry;
  1569. //
  1570. // Point to the partition table in the disk image.
  1571. //
  1572. partitionTableEntry = (PPARTITION_DESCRIPTOR)&((PUSHORT)va)[PARTITION_TABLE_OFFSET];
  1573. //
  1574. // Return information about the partition.
  1575. //
  1576. partInfo->StartingOffset.QuadPart = DiskExtension->BytesPerSector;
  1577. partInfo->PartitionLength.QuadPart =
  1578. DiskExtension->NumberOfCylinders *
  1579. DiskExtension->TracksPerCylinder *
  1580. DiskExtension->SectorsPerTrack *
  1581. DiskExtension->BytesPerSector;
  1582. // ISSUE: Currently, HiddenSectors is always 0. Is this right?
  1583. partInfo->HiddenSectors = DiskExtension->HiddenSectors;
  1584. partInfo->PartitionNumber = 0;
  1585. partInfo->PartitionType = partitionTableEntry->PartitionType;
  1586. partInfo->BootIndicator = (BOOLEAN)(DiskExtension->DiskType == RAMDISK_TYPE_BOOT_DISK);
  1587. partInfo->RecognizedPartition = IsRecognizedPartition(partInfo->PartitionType);
  1588. partInfo->RewritePartition = FALSE;
  1589. //
  1590. // Unmap the mapped page.
  1591. //
  1592. RamdiskUnmapPages( DiskExtension, va, 0, mappedLength );
  1593. Irp->IoStatus.Status = STATUS_SUCCESS;
  1594. Irp->IoStatus.Information = sizeof(DRIVE_LAYOUT_INFORMATION);
  1595. return STATUS_SUCCESS;
  1596. } // RamdiskGetDriveLayout
  1597. NTSTATUS
  1598. RamdiskGetPartitionInfo (
  1599. PIRP Irp,
  1600. PDISK_EXTENSION DiskExtension
  1601. )
  1602. /*++
  1603. Routine Description:
  1604. This routine is called to handle an IOCTL_GET_PARTITION_INFO IRP. It is
  1605. called in thread context iff the disk is file-backed.
  1606. Arguments:
  1607. Irp - a pointer to the I/O Request Packet for this request
  1608. DiskExtension - a pointer to the device extension for the target disk
  1609. Return Value:
  1610. NTSTATUS - the status of the operation
  1611. --*/
  1612. {
  1613. PIO_STACK_LOCATION irpSp;
  1614. PPARTITION_INFORMATION partInfo;
  1615. PPARTITION_DESCRIPTOR partitionTableEntry;
  1616. PUCHAR va;
  1617. ULONG mappedLength;
  1618. PAGED_CODE();
  1619. irpSp = IoGetCurrentIrpStackLocation( Irp );
  1620. if ( irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(PARTITION_INFORMATION) ) {
  1621. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  1622. Irp->IoStatus.Information = 0;
  1623. return STATUS_INVALID_PARAMETER;
  1624. }
  1625. //
  1626. // Map the first page of the image.
  1627. //
  1628. va = RamdiskMapPages( DiskExtension, 0, PAGE_SIZE, &mappedLength );
  1629. if ( va == NULL ) {
  1630. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  1631. Irp->IoStatus.Information = 0;
  1632. return STATUS_INSUFFICIENT_RESOURCES;
  1633. }
  1634. ASSERT( mappedLength == PAGE_SIZE );
  1635. //
  1636. // Get a pointer to the output buffer.
  1637. //
  1638. partInfo = (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
  1639. //
  1640. // Point to the partition table in the disk image.
  1641. //
  1642. partitionTableEntry = (PPARTITION_DESCRIPTOR)&((PUSHORT)va)[PARTITION_TABLE_OFFSET];
  1643. //
  1644. // Return information about the partition.
  1645. //
  1646. partInfo->StartingOffset.QuadPart = DiskExtension->BytesPerSector;
  1647. partInfo->PartitionLength.QuadPart =
  1648. DiskExtension->NumberOfCylinders *
  1649. DiskExtension->TracksPerCylinder *
  1650. DiskExtension->SectorsPerTrack *
  1651. DiskExtension->BytesPerSector;
  1652. // ISSUE: Currently, HiddenSectors is always 0. Is this right?
  1653. partInfo->HiddenSectors = DiskExtension->HiddenSectors;
  1654. partInfo->PartitionNumber = 0;
  1655. partInfo->PartitionType = partitionTableEntry->PartitionType;
  1656. partInfo->BootIndicator = (BOOLEAN)(DiskExtension->DiskType == RAMDISK_TYPE_BOOT_DISK);
  1657. partInfo->RecognizedPartition = IsRecognizedPartition(partInfo->PartitionType);
  1658. partInfo->RewritePartition = FALSE;
  1659. //
  1660. // Unmap the mapped page.
  1661. //
  1662. RamdiskUnmapPages( DiskExtension, va, 0, mappedLength );
  1663. Irp->IoStatus.Status = STATUS_SUCCESS;
  1664. Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
  1665. return STATUS_SUCCESS;
  1666. } // RamdiskGetPartitionInfo
  1667. NTSTATUS
  1668. RamdiskSetPartitionInfo (
  1669. PIRP Irp,
  1670. PDISK_EXTENSION DiskExtension
  1671. )
  1672. /*++
  1673. Routine Description:
  1674. This routine is called to handle an IOCTL_SET_PARTITION_INFO IRP. It is
  1675. called in thread context iff the disk is file-backed.
  1676. Arguments:
  1677. Irp - a pointer to the I/O Request Packet for this request
  1678. DiskExtension - a pointer to the device extension for the target disk
  1679. Return Value:
  1680. NTSTATUS - the status of the operation
  1681. --*/
  1682. {
  1683. PIO_STACK_LOCATION irpSp;
  1684. PSET_PARTITION_INFORMATION partInfo;
  1685. PPARTITION_DESCRIPTOR partitionTableEntry;
  1686. PUCHAR va;
  1687. ULONG mappedLength;
  1688. PAGED_CODE();
  1689. irpSp = IoGetCurrentIrpStackLocation( Irp );
  1690. if ( irpSp->Parameters.DeviceIoControl.InputBufferLength <
  1691. sizeof(SET_PARTITION_INFORMATION) ) {
  1692. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  1693. Irp->IoStatus.Information = 0;
  1694. return STATUS_INVALID_PARAMETER;
  1695. }
  1696. //
  1697. // Map the first page of the image.
  1698. //
  1699. va = RamdiskMapPages( DiskExtension, 0, PAGE_SIZE, &mappedLength );
  1700. if ( va == NULL ) {
  1701. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  1702. Irp->IoStatus.Information = 0;
  1703. return STATUS_INSUFFICIENT_RESOURCES;
  1704. }
  1705. ASSERT( mappedLength == PAGE_SIZE );
  1706. //
  1707. // Get a pointer to the output buffer.
  1708. //
  1709. partInfo = (PSET_PARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
  1710. //
  1711. // Point to the partition table in the disk image.
  1712. //
  1713. partitionTableEntry = (PPARTITION_DESCRIPTOR)&((PUSHORT)va)[PARTITION_TABLE_OFFSET];
  1714. //
  1715. // Write the new partition type.
  1716. //
  1717. partitionTableEntry->PartitionType = partInfo->PartitionType;
  1718. //
  1719. // Unmap the mapped page.
  1720. //
  1721. RamdiskUnmapPages( DiskExtension, va, 0, mappedLength );
  1722. Irp->IoStatus.Status = STATUS_SUCCESS;
  1723. Irp->IoStatus.Information = 0;
  1724. return STATUS_SUCCESS;
  1725. } // RamdiskGetPartitionInfo
  1726. NTSTATUS
  1727. RamdiskQueryProperty (
  1728. IN PDEVICE_OBJECT DeviceObject,
  1729. IN OUT PIRP Irp
  1730. )
  1731. /*++
  1732. Routine Description:
  1733. This routine handles a property query request. It builds the descriptor
  1734. on its own if possible, otherwise it forwards the request down to lower
  1735. level drivers.
  1736. Since this routine may forward the request downwards the caller should
  1737. not complete the IRP.
  1738. This routine must be called with the remove lock held. The lock is
  1739. released when this routine returns.
  1740. Arguments:
  1741. DeviceObject - a pointer to the device object being queried
  1742. Irp - a pointer to the IRP for the query
  1743. Return Value:
  1744. NTSTATUS - the status of the operation
  1745. --*/
  1746. {
  1747. NTSTATUS status;
  1748. PIO_STACK_LOCATION irpSp;
  1749. PSTORAGE_PROPERTY_QUERY query;
  1750. ULONG queryLength;
  1751. PSTORAGE_DEVICE_DESCRIPTOR storageDeviceDescriptor;
  1752. PSTORAGE_ADAPTER_DESCRIPTOR storageAdapterDescriptor;
  1753. ULONG offset;
  1754. ULONG length;
  1755. PUCHAR p;
  1756. PCOMMON_EXTENSION commonExtension;
  1757. PBUS_EXTENSION busExtension;
  1758. PDISK_EXTENSION diskExtension;
  1759. STORAGE_DEVICE_DESCRIPTOR sdd;
  1760. STORAGE_ADAPTER_DESCRIPTOR sad;
  1761. PAGED_CODE();
  1762. //
  1763. // Assume success.
  1764. //
  1765. status = STATUS_SUCCESS;
  1766. //
  1767. // Get parameters from the IRP.
  1768. //
  1769. irpSp = IoGetCurrentIrpStackLocation( Irp );
  1770. query = (PSTORAGE_PROPERTY_QUERY)Irp->AssociatedIrp.SystemBuffer;
  1771. queryLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  1772. //
  1773. // Get the device extension pointer.
  1774. //
  1775. commonExtension = DeviceObject->DeviceExtension;
  1776. busExtension = DeviceObject->DeviceExtension;
  1777. diskExtension = DeviceObject->DeviceExtension;
  1778. //
  1779. // We don't support mask queries.
  1780. //
  1781. if ( query->QueryType >= PropertyMaskQuery ) {
  1782. status = STATUS_INVALID_PARAMETER_1;
  1783. Irp->IoStatus.Information = 0;
  1784. } else {
  1785. //
  1786. // Dispatch based on the property ID.
  1787. //
  1788. switch ( query->PropertyId ) {
  1789. case StorageDeviceProperty:
  1790. //
  1791. // Make sure this is a target device.
  1792. //
  1793. if ( commonExtension->DeviceType != RamdiskDeviceTypeDiskPdo ) {
  1794. status = STATUS_INVALID_DEVICE_REQUEST;
  1795. Irp->IoStatus.Information = 0;
  1796. break;
  1797. }
  1798. //
  1799. // If it's a just query for whether the property exists, the
  1800. // answer is yes.
  1801. //
  1802. if ( query->QueryType == PropertyExistsQuery ) {
  1803. break;
  1804. }
  1805. //
  1806. // Build a full return buffer. The output buffer might not be
  1807. // big enough to hold the whole thing.
  1808. //
  1809. RtlZeroMemory( &sdd, sizeof(sdd) );
  1810. sdd.Version = sizeof(sdd);
  1811. sdd.DeviceType = DIRECT_ACCESS_DEVICE;
  1812. sdd.RemovableMedia = (diskExtension->Options.Fixed ? FALSE : TRUE);
  1813. sdd.CommandQueueing = FALSE;
  1814. sdd.BusType = BusTypeUnknown;
  1815. length = sizeof(sdd) +
  1816. ((strlen(VER_COMPANYNAME_STR) + 1 +
  1817. strlen(RAMDISK_DISK_DEVICE_TEXT_ANSI) + 1) * sizeof(CHAR));
  1818. sdd.Size = length;
  1819. //
  1820. // Zero the output buffer.
  1821. //
  1822. storageDeviceDescriptor = Irp->AssociatedIrp.SystemBuffer;
  1823. RtlZeroMemory( storageDeviceDescriptor, queryLength );
  1824. //
  1825. // Copy the base part of the return descriptor to the output
  1826. // buffer.
  1827. //
  1828. RtlCopyMemory(
  1829. storageDeviceDescriptor,
  1830. &sdd,
  1831. min( queryLength, sizeof(sdd) )
  1832. );
  1833. //
  1834. // If there's no room for the rest of the data, we're done.
  1835. //
  1836. if ( queryLength <= sizeof(sdd) ) {
  1837. Irp->IoStatus.Information = queryLength;
  1838. break;
  1839. }
  1840. //
  1841. // Copy as much of the rest of the data as will fit.
  1842. //
  1843. offset = sizeof(sdd);
  1844. p = (PUCHAR)storageDeviceDescriptor + offset;
  1845. length = (strlen(VER_COMPANYNAME_STR) + 1) * sizeof(CHAR);
  1846. if ( (offset + length) > queryLength ) {
  1847. Irp->IoStatus.Information = offset;
  1848. break;
  1849. }
  1850. storageDeviceDescriptor->VendorIdOffset = offset;
  1851. memcpy( p, VER_COMPANYNAME_STR, length );
  1852. offset += length;
  1853. p += length;
  1854. length = (strlen(RAMDISK_DISK_DEVICE_TEXT_ANSI) + 1) * sizeof(CHAR);
  1855. if ( (offset + length) > queryLength ) {
  1856. Irp->IoStatus.Information = offset;
  1857. break;
  1858. }
  1859. storageDeviceDescriptor->ProductIdOffset = offset;
  1860. memcpy( p, RAMDISK_DISK_DEVICE_TEXT_ANSI, length );
  1861. offset += length;
  1862. p += length;
  1863. storageDeviceDescriptor->ProductRevisionOffset = 0;
  1864. storageDeviceDescriptor->SerialNumberOffset = 0;
  1865. storageDeviceDescriptor->Size = offset;
  1866. Irp->IoStatus.Information = offset;
  1867. break;
  1868. case StorageAdapterProperty:
  1869. //
  1870. // If this is a target device then forward it down to the
  1871. // underlying device object. This lets filters do their magic.
  1872. //
  1873. if ( commonExtension->DeviceType == RamdiskDeviceTypeDiskPdo ) {
  1874. //
  1875. // Call the lower device.
  1876. //
  1877. IoReleaseRemoveLock( &commonExtension->RemoveLock, Irp );
  1878. IoSkipCurrentIrpStackLocation( Irp );
  1879. return IoCallDriver( commonExtension->LowerDeviceObject, Irp );
  1880. }
  1881. //
  1882. // If it's a just query for whether the property exists, the
  1883. // answer is yes.
  1884. //
  1885. if ( query->QueryType == PropertyExistsQuery ) {
  1886. break;
  1887. }
  1888. //
  1889. // Build a full return buffer. The output buffer might not be
  1890. // big enough to hold the whole thing.
  1891. //
  1892. RtlZeroMemory( &sad, sizeof(sad) );
  1893. sad.Version = sizeof(sad);
  1894. sad.Size = sizeof(sad);
  1895. sad.MaximumTransferLength = 0xFFFFFFFF;
  1896. sad.MaximumPhysicalPages = 0xFFFFFFFF;
  1897. sad.AlignmentMask = 1;
  1898. sad.AdapterUsesPio = FALSE;
  1899. sad.AdapterScansDown = FALSE;
  1900. sad.CommandQueueing = FALSE;
  1901. sad.AcceleratedTransfer = TRUE;
  1902. sad.BusType = BusTypeUnknown;
  1903. sad.BusMajorVersion = VER_PRODUCTMAJORVERSION;
  1904. sad.BusMinorVersion = VER_PRODUCTMINORVERSION;
  1905. //
  1906. // Zero the output buffer.
  1907. //
  1908. storageAdapterDescriptor = Irp->AssociatedIrp.SystemBuffer;
  1909. RtlZeroMemory( storageAdapterDescriptor, queryLength );
  1910. //
  1911. // Copy the base part of the return descriptor to the output
  1912. // buffer.
  1913. //
  1914. RtlCopyMemory(
  1915. storageAdapterDescriptor,
  1916. &sad,
  1917. min( queryLength, sizeof(sad) )
  1918. );
  1919. Irp->IoStatus.Information = min( queryLength, sizeof(sad) );
  1920. break;
  1921. case StorageDeviceIdProperty:
  1922. //
  1923. // Make sure this is a target device.
  1924. //
  1925. if ( commonExtension->DeviceType != RamdiskDeviceTypeDiskPdo ) {
  1926. status = STATUS_INVALID_DEVICE_REQUEST;
  1927. Irp->IoStatus.Information = 0;
  1928. break;
  1929. }
  1930. //
  1931. // We don't support this property.
  1932. //
  1933. status = STATUS_NOT_SUPPORTED;
  1934. Irp->IoStatus.Information = 0;
  1935. break;
  1936. default:
  1937. //
  1938. // If this is a target device, then some filter beneath us may
  1939. // handle this property.
  1940. //
  1941. if ( commonExtension->DeviceType == RamdiskDeviceTypeDiskPdo ) {
  1942. //
  1943. // Call the lower device.
  1944. //
  1945. IoReleaseRemoveLock( &commonExtension->RemoveLock, Irp );
  1946. IoSkipCurrentIrpStackLocation( Irp );
  1947. return IoCallDriver( commonExtension->LowerDeviceObject, Irp );
  1948. }
  1949. //
  1950. // Nope, this property really doesn't exist.
  1951. //
  1952. status = STATUS_INVALID_PARAMETER_1;
  1953. Irp->IoStatus.Information = 0;
  1954. break;
  1955. }
  1956. }
  1957. //
  1958. // At this point, we have not sent the IRP down to a lower device, so
  1959. // we need to complete it now.
  1960. //
  1961. ASSERT( status != STATUS_PENDING );
  1962. IoReleaseRemoveLock( &commonExtension->RemoveLock, Irp );
  1963. Irp->IoStatus.Status = status;
  1964. IoCompleteRequest( Irp, IO_DISK_INCREMENT );
  1965. return status;
  1966. } // RamdiskQueryProperty