16.7 Handling Removable Media

NT file systems and removable-media device drivers share the responsibility for ensuring that the correct media is mounted when a file is opened on a removable-media device and that the correct media remains mounted during operations that access the media. Any NT intermediate driver layered between such a file system and removable-media device driver also shares this responsiblity.

Responding to FS-Initiated Check-Verify Requests

At its discretion, the file system can send an IRP to the device driver's Dispatch entry point for IRP_MJ_DEVICE_CONTROL requests with Parameters.DeviceIoControl.IoControlCode in the I/O stack location set to the following:

IOCTL_XXX_CHECK_VERIFY

where XXX is the type of device, such as DISK, TAPE, or CDROM.

The type DISK includes both unpartitionable (floppy) and partitionable removable-media devices.

If the underlying device driver determines that the media has not changed, the driver should complete the IRP, returning the IoStatus block with the following values:

Status set to STATUS_SUCCESS
Information set to zero

In addition, if the device type is DISK or CDROM and the caller specified an output buffer, the driver returns the media change count in the buffer at
Irp->AssociatedSystemBuffer and sets IoStatus.Information to sizeof(ULONG). By returning this count the driver gives the caller an opportunity to determine whether the media has changed from its perspective.

If the underlying device driver determines that the media has changed, it should do the following:

·If the volume is mounted (the VPB_MOUNTED flag is set in the VPB):

1.Set the Flags in the DeviceObject by ORing Flags with DO_VERIFY_VOLUME.

2.Set the IoStatus block in the IRP to the following:

Status STATUS_VERIFY_REQUIRED

Information zero

3.Call IoCompleteRequest with the input IRP.

·If the volume is not mounted, the driver must not set the DO_VERIFY_VOLUME bit. The driver should set IoStatus.Status to STATUS_IO_DEVICE_ERROR, set IoStatus.Information to zero, and call IoCompleteRequest with the IRP.

Notifying the File System of Possible Media Changes

An NT removable-media device driver must ensure that the media is not changed for the device represented by the DeviceObject (input to every driver routine that is sent an IRP) whenever the driver processes an IRP that requests a transfer to/from the media or a device I/O control operation that affects the media. The best possible time to check for changed media is just after the transition from a no-media-present state to a media-present state if the physical device always notifies the driver about these state changes.

If its physical device indicates that the state of the media might have changed before the driver begins an I/O operation or during an operation, the driver must do the following:

1.Ensure that the volume is mounted by checking the VPB_MOUNTED flag in the VPB. (If the volume is not mounted, the driver must not set the DO_VERIFY_VOLUME bit. The driver should set IoStatus.Status to STATUS_VERIFY_REQUIRED, set IoStatus.Information to zero, and call IoCompleteRequest with the IRP.)

2.Set the Flags in the DeviceObject by ORing Flags with DO_VERIFY_VOLUME.

3.Set the IoStatus block in the IRP to the following:

Status STATUS_VERIFY_REQUIRED

Information zero

4.Before completing any IRP with an IoStatus block in which the Status field is not set to STATUS_SUCCESS, the driver must call IoIsErrorUserInduced, which returns a Boolean TRUE for any of the following Status values:

STATUS_VERIFY_REQUIRED
STATUS_NO_MEDIA_IN_DEVICE
STATUS_WRONG_VOLUME
STATUS_UNRECOGNIZED_MEDIA
STATUS_MEDIA_WRITE_PROTECTED
STATUS_IO_TIMEOUT
STATUS_DEVICE_NOT_READY

If IoIsErrorUserInduced returns TRUE, the driver must call IoSetHardErrorOrVerifyDevice so the FSD can send a popup to the user, who can then supply the correct media, decide to retry the original request, or decide to cancel the requested operation.

Checking the DeviceObject->Flags

For each IRP requesting an I/O operation to/from removable media, a removable-media device driver must determine whether DO_VERIFY_VOLUME is already set in its DeviceObject->Flags. If this value is set, the driver must do the following:

·For IRP_MJ_READ, IRP_MJ_WRITE, and certain IRP_MJ_DEVICE_CONTROL requests, check whether the I/O stack location Flags is set with SL_OVERRIDE_VERIFY_VOLUME. If it is, continue the requested operation.

Device control request that return information about the logical structure of the underlying media have SL_OVERRIDE_VERIFY_VOLUME set in the I/O stack location Flags when an IFS mounts or remounts a removable-media volume.

·Otherwise, the driver must refuse to carry out I/O requests for the corresponding drive, device, or partition while DO_VERIFY_VOLUME is set in its DeviceObject->Flags. A removable media driver must fail IRPs sent to the corresponding device as described in the preceding subsection, repeating both Steps 2 and 3 for each IRP until the FSD clears DO_VERIFY_VOLUME in the removable-media driver's DeviceObject->Flags.

Otherwise, if a removable-media device driver neglects to fail IRPs when DO_VERIFY_VOLUME is set and SL_OVERRIDE_VERIFY_VOLUME is not set for the preceding transfer requests, the file system can neither maintain the integrity of cached file data nor cause the user to be prompted to remount the media that holds an open file.

Setting up IRPs in Intermediate Drivers

Any intermediate driver layered between an NT file system driver and a removable-media device driver must set up the next-lower-level driver's I/O stack location in IRPs. From incoming IRP_MJ_READ, IRP_MJ_WRITE, and IRP_MJ_DEVICE_CONTROL requests, such an intermediate driver must copy its own I/O stack location Flags into the next-lower-level driver's I/O stack location when it sets up the I/O stack location for the lower driver.

If such an intermediate driver allocates new IRPs for lower-level removable-media drivers, it must set up the IRPs it allocates as follows:

·For transfer requests, it must set up the thread context in each driver-allocated IRP from the value at Tail.Overlay.Thread in the original IRP.

·For IRP_MJ_READ, IRP_MJ_WRITE, and IRP_MJ_DEVICE_CONTROL requests, it must copy the I/O stack location Flags from the original IRP to each driver-allocated IRP.

Otherwise, the file system can neither maintain the integrity of cached file data nor cause the user to be prompted to remount the media that holds an open file.