PrusaSlicer-NonPlainar/src/slic3r/GUI/RemovableDriveManager.cpp

331 lines
8.6 KiB
C++
Raw Normal View History

2019-11-26 13:19:29 +00:00
#include "RemovableDriveManager.hpp"
#include <iostream>
2019-11-27 10:33:36 +00:00
#include "boost/nowide/convert.hpp"
2019-11-26 13:19:29 +00:00
2019-11-26 14:52:18 +00:00
#if _WIN32
#include <windows.h>
#include <tchar.h>
2019-11-27 10:33:36 +00:00
#include <winioctl.h>
2019-11-27 12:30:45 +00:00
#include <shlwapi.h>
2019-11-26 13:19:29 +00:00
DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE,
0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED);
2019-11-26 14:52:18 +00:00
#else
//linux includes
#include <errno.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <glob.h>
#include <libgen.h>
2019-11-28 15:35:22 +00:00
#include <pwd.h>
2019-11-26 14:52:18 +00:00
#endif
2019-11-26 13:19:29 +00:00
namespace Slic3r {
namespace GUI {
2019-11-28 12:50:58 +00:00
//std::vector<DriveData> RemovableDriveManager::m_current_drives;
//std::vector<std::function<void()>> RemovableDriveManager::m_callbacks;
2019-11-28 12:38:08 +00:00
2019-11-26 14:52:18 +00:00
#if _WIN32
2019-11-27 10:33:36 +00:00
void RemovableDriveManager::search_for_drives()
2019-11-26 13:19:29 +00:00
{
2019-11-27 10:33:36 +00:00
m_current_drives.clear();
m_current_drives.reserve(26);
2019-11-27 13:30:10 +00:00
DWORD drives_mask = GetLogicalDrives();
2019-11-26 13:19:29 +00:00
for (size_t i = 0; i < 26; i++)
{
2019-11-27 13:30:10 +00:00
if(drives_mask & (1 << i))
2019-11-26 13:19:29 +00:00
{
std::string path (1,(char)('A' + i));
path+=":";
2019-11-27 13:30:10 +00:00
UINT drive_type = GetDriveTypeA(path.c_str());
2019-11-26 13:19:29 +00:00
//std::cout << "found drive" << (char)('A' + i) << ": type:" <<driveType << "\n";
2019-11-27 13:30:10 +00:00
if (drive_type == DRIVE_REMOVABLE)
2019-11-26 13:19:29 +00:00
{
// get name of drive
std::wstring wpath = std::wstring(path.begin(), path.end());
2019-11-27 13:30:10 +00:00
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));
2019-11-26 13:19:29 +00:00
if(error != 0)
{
2019-11-27 13:30:10 +00:00
if (volume_name == L"")
2019-11-26 13:19:29 +00:00
{
2019-11-27 13:30:10 +00:00
volume_name = L"REMOVABLE DRIVE";
2019-11-26 13:19:29 +00:00
}
2019-11-27 13:30:10 +00:00
if (file_system_name != L"")
2019-11-26 13:19:29 +00:00
{
2019-11-27 13:30:10 +00:00
ULARGE_INTEGER free_space;
GetDiskFreeSpaceExA(path.c_str(), &free_space, NULL, NULL);
2019-11-26 13:19:29 +00:00
//std::cout << std::string(volumeName.begin(), volumeName.end()) << " " << std::string(fileSystemName.begin(), fileSystemName.end()) << " " << freeSpace.QuadPart << "\n";
2019-11-27 13:30:10 +00:00
if (free_space.QuadPart > 0)
2019-11-26 13:19:29 +00:00
{
2019-11-27 13:30:10 +00:00
m_current_drives.push_back(DriveData(boost::nowide::narrow(volume_name), path));
2019-11-26 13:19:29 +00:00
}
}
}
}
}
}
2019-11-28 12:38:08 +00:00
//std::cout << "found drives:" << m_current_drives.size() << "\n";
2019-11-26 13:19:29 +00:00
}
2019-11-27 10:33:36 +00:00
void RemovableDriveManager::eject_drive(const std::string &path)
2019-11-26 13:19:29 +00:00
{
2019-11-27 10:33:36 +00:00
//if (!update() || !is_drive_mounted(path))
if(m_current_drives.empty())
2019-11-26 13:19:29 +00:00
return;
2019-11-27 10:33:36 +00:00
for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it)
2019-11-26 13:19:29 +00:00
{
if ((*it).path == path)
{
2019-11-27 10:33:36 +00:00
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);
2019-11-27 13:30:10 +00:00
if (error == 0)
{
2019-11-27 10:33:36 +00:00
std::cerr << "Ejecting " << mpath << " failed " << deviceControlRetVal << " " << GetLastError() << " \n";
2019-11-27 13:30:10 +00:00
}
2019-11-27 10:33:36 +00:00
m_current_drives.erase(it);
2019-11-26 13:19:29 +00:00
break;
}
}
}
2019-11-27 13:30:10 +00:00
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;
}
2019-11-28 12:38:08 +00:00
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;
*/
}
2019-11-26 14:52:18 +00:00
#else
2019-11-27 10:33:36 +00:00
void RemovableDriveManager::search_for_drives()
2019-11-26 14:52:18 +00:00
{
2019-11-28 15:35:22 +00:00
2019-11-27 10:33:36 +00:00
m_current_drives.clear();
2019-11-27 13:30:10 +00:00
m_current_drives.reserve(26);
2019-11-26 14:52:18 +00:00
//search /media/* folder
2019-11-28 15:35:22 +00:00
search_path("/media/*", "/media");
2019-11-26 14:52:18 +00:00
2019-11-28 15:35:22 +00:00
std::string path(std::getenv("USER"));
std::string pp(path);
//std::cout << "user: "<< path << "\n";
if(path == "root"){ //if program is run with sudo, we have to search for all users
while (true) {
passwd* entry = getpwent();
if (!entry) {
break;
}
path = entry->pw_name;
pp = path;
//search /media/USERNAME/* folder
pp = "/media/"+pp;
path = "/media/" + path + "/*";
search_path(path, pp);
2019-11-26 14:52:18 +00:00
2019-11-28 15:35:22 +00:00
//search /run/media/USERNAME/* folder
path = "/run" + path;
pp = "/run"+pp;
search_path(path, pp);
}
endpwent();
}else
{
//search /media/USERNAME/* folder
pp = "/media/"+pp;
path = "/media/" + path + "/*";
search_path(path, pp);
2019-11-26 14:52:18 +00:00
2019-11-28 15:35:22 +00:00
//search /run/media/USERNAME/* folder
path = "/run" + path;
pp = "/run"+pp;
search_path(path, pp);
2019-11-26 14:52:18 +00:00
2019-11-28 15:35:22 +00:00
}
std::cout << "found drives:" <<m_current_drives.size() << "\n";
2019-11-26 14:52:18 +00:00
}
2019-11-28 15:35:22 +00:00
void RemovableDriveManager::search_path(const std::string &path,const std::string &parent_path)
2019-11-26 14:52:18 +00:00
{
glob_t globbuf;
globbuf.gl_offs = 2;
int error = glob(path.c_str(), GLOB_TILDE, NULL, &globbuf);
2019-11-28 15:35:22 +00:00
if(error == 0)
2019-11-26 14:52:18 +00:00
{
2019-11-27 13:30:10 +00:00
for(size_t i = 0; i < globbuf.gl_pathc; i++)
2019-11-26 14:52:18 +00:00
{
2019-11-28 15:35:22 +00:00
//if not same file system - could be removable drive
if(!compare_filesystem_id(globbuf.gl_pathv[i], parent_path))
2019-11-27 13:30:10 +00:00
{
2019-11-28 15:35:22 +00:00
std::string name = basename(globbuf.gl_pathv[i]);
2019-11-27 13:30:10 +00:00
m_current_drives.push_back(DriveData(name,globbuf.gl_pathv[i]));
}
2019-11-26 14:52:18 +00:00
}
2019-11-28 15:35:22 +00:00
}else
{
//if error - path probably doesnt exists so function just exits
//std::cout<<"glob error "<< error<< "\n";
2019-11-26 14:52:18 +00:00
}
2019-11-27 13:30:10 +00:00
2019-11-26 14:52:18 +00:00
globfree(&globbuf);
}
2019-11-27 13:30:10 +00:00
2019-11-28 15:35:22 +00:00
bool RemovableDriveManager::compare_filesystem_id(const std::string &path_a, const std::string &path_b)
{
struct stat buf;
stat(path_a.c_str() ,&buf);
dev_t id_a = buf.st_dev;
stat(path_b.c_str() ,&buf);
dev_t id_b = buf.st_dev;
return id_a == id_b;
}
2019-11-27 10:33:36 +00:00
void RemovableDriveManager::eject_drive(const std::string &path)
2019-11-26 14:52:18 +00:00
{
2019-11-27 10:33:36 +00:00
if (m_current_drives.empty())
2019-11-26 14:52:18 +00:00
return;
2019-11-27 10:33:36 +00:00
for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it)
2019-11-26 14:52:18 +00:00
{
if((*it).path == path)
{
2019-11-28 15:35:22 +00:00
std::cout<<"Ejecting "<<(*it).name<<" from "<< (*it).path<<"\n";
2019-11-26 14:52:18 +00:00
int error = umount2(path.c_str(),MNT_DETACH);
if(error)
{
int errsv = errno;
std::cerr<<"Ejecting failed Error "<< errsv<<"\n";
}
2019-11-27 10:33:36 +00:00
m_current_drives.erase(it);
2019-11-26 14:52:18 +00:00
break;
}
}
}
2019-11-27 13:30:10 +00:00
bool RemovableDriveManager::is_path_on_removable_drive(const std::string &path)
{
if (m_current_drives.empty())
return false;
for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it)
{
2019-11-28 15:35:22 +00:00
if(compare_filesystem_id(path, (*it).path))
2019-11-27 13:30:10 +00:00
return true;
}
return false;
}
2019-11-26 14:52:18 +00:00
#endif
2019-11-27 14:47:37 +00:00
bool RemovableDriveManager::update(long time)
2019-11-26 14:52:18 +00:00
{
2019-11-28 12:38:08 +00:00
static long last_update = 0;
if(last_update == 0)
{
//add_callback(std::bind(&RemovableDriveManager::print, RemovableDriveManager::getInstance()));
2019-11-28 12:50:58 +00:00
add_callback([](void) { RemovableDriveManager::get_instance().print(); });
2019-11-28 12:38:08 +00:00
#if _WIN32
register_window();
#endif
}
2019-11-27 14:47:37 +00:00
if(time != 0) //time = 0 is forced update
{
2019-11-28 12:38:08 +00:00
long diff = last_update - time;
2019-11-27 14:47:37 +00:00
if(diff <= -2)
{
2019-11-28 12:38:08 +00:00
last_update = time;
2019-11-27 14:47:37 +00:00
}else
{
return false; // return value shouldnt matter if update didnt run
}
}
2019-11-28 12:38:08 +00:00
//std::cout << "RDM update " << last_update <<"\n";
2019-11-27 10:33:36 +00:00
search_for_drives();
2019-11-28 12:38:08 +00:00
check_and_notify();
2019-11-28 15:35:22 +00:00
eject_drive(m_current_drives.back().path);
2019-11-27 10:33:36 +00:00
return !m_current_drives.empty();
2019-11-26 14:52:18 +00:00
}
2019-11-27 10:33:36 +00:00
bool RemovableDriveManager::is_drive_mounted(const std::string &path)
2019-11-26 14:52:18 +00:00
{
2019-11-27 10:33:36 +00:00
for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it)
2019-11-26 14:52:18 +00:00
{
if ((*it).path == path)
{
return true;
}
}
return false;
}
2019-11-27 10:33:36 +00:00
std::string RemovableDriveManager::get_last_drive_path()
2019-11-26 13:19:29 +00:00
{
2019-11-27 10:33:36 +00:00
if (!m_current_drives.empty())
2019-11-26 13:19:29 +00:00
{
2019-11-27 12:30:45 +00:00
#if _WIN32
return m_current_drives.back().path + "\\";
#else
2019-11-27 10:33:36 +00:00
return m_current_drives.back().path;
2019-11-27 12:30:45 +00:00
#endif
2019-11-26 13:19:29 +00:00
}
return "";
}
2019-11-27 10:33:36 +00:00
std::vector<DriveData> RemovableDriveManager::get_all_drives()
2019-11-26 13:19:29 +00:00
{
2019-11-27 10:33:36 +00:00
return m_current_drives;
2019-11-26 13:19:29 +00:00
}
2019-11-28 12:38:08 +00:00
void RemovableDriveManager::check_and_notify()
{
2019-11-28 15:35:22 +00:00
static size_t number_of_drives = 0;
2019-11-28 12:38:08 +00:00
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";
}
2019-11-27 12:30:45 +00:00
}}//namespace Slicer::Gui::