host/common/volumemonitor.cpp (625 lines of code) (raw):

// Copyright (c) 2005 InMage. // This file contains proprietary and confidential information and // remains the unpublished property of InMage. Use, // disclosure, or reproduction is prohibited except as permitted // by express written license agreement with InMage. // // File : volumemonitor.cpp // // Description: // #ifndef INITGUID #define INITGUID #endif #include <windows.h> #include <winioctl.h> #include <dbt.h> #include <iostream> #include <ioevent.h> #include <sstream> #include <process.h> #include <iomanip> #include <devguid.h> #include <exception> #include <boost/shared_ptr.hpp> #include <boost/bind.hpp> #include "hostagenthelpers_ported.h" #include "portablehelpersmajor.h" #include "volumemonitor.h" Lockable VolumeMonitor::SyncLock; std::string const VolumeDeviceInterfaceName("VolumeDeviceInterface"); std::string const UsbDeviceInterfaceName("UsbDeviceInterface"); // ---------------------------------------------------------------------------- // trace support // ---------------------------------------------------------------------------- // #define SIMPLE_TRACE_ON #ifdef SIMPLE_TRACE_ON #define SIMPLE_TRACE(msg) \ do { \ std::ostringstream o; \ o << msg; \ OutputDebugString(o.str().c_str()); \ } while(0); #else #define SIMPLE_TRACE(msg) #endif // ------------------------------------------- // VolumeMonitor::SimpleLock // ------------------------------------------- /* VolumeMonitor::SimpleLock::SimpleLock() { m_Lock = CreateMutex(0, false, 0); } VolumeMonitor::SimpleLock::~SimpleLock() { if (0 != m_Lock) { CloseHandle(m_Lock); } } bool VolumeMonitor::SimpleLock::Lock() { DebugPrintf(SV_LOG_DEBUG,"ENTERED %s\n",FUNCTION_NAME); if (WAIT_OBJECT_0 == WaitForSingleObject(m_Lock, INFINITE)) { DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); return true; } else { DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); return false; } } void VolumeMonitor::SimpleLock::Unlock() { DebugPrintf(SV_LOG_DEBUG,"ENTERED %s\n",FUNCTION_NAME); ReleaseMutex(m_Lock); DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); } */ // ------------------------------------------- // VolumeMonitor::SimpleEvent // ------------------------------------------- VolumeMonitor::SimpleEvent::SimpleEvent() { m_Event = CreateEvent(0, FALSE, FALSE, "SimpleEvent"); } VolumeMonitor::SimpleEvent::~SimpleEvent() { if (0 != m_Event) { CloseHandle(m_Event); } } bool VolumeMonitor::SimpleEvent::Wait() { DebugPrintf(SV_LOG_DEBUG,"ENTERED %s\n",FUNCTION_NAME); bool ok = false; if (0 != m_Event) { if (WAIT_OBJECT_0 == WaitForSingleObject(m_Event, INFINITE)) { ok = true; } else { ok = false; } } DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); return ok; } void VolumeMonitor::SimpleEvent::Set() { SetEvent(m_Event); } // ------------------------------------------- // VolumeMonitor // ------------------------------------------- VolumeMonitor::~VolumeMonitor() { Stop(); if (0 != m_Window) { DestroyWindow(m_Window); } if (0 != m_Atom) { UnregisterClass((LPCTSTR)m_Atom, GetModuleHandle(NULL)); } if (0 != m_Thread) { CloseHandle(m_Thread); } } bool VolumeMonitor::Register() { DebugPrintf(SV_LOG_DEBUG,"ENTERED %s\n",FUNCTION_NAME); bool ok = false; if (m_Registered) { ok = true; } else { if (ERROR_SUCCESS == CreateNotificationWindow()) { ok = Register(m_Window, DEVICE_NOTIFY_WINDOW_HANDLE); m_ClientSignal = true; } } // let caller know registration is done. // neded in case this is being done in a seperate thread Signal(); DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); return ok; } bool VolumeMonitor::Register(HANDLE h, DWORD handleType) { DebugPrintf(SV_LOG_DEBUG,"ENTERED %s\n",FUNCTION_NAME); /* if (!Lock()) { DebugPrintf(SV_LOG_ERROR, "VolumeMonitor::Register Lock failed: %d\n", GetLastError()); DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); return false; } */ AutoLock LockSection(SyncLock); // boost::shared_ptr<void> guard((void*)NULL, boost::bind<void>(&VolumeMonitor::Unlock, this)); bool ok = true; m_RegisterHandle = h; m_RegisterHandleType = handleType; // register for volume interface Monitor DEV_BROADCAST_DEVICEINTERFACE interfaceFilter; ZeroMemory(&interfaceFilter, sizeof(interfaceFilter)); interfaceFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); interfaceFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; interfaceFilter.dbcc_classguid = GUID_DEVINTERFACE_VOLUME; HDEVNOTIFY notify = RegisterDeviceNotification(m_RegisterHandle, &interfaceFilter, m_RegisterHandleType); if (0 == notify) { DebugPrintf(SV_LOG_ERROR, "VolumeMonitor::Register RegisterDeviceNotification DBT_DEVTYP_DEVICEINTERFACE GUID_DEVINTERFACE_VOLUME failed: %d\n", GetLastError()); DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); return false; } m_Monitors.insert(MONITOR_PAIR(notify, VolumeState(VolumeDeviceInterfaceName, GUID_IO_VOLUME_MOUNT))); // now set up for usb ZeroMemory(&interfaceFilter, sizeof(interfaceFilter)); interfaceFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); interfaceFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; interfaceFilter.dbcc_classguid = GUID_DEVCLASS_USB; notify = RegisterDeviceNotification(m_RegisterHandle, &interfaceFilter, m_RegisterHandleType); if (0 == notify) { DebugPrintf(SV_LOG_ERROR, "VolumeMonitor::Register RegisterDeviceNotification DBT_DEVTYP_DEVICEINTERFACE GUID_DEVCLASS_USB failed: %d\n", GetLastError()); DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); return false; } m_Monitors.insert(MONITOR_PAIR(notify, VolumeState(UsbDeviceInterfaceName, GUID_IO_VOLUME_MOUNT))); // Unlock(); DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); return RegisterDrives(); } bool VolumeMonitor::ReregisterAll() { DebugPrintf(SV_LOG_DEBUG,"ENTERED %s\n",FUNCTION_NAME); // clear all registations and get new notification objects m_Registered = false; UnregisterAll(); m_Monitors.clear(); DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); return Register(m_RegisterHandle, m_RegisterHandleType); } bool VolumeMonitor::UnregisterAll() { DebugPrintf(SV_LOG_DEBUG,"ENTERED %s\n",FUNCTION_NAME); // Lock(); AutoLock LockSection(SyncLock); // boost::shared_ptr<void> guard((void*)NULL, boost::bind<void>(&VolumeMonitor::Unlock, this)); bool ok = true; for (MONITORS::iterator iter = m_Monitors.begin(); iter != m_Monitors.end(); ++iter) { if (!UnregisterDeviceNotification((*iter).first)) { DebugPrintf(SV_LOG_ERROR, "VolumeMonitor::UnregisterAll UnregisterDeviceNotification for device %s failed: %d\n", (*iter).second.Device().c_str(), GetLastError()); ok = false; } } DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); return ok; } void VolumeMonitor::UnregisterDriveLetter(char drive) { DebugPrintf(SV_LOG_DEBUG,"ENTERED %s\n",FUNCTION_NAME); SIMPLE_TRACE("VolumeMonitor::UnregisterDrive\n"); /* if (!Lock()) { DebugPrintf(SV_LOG_ERROR, "VolumeMonitor::UnregisterDriveLetter Lock failed: %d\n", GetLastError()); DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); return; } */ AutoLock LockSection(SyncLock); char guid[128]; char name[4] = { 'A', ':', '\\', '\0' }; name[0] = drive; if (!GetVolumeNameForVolumeMountPoint(name, guid, sizeof(guid) - 1)) { DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); return; } for (MONITORS::iterator iter = m_Monitors.begin(); iter != m_Monitors.end(); ++iter) { if ((*iter).second.Device() == guid) { if (!UnregisterDeviceNotification((*iter).first)) { DebugPrintf(SV_LOG_ERROR, "VolumeMonitor::UnregisterDriveLetter UnregisterDeviceNotification for device %s failed: %d\n", (*iter).second.Device().c_str(), GetLastError()); } m_Monitors.erase(iter); break; } } //Unlock(); DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); } bool VolumeMonitor::RegisterDrives() { DebugPrintf(SV_LOG_DEBUG,"ENTERED %s\n",FUNCTION_NAME); bool ok = true; char volName[MAX_PATH]; HANDLE h = FindFirstVolume(volName, sizeof(volName) -1); if (INVALID_HANDLE_VALUE == h) { DebugPrintf(SV_LOG_ERROR, "VolumeMonitor::RegisterDrives FindFirstVolume failed: %d\n", GetLastError()); return false; } boost::shared_ptr<void> guard((void*)NULL, boost::bind<BOOL>(FindVolumeClose, h)); do { if (DRIVE_FIXED == GetDriveType(volName)) { // need to replace the '?' with '.' and remove the trailing '\' so RegisterDevice can open the volume volName[2] = '.'; volName[strlen(volName)-1] = '\0'; if (!RegisterDevice(volName)) { ok = false; } } } while (FindNextVolume(h, volName, sizeof(volName) - 1)); DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); return ok; } bool VolumeMonitor::RegisterDriveLetter(char drive) { DebugPrintf(SV_LOG_DEBUG,"ENTERED %s\n",FUNCTION_NAME); char guid[128]; char name[4] = { 'A', ':', '\\', '\0' }; name[0] = drive; if (!GetVolumeNameForVolumeMountPoint(name, guid, sizeof(guid) - 1)) { DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); return false; } // need to replace the '?' with '.' and remove the trailing '\' so RegisterDevice can open the volume guid[2] = '.'; guid[strlen(guid)-1] = '\0'; DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); return RegisterDevice(guid); } bool VolumeMonitor::RegisterVolume(char const * volume) { DebugPrintf(SV_LOG_DEBUG,"ENTERED %s\n",FUNCTION_NAME); char name[1024]; inm_sprintf_s(name, ARRAYSIZE(name), "%s", volume); DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); return RegisterDevice(name); } bool VolumeMonitor::RegisterDevice(char const * name) { DebugPrintf(SV_LOG_DEBUG,"ENTERED %s\n",FUNCTION_NAME); bool ok = true; // PR#10815: Long Path support HANDLE hFile = SVCreateFile(name, 0, //QUERY is good enough FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hFile) { unsigned long rc = GetLastError(); if (ERROR_UNRECOGNIZED_VOLUME != rc) { DebugPrintf(SV_LOG_ERROR, "VolumeMonitor::RegisterDevice open file %s failed: %d\n", name, GetLastError()); } DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); return false; } DEV_BROADCAST_HANDLE handleFilter; ZeroMemory(&handleFilter, sizeof(handleFilter)); handleFilter.dbch_size = sizeof(DEV_BROADCAST_HANDLE); handleFilter.dbch_devicetype = DBT_DEVTYP_HANDLE; handleFilter.dbch_handle = hFile; HDEVNOTIFY notify = RegisterDeviceNotification(m_RegisterHandle, &handleFilter, m_RegisterHandleType); if (0 == notify) { DebugPrintf(SV_LOG_ERROR, "VolumeMonitor::RegisterDevice RegisterDeviceNotification for %s failed: %d\n", name, GetLastError()); ok = false; } else { /* if (!Lock()) { DebugPrintf(SV_LOG_ERROR, "VolumeMonitor::RegisterDevice Lock failed: %d\n", GetLastError()); ok = false; } else*/ AutoLock LockSection(SyncLock); // { m_Monitors.insert(MONITOR_PAIR(notify, VolumeState(name, GUID_IO_VOLUME_MOUNT))); //Unlock(); // } } CloseHandle(hFile); DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); return ok; } bool VolumeMonitor::Process(WPARAM wparam, LPARAM lparam) { DebugPrintf(SV_LOG_DEBUG,"ENTERED %s\n",FUNCTION_NAME); bool callRegisterHost = false; try { SIMPLE_TRACE("VolumeMonitor::Process\n"); switch (wparam) { case DBT_CUSTOMEVENT: SIMPLE_TRACE("VolumeMonitor DBT_CUSTOMEVENT\n"); if ( true == (callRegisterHost = ProcessCustomEvent((DEV_BROADCAST_HDR*)lparam))) SignalClientIfRequired(); break; case DBT_DEVICEARRIVAL: SIMPLE_TRACE("VolumeMonitor DBT_DEVICEARRIVAL\n"); if ( true == (callRegisterHost = ProcessArrival((DEV_BROADCAST_HDR*)lparam))) SignalClientIfRequired(); break; case DBT_DEVICEQUERYREMOVEFAILED: SIMPLE_TRACE("VolumeMonitor DBT_DEVICEQUERYREMOVEFAILED\n"); break; case DBT_DEVICEREMOVECOMPLETE: SIMPLE_TRACE("VolumeMonitor DBT_DEVICEREMOVECOMPLETE\n"); if ( true == (callRegisterHost = ProcessRemoveComplete((DEV_BROADCAST_HDR*)lparam))) SignalClientIfRequired(); break; case DBT_DEVICEREMOVEPENDING: SIMPLE_TRACE("VolumeMonitor DBT_DEVICEREMOVEPENDING\n"); break; case DBT_DEVICETYPESPECIFIC: SIMPLE_TRACE("VolumeMonitor DBT_DEVICETYPESPECIFIC\n"); // TODO: // may need to process this, if so, it would be more or less the same as DBT_CUSTOMEVENT break; case DBT_DEVNODES_CHANGED: SIMPLE_TRACE("VolumeMonitor DBT_DEVNODES_CHANGED\n"); break; case DBT_USERDEFINED: SIMPLE_TRACE("VolumeMonitor DBT_USERDEFINED\n"); break; case DBT_CONFIGCHANGECANCELED: SIMPLE_TRACE("VolumeMonitor DBT_CONFIGCHANGECANCELED\n"); break; case DBT_CONFIGCHANGED: SIMPLE_TRACE("VolumeMonitor DBT_CONFIGCHANGED\n"); break; case DBT_DEVICEQUERYREMOVE: SIMPLE_TRACE("VolumeMonitor DBT_DEVICEQUERYREMOVE\n"); break; default: SIMPLE_TRACE("VolumeMonitor default\n"); break; } } catch (std::exception const & e) { DebugPrintf(SV_LOG_ERROR, "VolumeMonitor::Process failed: %s\n", e.what()); callRegisterHost = true; // play it safe force a registration SignalClientIfRequired(); } catch (...) { DebugPrintf(SV_LOG_ERROR, "VolumeMonitor::Process failed with unknown exception\n"); callRegisterHost = true; // play it safe force a registration SignalClientIfRequired(); } DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); return callRegisterHost; } bool VolumeMonitor::ProcessCustomEvent(DEV_BROADCAST_HDR* hdr) { if (0 == hdr || DBT_DEVTYP_HANDLE != hdr->dbch_devicetype) { return false; } /* if (!Lock()) { DebugPrintf(SV_LOG_ERROR, "VolumeMonitor::ProcessCustomEvent Lock failed: %d\n", GetLastError()); return false; } */ AutoLock LockSection(SyncLock); DEV_BROADCAST_HANDLE* notify = (DEV_BROADCAST_HANDLE*)hdr; SIMPLE_TRACE("VolumeMonitor::ProcessCustomEvent GUID:" << std::hex << notify->dbch_eventguid.Data1 << '-' << notify->dbch_eventguid.Data2 << '-' << notify->dbch_eventguid.Data3 << '-' << std::setfill('0') << std::setw(2) << (unsigned)notify->dbch_eventguid.Data4[0] << std::setfill('0') << std::setw(2) << (unsigned)notify->dbch_eventguid.Data4[1] << std::setfill('0') << std::setw(2) << (unsigned)notify->dbch_eventguid.Data4[2] << std::setfill('0') << std::setw(2) << (unsigned)notify->dbch_eventguid.Data4[3] << std::setfill('0') << std::setw(2) << (unsigned)notify->dbch_eventguid.Data4[4] << std::setfill('0') << std::setw(2) << (unsigned)notify->dbch_eventguid.Data4[5] << std::setfill('0') << std::setw(2) << (unsigned)notify->dbch_eventguid.Data4[6] << std::setfill('0') << std::setw(2) << (unsigned)notify->dbch_eventguid.Data4[7] << '\n'); bool callRegisterHost = false; MONITORS::iterator iter = m_Monitors.find(notify->dbch_hdevnotify); if (iter != m_Monitors.end()) { SIMPLE_TRACE("VolumeMonitor::ProcessCustomEvent current state:" << std::hex << (*iter).second.State().Data1 << '-' << (*iter).second.State().Data2 << '-' << (*iter).second.State().Data3 << '-' << std::setfill('0') << std::setw(2) << (unsigned)(*iter).second.State().Data4[0] << std::setfill('0') << std::setw(2) << (unsigned)(*iter).second.State().Data4[1] << std::setfill('0') << std::setw(2) << (unsigned)(*iter).second.State().Data4[2] << std::setfill('0') << std::setw(2) << (unsigned)(*iter).second.State().Data4[3] << std::setfill('0') << std::setw(2) << (unsigned)(*iter).second.State().Data4[4] << std::setfill('0') << std::setw(2) << (unsigned)(*iter).second.State().Data4[5] << std::setfill('0') << std::setw(2) << (unsigned)(*iter).second.State().Data4[6] << std::setfill('0') << std::setw(2) << (unsigned)(*iter).second.State().Data4[7] << '\n'); if ((IsEqualGUID(GUID_IO_VOLUME_NAME_CHANGE, notify->dbch_eventguid) && !IsEqualGUID(GUID_IO_VOLUME_NAME_CHANGE, (*iter).second.State())) || (IsEqualGUID(GUID_IO_VOLUME_CHANGE, notify->dbch_eventguid)) || (IsEqualGUID(GUID_IO_VOLUME_FVE_STATUS_CHANGE, notify->dbch_eventguid))) { std::string vol((*iter).second.Device()); vol += "\\"; int type = GetDriveType(vol.c_str()); if (DRIVE_FIXED == type) { SIMPLE_TRACE("VolumeMonitor::ProcessCustomEvent need to register host: volume: " << vol[0] << '\n'); callRegisterHost = true; if (IsEqualGUID(GUID_IO_VOLUME_FVE_STATUS_CHANGE, notify->dbch_eventguid)) SignalBitlockerEventToClient(); } } (*iter).second.SetState(notify->dbch_eventguid); } //Unlock(); return callRegisterHost; } bool VolumeMonitor::ProcessArrival(DEV_BROADCAST_HDR* hdr) { DebugPrintf(SV_LOG_DEBUG,"ENTERED %s\n",FUNCTION_NAME); if (0 == hdr) { return false; } SIMPLE_TRACE("VolumeMonitor::ProcessArrival device type: " << hdr->dbch_devicetype << '\n'); switch (hdr->dbch_devicetype ) { case DBT_DEVTYP_VOLUME: { DEV_BROADCAST_VOLUME* notify = (DEV_BROADCAST_VOLUME*)hdr; SIMPLE_TRACE("VolumeMonitor::ProcessArrival DBT_DEVTYP_VOLUME flag: " << notify->dbcv_flags << " unitmask: " << notify->dbcv_unitmask << '\n'); if (DBTF_MEDIA != notify->dbcv_flags && DBTF_NET != notify->dbcv_flags) { // for a DISK // get drive letter for (int i = 0; i < 26; ++i) { if (notify->dbcv_unitmask & (1 << i)) { RegisterDriveLetter((char)(i + 'A')); SIMPLE_TRACE("VolumeMonitor::ProcessArrival need to register host\n"); DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); return true; } } } } break; case DBT_DEVTYP_DEVICEINTERFACE: { DEV_BROADCAST_DEVICEINTERFACE* notify = (DEV_BROADCAST_DEVICEINTERFACE*)hdr; SIMPLE_TRACE("VolumeMonitor::ProcessArrival DBT_DEVTYP_DEVICEINTERFACE class guid: " << std::hex << notify->dbcc_classguid.Data1 << '-' << notify->dbcc_classguid.Data2 << '-' << notify->dbcc_classguid.Data3 << '-' << std::setfill('0') << std::setw(2) << (unsigned)notify->dbcc_classguid.Data4[0] << std::setfill('0') << std::setw(2) << (unsigned)notify->dbcc_classguid.Data4[1] << std::setfill('0') << std::setw(2) << (unsigned)notify->dbcc_classguid.Data4[2] << std::setfill('0') << std::setw(2) << (unsigned)notify->dbcc_classguid.Data4[3] << std::setfill('0') << std::setw(2) << (unsigned)notify->dbcc_classguid.Data4[4] << std::setfill('0') << std::setw(2) << (unsigned)notify->dbcc_classguid.Data4[5] << std::setfill('0') << std::setw(2) << (unsigned)notify->dbcc_classguid.Data4[6] << std::setfill('0') << std::setw(2) << (unsigned)notify->dbcc_classguid.Data4[7] << '\n'); if (GUID_DEVINTERFACE_VOLUME == notify->dbcc_classguid) { SIMPLE_TRACE("VolumeMonitor::ProcessArrival need to register host\n"); // since it is too much work to figure out which volume this is, just use brute force and redo everything. ReregisterAll(); RegisterVolume(notify->dbcc_name); DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); return true; } } break; default: break; } DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); return false; } bool VolumeMonitor::ProcessRemoveComplete(DEV_BROADCAST_HDR* hdr) { if (0 == hdr) { return false; } SIMPLE_TRACE("VolumeMonitor::ProcessRemoveComplete device type: " << hdr->dbch_devicetype << '\n'); switch (hdr->dbch_devicetype ) { case DBT_DEVTYP_VOLUME: { DEV_BROADCAST_VOLUME* notify = (DEV_BROADCAST_VOLUME*)hdr; SIMPLE_TRACE("VolumeMonitor::ProcessRemoveComplete DBT_DEVTYP_VOLUME flag: " << notify->dbcv_flags << " unitmask: " << notify->dbcv_unitmask << '\n'); if (DBTF_MEDIA != notify->dbcv_flags && DBTF_NET != notify->dbcv_flags) { for (int i = 0; i < 26; ++i) { if (notify->dbcv_unitmask & (1 << i)) { UnregisterDriveLetter((char)(i + 'A')); SIMPLE_TRACE("VolumeMonitor::ProcessRemoveComplete need to register host volume: " << (char)(i + 'A') << '\n'); return true; } } } } break; case DBT_DEVTYP_DEVICEINTERFACE: { DEV_BROADCAST_DEVICEINTERFACE* notify = (DEV_BROADCAST_DEVICEINTERFACE*)hdr; SIMPLE_TRACE("VolumeMonitor::ProcessRemoveComplete DEV_BROADCAST_DEVICEINTERFACE class guid: " << std::hex << notify->dbcc_classguid.Data1 << '-' << notify->dbcc_classguid.Data2 << '-' << notify->dbcc_classguid.Data3 << '-' << std::setfill('0') << std::setw(2) << std::setfill('0') << std::setw(2) << (unsigned)notify->dbcc_classguid.Data4[0] << std::setfill('0') << std::setw(2) << (unsigned)notify->dbcc_classguid.Data4[1] << std::setfill('0') << std::setw(2) << (unsigned)notify->dbcc_classguid.Data4[2] << std::setfill('0') << std::setw(2) << (unsigned)notify->dbcc_classguid.Data4[3] << std::setfill('0') << std::setw(2) << std::setfill('0') << std::setw(2) << (unsigned)notify->dbcc_classguid.Data4[4] << std::setfill('0') << std::setw(2) << (unsigned)notify->dbcc_classguid.Data4[5] << std::setfill('0') << std::setw(2) << (unsigned)notify->dbcc_classguid.Data4[6] << std::setfill('0') << std::setw(2) << (unsigned)notify->dbcc_classguid.Data4[7] << '\n'); if (GUID_DEVINTERFACE_VOLUME == notify->dbcc_classguid) { SIMPLE_TRACE("VolumeMonitor::ProcessRemoveComplete need to register host\n"); // since it is too much work to figure out which volume this is, just use brute force and redo everything. ReregisterAll(); return true; } } break; default: break; } return false; } bool VolumeMonitor::DriveOnline(char c) { DebugPrintf(SV_LOG_DEBUG,"ENTERED %s\n",FUNCTION_NAME); bool ok = false; /* if (!Lock()) { DebugPrintf(SV_LOG_ERROR, "VolumeMonitor::DriveOnline Lock failed: %d\n", GetLastError()); } else */ AutoLock LockSection(SyncLock); { for (MONITORS::iterator iter = m_Monitors.begin(); iter != m_Monitors.end(); ++iter) { if (1 == (*iter).second.Device().size() && c == (*iter).second.Device()[0]) { if (IsEqualGUID(GUID_IO_VOLUME_MOUNT, (*iter).second.State())) { ok = true; break; } } } //Unlock(); } DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); return ok; } DWORD VolumeMonitor::CreateNotificationWindow() { DebugPrintf(SV_LOG_DEBUG,"ENTERED %s\n",FUNCTION_NAME); DWORD result = ERROR_SUCCESS; char* className = "VolumeNotificationWindow"; WNDCLASSEX wc; ZeroMemory(&wc, sizeof(wc)); wc.cbSize = sizeof(wc); wc.lpfnWndProc = VolumeMonitor::NotifyWindowProc; // DefWindowProc; wc.lpszClassName = className; m_Atom = RegisterClassEx(&wc); if (0 == m_Atom) { result = GetLastError(); } else { m_Window = CreateWindow(className, "VolumeNotificationWindow", WS_OVERLAPPEDWINDOW, 0, 0, 300, 300, 0, 0, 0, 0); if (0 == m_Window) { result = GetLastError(); } else { SetLastError(0); if (!SetWindowLongPtr(m_Window, GWLP_USERDATA, (LONG_PTR)this)) { result = GetLastError(); } } } DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); return result; } bool VolumeMonitor::Start(HANDLE serviceHandle, DWORD type) { DebugPrintf(SV_LOG_DEBUG,"ENTERED %s\n",FUNCTION_NAME); bool ok = false; try { if (m_Registered) { ok = true; } else { ok = Register(serviceHandle, type); } } catch (std::exception const & e) { DebugPrintf(SV_LOG_ERROR, "VolumeMonitor::Start failed: %d\n", e.what()); ok = false; } catch (...) { DebugPrintf(SV_LOG_ERROR, "VolumeMonitor::Start failed with unknown exception\n"); ok = false; } DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); return ok; } bool VolumeMonitor::Start() { DebugPrintf(SV_LOG_DEBUG,"ENTERED %s\n",FUNCTION_NAME); bool ok = true; if (0 == m_ThreadId) { m_Thread = (HANDLE)_beginthreadex(0, 0, VolumeMonitor::MonitorThread, (void*)this, 0, &m_ThreadId); // m_Thread = CreateThread(NULL, 0, VolumeMonitor::MonitorThread, this, 0, &m_ThreadId); if (0 == m_Thread) { ok = false; DebugPrintf(SV_LOG_ERROR, "VolumeMonitor::Start Error creating cluster monitor thread: %d\n", GetLastError()); } else { // wait for registration to complete ok = Wait(); } } DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); return ok; } void VolumeMonitor::Stop() { DebugPrintf(SV_LOG_DEBUG,"ENTERED %s\n",FUNCTION_NAME); UnregisterAll(); m_Monitors.clear(); if (0 != m_ThreadId) { PostThreadMessage(m_ThreadId, WM_QUIT, 0, 0); WaitForSingleObject(m_Thread, INFINITE); m_ThreadId = 0; CloseHandle(m_Thread); m_Thread = 0; } DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); } unsigned __stdcall VolumeMonitor::MonitorThread(LPVOID pParam) { DebugPrintf(SV_LOG_DEBUG,"ENTERED %s\n",FUNCTION_NAME); try { if (0 != pParam) { VolumeMonitor* volumeMonitor = (VolumeMonitor*) pParam; volumeMonitor->Register(); MSG msg; BOOL ret; do { ret = GetMessage(&msg, (HWND) NULL, 0, 0); if (ret <= 0) { break; } TranslateMessage(&msg); DispatchMessage(&msg); } while (1); } } catch (std::exception const & e) { DebugPrintf(SV_LOG_ERROR, "VolumeMonitor::MonitorThread failed: %d\n", e.what()); DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); return -1; } catch (...) { DebugPrintf(SV_LOG_ERROR, "VolumeMonitor::MonitorThread failed with unknown exception\n"); DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); return -1; } DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); return 0; } LRESULT CALLBACK VolumeMonitor::NotifyWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { DebugPrintf(SV_LOG_DEBUG,"ENTERED %s\n",FUNCTION_NAME); LRESULT result = 0; if (WM_DEVICECHANGE == uMsg) { VolumeMonitor* volumeMonitor = (VolumeMonitor*)GetWindowLongPtr(hwnd, GWLP_USERDATA); if (0 == volumeMonitor) { DebugPrintf(SV_LOG_ERROR, "VolumeMonitor::NotifyWindowProc error geting volumemonitor: %d\n", GetLastError()); } else { volumeMonitor->Process(wParam, lParam); } } else { result = DefWindowProc(hwnd, uMsg, wParam, lParam); } DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); return result; } std::string VolumeMonitor::GetVolumesOnlineAsString() { std::string sVolumes = ""; /* if (!Lock()) { DebugPrintf(SV_LOG_ERROR, "Lock failed: %d\n", GetLastError()); } else */ AutoLock LockSection(SyncLock); { for (MONITORS::iterator iter = m_Monitors.begin(); iter != m_Monitors.end(); ++iter) { if (IsEqualGUID(GUID_IO_VOLUME_MOUNT, (*iter).second.State()) && (*iter).second.Device() != "!" ) { // don't want the interface monitor it's tag is '!' sVolumes += ";" + ((*iter).second.Device()); } } //Unlock(); } return sVolumes; } sigslot::signal1<void*>& VolumeMonitor::getVolumeMonitorSignal() { return m_VolumeMonitorSignal; } void VolumeMonitor::SignalClientIfRequired() { if ( m_ClientSignal ) // Pass NULL for now. Maybe we want to pass the list of modified volumes // or volume list m_VolumeMonitorSignal(NULL); } sigslot::signal1<void*>& VolumeMonitor::getBitlockerMonitorSignal() { return m_BitlockerMonitorSignal; } void VolumeMonitor::SignalBitlockerEventToClient() { if (m_ClientSignal) m_BitlockerMonitorSignal(NULL); }