/*************************************************************************
* UrBackup - Client/Server backup system
* Copyright (C) 2011-2015 Martin Raiber
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
**************************************************************************/
#include "SetupWizard.h"
#include
#include
#include "stringtools.h"
#ifdef _WIN32
#include
#include
#include
#include
#include
#pragma comment(lib, "netapi32.lib")
#pragma comment(lib, "Userenv.lib")
#endif
#include "Connector.h"
#include "ConfigPath.h"
#include "FileSettingsReader.h"
extern std::string ConvertToUTF8(const std::wstring &input);
extern wxString res_path;
extern wxString ico_ext;
extern wxBitmapType ico_type;
SVolumesCache* SetupWizard::cache = NULL;
namespace
{
#ifdef _WIN32
std::vector get_users()
{
LPUSER_INFO_0 buf;
DWORD prefmaxlen = MAX_PREFERRED_LENGTH;
DWORD entriesread = 0;
DWORD totalentries = 0;
DWORD resume_handle = 0;
NET_API_STATUS status;
std::vector ret;
do
{
status = NetUserEnum(NULL, 0, FILTER_NORMAL_ACCOUNT,
(LPBYTE*)&buf, prefmaxlen, &entriesread,
&totalentries, &resume_handle);
if (status == NERR_Success || status == ERROR_MORE_DATA)
{
for(DWORD i=0;iusri0_name);
}
}
else
{
std::cerr << "Error while enumerating users: "+ nconvert((int)status) << std::endl;
}
if(buf!=NULL)
{
NetApiBufferFree(buf);
}
}
while (status == ERROR_MORE_DATA);
return ret;
}
std::vector getPathsNotToBackup()
{
HKEY FilesNotToBackup;
if(RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\BackupRestore\\FilesNotToBackup",
0, KEY_ENUMERATE_SUB_KEYS|KEY_READ, &FilesNotToBackup)!=ERROR_SUCCESS)
{
std::cerr << "Error opening registry key SYSTEM\\CurrentControlSet\\Control\\BackupRestore\\FilesNotToBackup" << std::endl;
return std::vector();
}
DWORD maxClassLen;
DWORD numValues;
DWORD maxValueKeyLen;
DWORD maxValueLen;
if(RegQueryInfoKey(FilesNotToBackup, NULL, NULL, NULL, NULL, NULL, &maxClassLen, &numValues,
&maxValueKeyLen, &maxValueLen, NULL, NULL)!=ERROR_SUCCESS)
{
std::cerr << "Error getting RegQueryInfoKey" << std::endl;
return std::vector();
}
maxValueKeyLen+=sizeof(wchar_t);
std::wstring keyName;
keyName.resize(maxValueKeyLen);
std::vector ret;
for(DWORD idx=0;idx(&data[0]), &dataLen);
}
if(rc!=ERROR_SUCCESS)
{
std::cerr << "RegEnumValueW has error" << std::endl;
return ret;
}
if(type==REG_EXPAND_SZ || type==REG_SZ)
{
ret.push_back(data);
}
else if(type==REG_MULTI_SZ)
{
Tokenize(data, ret, L"\0");
}
}
return ret;
}
std::vector resolvePaths(const std::vector& paths)
{
std::vector ret;
std::wstring out;
out.resize(32767);
for(size_t i=0;i fixupPaths(std::vector paths)
{
std::wstring userprofile_dir;
HANDLE hUserToken;
if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hUserToken))
{
DWORD dwSize = 0;
GetUserProfileDirectoryW(hUserToken, NULL, &dwSize);
if(dwSize>0)
{
userprofile_dir.resize(dwSize);
if(GetUserProfileDirectoryW(hUserToken, &userprofile_dir[0], &dwSize) && dwSize>0)
{
userprofile_dir.resize(dwSize-1);
}
}
CloseHandle(hUserToken);
}
std::vector users = get_users();
for(size_t i=0, size=paths.size();i::iterator it = cache->is_usb_info.find(path);
if(it!=cache->is_usb_info.end())
{
return it->second;
}
HANDLE hVolume = CreateFileW(path.c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
if ( hVolume != INVALID_HANDLE_VALUE )
{
DWORD dwOutBytes = 0;
STORAGE_PROPERTY_QUERY query;
query.PropertyId = StorageDeviceProperty;
query.QueryType = PropertyStandardQuery;
char buffer[1024] = {};
PSTORAGE_DEVICE_DESCRIPTOR dev_desc = (PSTORAGE_DEVICE_DESCRIPTOR)buffer;
dev_desc->Size = sizeof(buffer);
BOOL b = DeviceIoControl(hVolume,
IOCTL_STORAGE_QUERY_PROPERTY,
&query, sizeof(STORAGE_PROPERTY_QUERY),
dev_desc, dev_desc->Size,
&dwOutBytes,
(LPOVERLAPPED)NULL);
CloseHandle(hVolume);
if ( b )
{
bool is_usb = dev_desc->BusType == BusTypeUsb;
cache->is_usb_info[path] = is_usb;
return is_usb;
}
}
return false;
}
std::string get_all_volumes_list(bool filter_usb, SVolumesCache*& cache)
{
WCHAR vol_name[MAX_PATH] = {};
HANDLE hFind = FindFirstVolumeW(vol_name, ARRAYSIZE(vol_name));
if (hFind == INVALID_HANDLE_VALUE)
{
return "";
}
if(cache==NULL)
{
cache=new SVolumesCache;
}
std::string ret;
while(true)
{
size_t idx = wcslen(vol_name) - 1;
if (vol_name[0] != L'\\' || vol_name[1] != L'\\' ||
vol_name[2] != L'?' || vol_name[3] != L'\\' ||
vol_name[idx] != L'\\' )
{
std::cerr << std::wstring(L"get_all_volumes_list: bad path: ") + vol_name << std::endl;
return "";
}
vol_name[idx] = L'\0';
WCHAR DeviceName[MAX_PATH] = {};
DWORD CharCount = QueryDosDeviceW(&vol_name[4], DeviceName, ARRAYSIZE(DeviceName));
vol_name[idx] = L'\\';
if ( CharCount == 0 )
{
std::cerr << std::wstring(L"QueryDosDeviceW failed with ec = ") + convert(static_cast(GetLastError())) << std::endl;
break;
}
std::wstring new_volume = get_volume_path(vol_name);
if(new_volume.size()==3 && new_volume[1]==':' && new_volume[2]=='\\')
{
std::map::iterator it_ntfs_info = cache->is_ntfs_info.find(new_volume);
std::wstring dev_fn = std::wstring(L"\\\\.\\")+std::wstring(1, new_volume[0])+L":";
if(it_ntfs_info!=cache->is_ntfs_info.end())
{
if(it_ntfs_info->second)
{
if(!filter_usb || !is_usb_disk(dev_fn, cache))
{
if(!ret.empty())
{
ret+=";";
}
ret+=new_volume[0];
}
else if(filter_usb)
{
std::cerr << "Device "+new_volume+" is connected via USB" << std::endl;
}
}
else
{
std::cerr << "Device "+new_volume+" isn't NTFS formatted" << std::endl;
}
}
else
{
bool is_ntfs = false;
wchar_t fs_name[MAX_PATH+1];
if(GetVolumeInformation(new_volume.c_str(), NULL, 0, NULL, NULL, NULL,fs_name,MAX_PATH+1))
{
is_ntfs = strlower(std::wstring(fs_name))=="ntfs";
}
if(is_ntfs)
{
if(!filter_usb || !is_usb_disk(dev_fn, cache))
{
if(!ret.empty())
{
ret+=";";
}
ret+=new_volume[0];
}
else if(!filter_usb)
{
std::cerr << "Device "+new_volume+" is connected via USB" << std::endl;
}
}
cache->is_ntfs_info[new_volume] = is_ntfs;
}
}
BOOL rc = FindNextVolumeW(hFind, vol_name, ARRAYSIZE(vol_name));
if ( !rc )
{
if (GetLastError() != ERROR_NO_MORE_FILES)
{
std::cerr << std::wstring(L"FindNextVolumeW failed with ec = ") + convert(static_cast(GetLastError())) << std::endl;
break;
}
break;
}
}
FindVolumeClose(hFind);
return ret;
}
std::vector volumesToPaths(std::string vols)
{
std::vector toks;
TokenizeMail(vols, toks, ";");
std::vector ret;
for(size_t i=0;i &new_setup_settings, std::string output_fn )
{
std::wstring data;
std::vector keys = setupSettings.getKeys();
for(size_t i=0;i::iterator it = new_setup_settings.find(keys[i]);
if(it==new_setup_settings.end())
{
if(setupSettings.getValue(keys[i], &val))
{
data+=keys[i] + L"=" + val;
}
}
else
{
data+=keys[i] + L"=" + it->second;
new_setup_settings.erase(it);
}
}
for(std::map::iterator it=new_setup_settings.begin();
it!=new_setup_settings.end();++it)
{
if(!data.empty()) data+=L"\n";
data+=it->first+ L"=" + it->second;
}
writestring(ConvertToUTF8(data), output_fn);
}
#endif //_WIN32
}
SetupWizard::SetupWizard( wxWindow* parent )
: GUISetupWizard(parent)
{
SetIcon(wxIcon(res_path+wxT("backup-ok.")+ico_ext, ico_type));
EFileBackupChoice fileBackupChoice;
EImageBackupChoice imageBackupChoice;
std::wstring volume_choice;
bool no_setupwizard;
readConfig(fileBackupChoice, imageBackupChoice, volume_choice, no_setupwizard);
if(fileBackupChoice == EFileBackupChoice_UserFiles)
{
m_radioBtn2->SetValue(true);
}
else if(fileBackupChoice == EFileBackupChoice_Manual)
{
m_radioBtn3->SetValue(true);
}
if(imageBackupChoice == EImageBackupChoice_AllNonUsb)
{
m_radioBtn5->SetValue(true);
}
else if(imageBackupChoice==EImageBackupChoice_Manual)
{
m_radioBtn6->SetValue(true);
m_textCtrl1->Enable();
}
m_textCtrl1->SetValue(volume_choice);
GetPageAreaSizer()->Add(*m_pages.begin());
if(no_setupwizard)
{
Close();
}
}
void SetupWizard::wizardCancel( wxWizardEvent& event )
{
writestring("no_setupwizard=true", "setup_wizard.cfg");
}
void SetupWizard::wizardFinished( wxWizardEvent& event )
{
EFileBackupChoice fileBackupChoice;
if(m_radioBtn1->GetValue())
{
fileBackupChoice = EFileBackupChoice_AllWithoutSystem;
}
else if(m_radioBtn2->GetValue())
{
fileBackupChoice = EFileBackupChoice_UserFiles;
}
else
{
fileBackupChoice = EFileBackupChoice_Manual;
}
EImageBackupChoice imageBackupChoice;
if(m_radioBtn4->GetValue())
{
imageBackupChoice = EImageBackupChoice_System;
}
else if(m_radioBtn5->GetValue())
{
imageBackupChoice = EImageBackupChoice_AllNonUsb;
}
else
{
imageBackupChoice = EImageBackupChoice_Manual;
}
finishSetup(fileBackupChoice, imageBackupChoice, m_textCtrl1->GetValue().ToStdWstring());
if(fileBackupChoice==EFileBackupChoice_Manual)
{
Close();
ConfigPath* cp = new ConfigPath(NULL);
cp->ShowModal();
cp->Destroy();
wxExit();
}
}
void SetupWizard::wizardNext( wxWizardEvent& event )
{
}
void SetupWizard::finishSetup( EFileBackupChoice fileBackupChoice, EImageBackupChoice imageBackupChoice, const std::wstring& volume_choice )
{
#ifdef _WIN32
std::vector pathsNotToBackup = fixupPaths(resolvePaths(getPathsNotToBackup()));
pathsNotToBackup.push_back(L"C:\\Users\\:\\AppData\\Local\\Temp");
pathsNotToBackup.push_back(L"C:\\Users\\:\\AppData\\Local\\Microsoft\\Windows\\Temporary Internet Files");
pathsNotToBackup.push_back(L"C:\\Users\\:\\AppData\\Local\\Google\\Chrome\\User Data\\:\\Cache");
pathsNotToBackup.push_back(L"C:\\Users\\:\\AppData\\Local\\Google\\Chrome\\User Data\\:\\Media Cache");
pathsNotToBackup.push_back(L"C:\\Users\\:\\AppData\\Local\\Google\\Chrome\\User Data\\:\\Code Cache");
pathsNotToBackup.push_back(L"C:\\Users\\:\\AppData\\Local\\Microsoft\\Windows\\Explorer\\thumbcache*");
pathsNotToBackup.push_back(L"C:\\Users\\:\\AppData\\Local\\Mozilla\\Firefox\\Profiles\\:\\cache2");
pathsNotToBackup.push_back(L"C:\\Users\\:\\AppData\\Local\\Mozilla\\Firefox\\Profiles\\:\\cache");
pathsNotToBackup.push_back(L"C:\\Windows\\Temp");
pathsNotToBackup.push_back(L":\\$Recycle.Bin");
pathsNotToBackup.push_back(L":\\System Volume Information");
pathsNotToBackup.push_back(L"C:\\Windows.old");
pathsNotToBackup.push_back(L"C:\\$Windows.~BT");
pathsNotToBackup.push_back(L"C:\\ProgramData\\Microsoft\\Windows Defender\\Scans\\mpcache-*");
std::vector backupPaths;
std::vector includeDirs;
if(fileBackupChoice==EFileBackupChoice_AllWithoutSystem)
{
pathsNotToBackup.push_back(L"C:\\Windows");
pathsNotToBackup.push_back(L"C:\\$GetCurrent");
TCHAR pf[MAX_PATH];
if(SHGetFolderPathW(
0,
CSIDL_PROGRAM_FILES,
NULL,
SHGFP_TYPE_CURRENT,
pf)==S_OK)
{
pathsNotToBackup.push_back(std::wstring(pf));
}
memset(pf, 0, MAX_PATH);
if(SHGetFolderPathW(
0,
CSIDL_PROGRAM_FILESX86,
NULL,
SHGFP_TYPE_CURRENT,
pf)==S_OK)
{
pathsNotToBackup.push_back(std::wstring(pf));
}
memset(pf, 0, MAX_PATH);
if (SHGetFolderPathW(
0,
CSIDL_COMMON_APPDATA,
NULL,
SHGFP_TYPE_CURRENT,
pf) == S_OK)
{
pathsNotToBackup.push_back(std::wstring(pf));
}
backupPaths = volumesToPaths(get_all_volumes_list(false, cache));
}
else if(fileBackupChoice==EFileBackupChoice_UserFiles)
{
backupPaths.push_back(L"C:\\Users");
includeDirs.push_back(L"C:\\Users\\:\\Documents\\*");
includeDirs.push_back(L"C:\\Users\\:\\Pictures\\*");
includeDirs.push_back(L"C:\\Users\\:\\Music\\*");
includeDirs.push_back(L"C:\\Users\\:\\Videos\\*");
includeDirs.push_back(L"C:\\Users\\:\\Desktop\\*");
}
std::wstring backup_volumes;
if(imageBackupChoice==EImageBackupChoice_System)
{
backup_volumes=L"C";
}
else if(imageBackupChoice==EImageBackupChoice_AllNonUsb)
{
backup_volumes = widen(get_all_volumes_list(true, cache));
}
else
{
backup_volumes = volume_choice;
}
wxMilliClock_t starttime = wxGetLocalTimeMillis();
while(!FileExists("urbackup/data/settings.cfg")
&& FileExists("initial_settings.cfg")
&& wxGetLocalTimeMillis()-starttime<2*60*1000)
{
wxMilliSleep(100);
}
CFileSettingsReader setupSettings("setup_wizard.cfg");
CFileSettingsReader backupSettings("urbackup/data/settings.cfg");
std::map new_settings;
std::map new_setup_settings;
if(!backup_volumes.empty())
{
std::wstring curr_images;
std::wstring image_key = L"image_letters";
bool has_image_letters = true;
if(!backupSettings.getValue(image_key, &curr_images))
{
has_image_letters = backupSettings.getValue(image_key+L"_def", &curr_images);
if(has_image_letters) image_key+=L"_def";
}
std::wstring setup_image;
if( (setupSettings.getValue(L"image_letters", &setup_image) &&
setup_image==curr_images ) || !has_image_letters )
{
new_settings[image_key] = backup_volumes;
new_setup_settings[L"image_letters"] = backup_volumes;
}
}
if(!backupPaths.empty())
{
std::wstring new_backupdirs;
for(size_t i=0;i keys = backupSettings.getKeys();
for(size_t i=0;i::iterator it = new_settings.find(keys[i]);
if(it==new_settings.end())
{
if(backupSettings.getValue(keys[i], &val))
{
data+=keys[i] + L"=" + val;
}
}
else
{
data+=keys[i] + L"=" + it->second;
new_settings.erase(it);
}
}
for(std::map::iterator it=new_settings.begin();
it!=new_settings.end();++it)
{
if(!data.empty()) data+=L"\n";
data+=it->first+ L"=" + it->second;
}
if(!Connector::updateSettings(ConvertToUTF8(data), 3*60*1000))
{
std::cerr << "Error saving settings" << std::endl;
}
}
switch(fileBackupChoice)
{
case EFileBackupChoice_AllWithoutSystem:
new_setup_settings[L"FileBackupChoice"] = L"AllWithoutSystem"; break;
case EFileBackupChoice_UserFiles:
new_setup_settings[L"FileBackupChoice"] = L"UserFiles"; break;
case EFileBackupChoice_Manual:
new_setup_settings[L"FileBackupChoice"] = L"Manual"; break;
}
switch(imageBackupChoice)
{
case EImageBackupChoice_AllNonUsb:
new_setup_settings[L"ImageBackupChoice"] = L"AllNonUsb"; break;
case EImageBackupChoice_System:
new_setup_settings[L"ImageBackupChoice"] = L"System"; break;
case EImageBackupChoice_Manual:
new_setup_settings[L"ImageBackupChoice"] = L"Manual";
new_setup_settings[L"VolumeChoice"] = volume_choice;
break;
}
if(!new_setup_settings.empty())
{
rewrite_settings(setupSettings, new_setup_settings, "setup_wizard.cfg");
}
#endif
}
void SetupWizard::doDefConfig()
{
EFileBackupChoice fileBackupChoice;
EImageBackupChoice imageBackupChoice;
std::wstring volume_choice;
bool no_setupwizard;
readConfig(fileBackupChoice, imageBackupChoice, volume_choice, no_setupwizard);
if(!no_setupwizard)
{
finishSetup(fileBackupChoice, imageBackupChoice, volume_choice);
}
}
void SetupWizard::manualVolumeConfig( wxCommandEvent& event )
{
if(m_radioBtn6->GetValue())
{
m_textCtrl1->Enable();
}
else
{
m_textCtrl1->Disable();
}
}
void SetupWizard::readConfig( EFileBackupChoice& fileBackupChoice, EImageBackupChoice& imageBackupChoice, std::wstring& volume_choice, bool& no_setupwizard )
{
CFileSettingsReader setupSettings("setup_wizard.cfg");
std::string str_no_setupwizard;
setupSettings.getValue("no_setupwizard", &str_no_setupwizard);
no_setupwizard = (str_no_setupwizard=="true");
if(no_setupwizard)
{
return;
}
std::wstring lastImageBackupChoice;
std::wstring lastFileBackupChoice;
setupSettings.getValue(L"ImageBackupChoice", &lastImageBackupChoice);
setupSettings.getValue(L"FileBackupChoice", &lastFileBackupChoice);
fileBackupChoice = EFileBackupChoice_AllWithoutSystem; //Default
if(lastFileBackupChoice==L"UserFiles")
{
fileBackupChoice = EFileBackupChoice_UserFiles;
}
else if(lastFileBackupChoice == L"Manual" )
{
fileBackupChoice = EFileBackupChoice_Manual;
}
#ifdef _WIN32
volume_choice = widen(get_all_volumes_list(false, cache));
#endif
if(lastImageBackupChoice==L"AllNonUsb")
{
imageBackupChoice = EImageBackupChoice_AllNonUsb;
}
else if(lastImageBackupChoice==L"Manual")
{
imageBackupChoice = EImageBackupChoice_Manual;
setupSettings.getValue(L"VolumeChoice", &volume_choice);
}
}
bool SetupWizard::runSetupWizard()
{
EFileBackupChoice fileBackupChoice;
EImageBackupChoice imageBackupChoice;
std::wstring volume_choice;
bool no_setupwizard;
readConfig(fileBackupChoice, imageBackupChoice, volume_choice, no_setupwizard);
return !no_setupwizard;
}