/*
 * Remove the devices that are no longer present in the system.
 */
int checkDiscoveryRemoveDevices() {
    int i;
    struct FreespaceDeviceStruct* list[FREESPACE_MAXIMUM_DEVICE_COUNT];
    int listLength = 0;

    // Collect the removed devices.
    freespace_private_filterDevices(list, FREESPACE_MAXIMUM_DEVICE_COUNT, &listLength, filterSweep);

    // Remove them from the device list so that future API calls fail to this device
    // fail. See callbacks after this loop.
    for (i = 0; i < listLength; i++) {
        int idx;
        DEBUG_WPRINTF(L"device %d removed\n", list[i]->id_);
        for (idx = 0; idx < freespace_instance_->deviceCount_; idx++) {
            if (list[i] == freespace_instance_->devices_[idx]) {
                memmove(&freespace_instance_->devices_[idx], &freespace_instance_->devices_[idx + 1], (freespace_instance_->deviceCount_ - idx - 1) * sizeof(struct FreespaceDeviceStruct*));
                freespace_instance_->deviceCount_--;
            }
        }
    }

    // Call the removal callbacks.
    for (i = 0; i < listLength; i++) {
        freespace_private_removeDevice(list[i]);
    }

    // Free the device structure.
    for (i = 0; i < listLength; i++) {
        freespace_private_freeDevice(list[i]);
    }

    return listLength;
}
/**
 * Handle the case where the device unexpectedly fails.
 * @param device The device the failed.
 * @param ec The error code from GetLastError()
 * @return The device error code.
 */
int handleDeviceFailure(struct FreespaceDeviceStruct* device, int ec) {
    int rc = FREESPACE_ERROR_UNEXPECTED;
    int formatRc = 0;
    LPVOID lpMsgBuf;

    // Retrieve the system error message for the last-error code
    formatRc = FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | 
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        ec,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR) &lpMsgBuf,
        0, NULL );
    if (formatRc == 0) {
        DEBUG_WPRINTF(L"handleDeviceFailure: %d\n", ec);
    } else {
        // Display the error message and exit the process
        DEBUG_WPRINTF(L"handleDeviceFailure: %d => %s\n", ec, lpMsgBuf);
        LocalFree(lpMsgBuf);
    }

    // Clean up this device.
    freespace_private_removeDevice(device);
    freespace_private_forceCloseDevice(device);
    freespace_private_requestDeviceRescan();

    if (ec == ERROR_DEVICE_NOT_CONNECTED) {
        rc = FREESPACE_ERROR_NOT_FOUND;
    }

    return rc;
}
/*
 * Process devices with multiple handles that are not fully complete.
 */
int checkDiscoveryPartiallyRemovedDevices() {
    struct FreespaceDeviceStruct* list[FREESPACE_MAXIMUM_DEVICE_COUNT];
    int listLength = 0;
    int i;

    // Collect the removed devices and call the removed callbacks.
    freespace_private_filterDevices(list, FREESPACE_MAXIMUM_DEVICE_COUNT, &listLength, filterPartiallyRemoved);
    for (i = 0; i < listLength; i++) {
        DEBUG_WPRINTF(L"device %d partially removed\n", list[i]->id_);
    }
    for (i = 0; i < listLength; i++) {
        freespace_private_removeDevice(list[i]);
    }

    // Close file handles of devices that are open.
    for (i = 0; i < listLength; i++) {
        freespace_closeDevice(list[i]->id_);
    }

    return listLength;
}