nsresult
sbWinGetVolumeGUIDPath(DEVINST    aDevInst,
                       nsAString& aVolumeGUIDPath)
{
  BOOL     success;
  nsresult rv;

  // Get the volume device interface path.
  GUID guid = GUID_DEVINTERFACE_VOLUME;
  nsAutoString volumeDeviceInterfacePath;
  rv = sbWinGetDevicePath(aDevInst, &guid, volumeDeviceInterfacePath);
  NS_ENSURE_SUCCESS(rv, rv);

  // Get the volume GUID path.  The mount point must end with "\\".
  static const DWORD volumeGUIDPathLength = 51;
  WCHAR volumeGUIDPath[volumeGUIDPathLength];
  volumeDeviceInterfacePath.AppendLiteral("\\");
  success = GetVolumeNameForVolumeMountPointW(volumeDeviceInterfacePath.get(),
                                              volumeGUIDPath,
                                              volumeGUIDPathLength);
  NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);

  // Return results.
  aVolumeGUIDPath.Assign(volumeGUIDPath);

  return NS_OK;
}
nsresult
sbWinVolumeIsReady(DEVINST aDevInst,
                   PRBool* aIsReady)
{
  // Validate arguments.
  NS_ENSURE_ARG_POINTER(aIsReady);

  // Function variables.
  PRBool   success;
  nsresult rv;

  // Get the volume device interface path.
  GUID guid = GUID_DEVINTERFACE_VOLUME;
  nsAutoString volumeDeviceInterfacePath;
  rv = sbWinGetDevicePath(aDevInst, &guid, volumeDeviceInterfacePath);
  NS_ENSURE_SUCCESS(rv, rv);

  // Try getting the volume GUID path.  If this fails, the volume is not ready.
  static const DWORD volumeGUIDPathLength = 51;
  WCHAR volumeGUIDPath[volumeGUIDPathLength];
  volumeDeviceInterfacePath.AppendLiteral("\\");
  success = GetVolumeNameForVolumeMountPointW(volumeDeviceInterfacePath.get(),
                                              volumeGUIDPath,
                                              volumeGUIDPathLength);
  if (!success) {
    *aIsReady = PR_FALSE;
    return NS_OK;
  }

  // Try getting the volume information.  If this fails, the volume is not
  // ready.
  DWORD fileSystemFlags;
  WCHAR  volumeLabel[MAX_PATH+1];
  WCHAR  fileSystemName[MAX_PATH+1];
  success = GetVolumeInformationW(volumeDeviceInterfacePath.BeginReading(),
                                  volumeLabel,
                                  NS_ARRAY_LENGTH(volumeLabel),
                                  NULL,
                                  NULL,
                                  &fileSystemFlags,
                                  fileSystemName,
                                  NS_ARRAY_LENGTH(fileSystemName));
  if (!success) {
    *aIsReady = PR_FALSE;
    return NS_OK;
  }

  // The volume is ready.
  *aIsReady = PR_TRUE;

  return NS_OK;
}
nsresult
sbWinGetStorageDevNum(DEVINST                aDevInst,
                      const GUID*            aGUID,
                      STORAGE_DEVICE_NUMBER* aStorageDevNum)
{
  // Validate arguments.
  NS_ENSURE_ARG_POINTER(aStorageDevNum);
  NS_ENSURE_ARG_POINTER(aGUID);

  // Function variables.
  nsresult rv;

  // Get the device interface path.
  nsAutoString deviceInterfacePath;
  rv = sbWinGetDevicePath(aDevInst, aGUID, deviceInterfacePath);
  NS_ENSURE_SUCCESS(rv, rv);

  return sbWinGetStorageDevNum(deviceInterfacePath.get(), aStorageDevNum);
}
nsresult
sbWinCreateDeviceFile(HANDLE*               aDevFile,
                      DEVINST               aDevInst,
                      const GUID*           aGUID,
                      DWORD                 aDesiredAccess,
                      DWORD                 aShareMode,
                      LPSECURITY_ATTRIBUTES aSecurityAttributes,
                      DWORD                 aCreationDisposition,
                      DWORD                 aFlagsAndAttributes,
                      HANDLE                aTemplateFile)
{
  // Validate arguments.
  NS_ENSURE_ARG_POINTER(aDevFile);
  NS_ENSURE_ARG_POINTER(aGUID);

  // Function variables.
  nsresult rv;

  // Get the device path.
  nsAutoString devicePath;
  rv = sbWinGetDevicePath(aDevInst, aGUID, devicePath);
  NS_ENSURE_SUCCESS(rv, rv);

  // Create the device file.
  HANDLE devFile = CreateFileW(devicePath.get(),
                               aDesiredAccess,
                               aShareMode,
                               aSecurityAttributes,
                               aCreationDisposition,
                               aFlagsAndAttributes,
                               aTemplateFile);
  NS_ENSURE_TRUE(devFile != INVALID_HANDLE_VALUE, NS_ERROR_FAILURE);

  // Return results.
  *aDevFile = devFile;

  return NS_OK;
}