diff --git a/src/libopensc/reader-pcsc.c b/src/libopensc/reader-pcsc.c index 96ce8ee2..63f388a4 100644 --- a/src/libopensc/reader-pcsc.c +++ b/src/libopensc/reader-pcsc.c @@ -234,41 +234,47 @@ static int refresh_slot_attributes(struct sc_reader *reader, struct sc_slot_info } if (pslot->readerState.dwEventState & SCARD_STATE_PRESENT) { int old_flags = slot->flags; + int maybe_changed = 0; slot->flags |= SC_SLOT_CARD_PRESENT; slot->atr_len = pslot->readerState.cbAtr; if (slot->atr_len > SC_MAX_ATR_SIZE) slot->atr_len = SC_MAX_ATR_SIZE; memcpy(slot->atr, pslot->readerState.rgbAtr, slot->atr_len); + #ifndef _WIN32 - /* If there was a card in the slot previously, and the - * PCSC driver reports a state change, we assume the - * user removed the old card and inserted a new one in the - * meantime. */ - if ((pslot->readerState.dwEventState & SCARD_STATE_CHANGED) - && (old_flags & SC_SLOT_CARD_PRESENT)) - slot->flags |= SC_SLOT_CARD_CHANGED; + /* On Linux, SCARD_STATE_CHANGED always means there was an + * insert or removal. But we may miss events that way. */ + if (pslot->readerState.dwEventState & SCARD_STATE_CHANGED) { + slot->flags |= SC_SLOT_CARD_CHANGED; + } else { + maybe_changed = 1; + } #else -/* The above doesn't work on Win32 because there are other events, - * so this code will set the SC_SLOT_CARD_CHANGED most of the time, - * resulting in a complete re-read of the card. - * So we give the card handle to a function (SCardStatus) and see - * if it returns SCARD_W_REMOVED_CARD. - */ - if ((pslot->readerState.dwEventState & SCARD_STATE_CHANGED) - && (old_flags & SC_SLOT_CARD_PRESENT)) { + /* On windows, SCARD_STATE_CHANGED is turned on by lots of + * other events, so it gives us a lot of false positives. + * But if it's off, there really no change */ + if (pslot->readerState.dwEventState & SCARD_STATE_CHANGED) { + maybe_changed = 1; + } +#endif + /* If we aren't sure if the card state changed, check if + * the card handle is still valid. If the card changed, + * the handle will be invalid. */ + + if (maybe_changed && (old_flags & SC_SLOT_CARD_PRESENT)) { DWORD readers_len = 0, state, prot, atr_len = 32; - byte atr[32]; + unsigned char atr[32]; int rv = SCardStatus(pslot->pcsc_card, NULL, &readers_len, &state, &prot, atr, &atr_len); if (rv == SCARD_W_REMOVED_CARD) slot->flags |= SC_SLOT_CARD_CHANGED; + else + slot->flags &= ~SC_SLOT_CARD_CHANGED; } -#endif } else { slot->flags &= ~(SC_SLOT_CARD_PRESENT|SC_SLOT_CARD_CHANGED); } - return 0; }