#include "RemovableDriveManager.hpp" #include <iostream> #include <stdio.h> #include "boost/nowide/convert.hpp" #if _WIN32 #include <windows.h> #include <tchar.h> #include <winioctl.h> #include <shlwapi.h> DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED); #else //linux includes #include <errno.h> #include <sys/mount.h> #include <sys/stat.h> #include <glob.h> #include <libgen.h> #endif namespace Slic3r { namespace GUI { std::vector<DriveData> RemovableDriveManager::m_current_drives; std::vector<std::function<void()>> RemovableDriveManager::m_callbacks; #if _WIN32 void RemovableDriveManager::search_for_drives() { m_current_drives.clear(); m_current_drives.reserve(26); DWORD drives_mask = GetLogicalDrives(); for (size_t i = 0; i < 26; i++) { if(drives_mask & (1 << i)) { std::string path (1,(char)('A' + i)); path+=":"; UINT drive_type = GetDriveTypeA(path.c_str()); //std::cout << "found drive" << (char)('A' + i) << ": type:" <<driveType << "\n"; if (drive_type == DRIVE_REMOVABLE) { // get name of drive std::wstring wpath = std::wstring(path.begin(), path.end()); std::wstring volume_name; volume_name.resize(1024); std::wstring file_system_name; file_system_name.resize(1024); LPWSTR lp_volume_name_buffer = new wchar_t; BOOL error = GetVolumeInformationW(wpath.c_str(), &volume_name[0], sizeof(volume_name), NULL, NULL, NULL, &file_system_name[0], sizeof(file_system_name)); if(error != 0) { if (volume_name == L"") { volume_name = L"REMOVABLE DRIVE"; } if (file_system_name != L"") { ULARGE_INTEGER free_space; GetDiskFreeSpaceExA(path.c_str(), &free_space, NULL, NULL); //std::cout << std::string(volumeName.begin(), volumeName.end()) << " " << std::string(fileSystemName.begin(), fileSystemName.end()) << " " << freeSpace.QuadPart << "\n"; if (free_space.QuadPart > 0) { m_current_drives.push_back(DriveData(boost::nowide::narrow(volume_name), path)); } } } } } } //std::cout << "found drives:" << m_current_drives.size() << "\n"; } void RemovableDriveManager::eject_drive(const std::string &path) { //if (!update() || !is_drive_mounted(path)) if(m_current_drives.empty()) return; for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) { if ((*it).path == path) { std::string mpath = "\\\\.\\" + path; HANDLE handle = CreateFileA(mpath.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); if (handle == INVALID_HANDLE_VALUE) { std::cerr << "Ejecting " << mpath << " failed " << GetLastError() << " \n"; return; } DWORD deviceControlRetVal(0); BOOL error = DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr); CloseHandle(handle); if (error == 0) { std::cerr << "Ejecting " << mpath << " failed " << deviceControlRetVal << " " << GetLastError() << " \n"; } m_current_drives.erase(it); break; } } } bool RemovableDriveManager::is_path_on_removable_drive(const std::string &path) { if (m_current_drives.empty()) return false; int letter = PathGetDriveNumberA(path.c_str()); for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) { char drive = (*it).path[0]; if (drive == ('A' + letter)) return true; } return false; } void RemovableDriveManager::register_window() { /* WNDCLASSEX wndClass; wndClass.cbSize = sizeof(WNDCLASSEX); wndClass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; wndClass.hInstance = reinterpret_cast<HINSTANCE>(GetModuleHandle(0)); wndClass.lpfnWndProc = reinterpret_cast<WNDPROC>(WinProcCallback); wndClass.cbClsExtra = 0; wndClass.cbWndExtra = 0; wndClass.hIcon = LoadIcon(0, IDI_APPLICATION); wndClass.hbrBackground = CreateSolidBrush(RGB(192, 192, 192)); wndClass.hCursor = LoadCursor(0, IDC_ARROW); wndClass.lpszClassName = L"SlicerWindowClass"; wndClass.lpszMenuName = NULL; wndClass.hIconSm = wndClass.hIcon; */ } #else void RemovableDriveManager::search_for_drives() { struct stat buf; std::string path(std::getenv("USER")); std::string pp(path); m_current_drives.clear(); m_current_drives.reserve(26); //search /media/* folder stat("/media/",&buf); //std::cout << "/media ID: " <<buf.st_dev << "\n"; search_path("/media/*", buf.st_dev); //search /media/USERNAME/* folder pp = "/media/"+pp; path = "/media/" + path + "/*"; stat(pp.c_str() ,&buf); //std::cout << pp <<" ID: " <<buf.st_dev << "\n"; search_path(path, buf.st_dev); //search /run/media/USERNAME/* folder path = "/run" + path; pp = "/run"+pp; stat(pp.c_str() ,&buf); //std::cout << pp <<" ID: " <<buf.st_dev << "\n"; search_path(path, buf.st_dev); //std::cout << "found drives:" <<m_current_drives.size() << "\n"; } void RemovableDriveManager::search_path(const std::string &path,const dev_t &parentDevID) { glob_t globbuf; globbuf.gl_offs = 2; //std::cout<<"searching "<<path<<"\n"; int error = glob(path.c_str(), GLOB_TILDE, NULL, &globbuf); if(error) { //std::cout<<"glob error "<< error<< "\n"; }else { for(size_t i = 0; i < globbuf.gl_pathc; i++) { //std::cout<<globbuf.gl_pathv[i]<<"\n"; //TODO check if mounted std::string name = basename(globbuf.gl_pathv[i]); //std::cout<<name<<"\n"; struct stat buf; stat(globbuf.gl_pathv[i],&buf); //std::cout << buf.st_dev << "\n"; if(buf.st_dev != parentDevID)// not same file system { m_current_drives.push_back(DriveData(name,globbuf.gl_pathv[i])); } } } globfree(&globbuf); } void RemovableDriveManager::eject_drive(const std::string &path) { if (m_current_drives.empty()) return; for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) { if((*it).path == path) { //std::cout<<"Ejecting "<<(*it).name<<" from "<< (*it).path<<"\n"; int error = umount2(path.c_str(),MNT_DETACH); if(error) { int errsv = errno; std::cerr<<"Ejecting failed Error "<< errsv<<"\n"; } m_current_drives.erase(it); break; } } } bool RemovableDriveManager::is_path_on_removable_drive(const std::string &path) { if (m_current_drives.empty()) return false; struct stat path_buf; stat(path.c_str(), &path_buf); for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) { struct stat drive_buf; stat((*it).path.c_str(), &drive_buf); if(drive_buf.st_dev == path_buf.st_dev) return true; } return false; } #endif bool RemovableDriveManager::update(long time) { static long last_update = 0; if(last_update == 0) { //add_callback(std::bind(&RemovableDriveManager::print, RemovableDriveManager::getInstance())); add_callback([](void) { print(); }); #if _WIN32 register_window(); #endif } if(time != 0) //time = 0 is forced update { long diff = last_update - time; if(diff <= -2) { last_update = time; }else { return false; // return value shouldnt matter if update didnt run } } //std::cout << "RDM update " << last_update <<"\n"; search_for_drives(); check_and_notify(); return !m_current_drives.empty(); } bool RemovableDriveManager::is_drive_mounted(const std::string &path) { for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it) { if ((*it).path == path) { return true; } } return false; } std::string RemovableDriveManager::get_last_drive_path() { if (!m_current_drives.empty()) { #if _WIN32 return m_current_drives.back().path + "\\"; #else return m_current_drives.back().path; #endif } return ""; } std::vector<DriveData> RemovableDriveManager::get_all_drives() { return m_current_drives; } void RemovableDriveManager::check_and_notify() { static int number_of_drives = 0; if(number_of_drives != m_current_drives.size()) { for (auto it = m_callbacks.begin(); it != m_callbacks.end(); ++it) { (*it)(); } number_of_drives = m_current_drives.size(); } } void RemovableDriveManager::add_callback(std::function<void()> callback) { m_callbacks.push_back(callback); } void RemovableDriveManager::print() { std::cout << "notified\n"; } }}//namespace Slicer::Gui::