diff options
Diffstat (limited to 'shared')
-rw-r--r-- | shared/customComboBox.cpp | 73 | ||||
-rw-r--r-- | shared/customComboBox.h | 29 | ||||
-rw-r--r-- | shared/dllLoader.cpp | 44 | ||||
-rw-r--r-- | shared/dllLoader.h | 40 | ||||
-rw-r--r-- | shared/fileHandling.cpp | 172 | ||||
-rw-r--r-- | shared/globalFunctions.h | 24 | ||||
-rw-r--r-- | shared/inotify/inotify-cxx.cpp | 4 | ||||
-rw-r--r-- | shared/localization.cpp | 12 | ||||
-rw-r--r-- | shared/serialize.cpp | 50 | ||||
-rw-r--r-- | shared/serialize.h | 198 | ||||
-rw-r--r-- | shared/shadow.cpp | 112 | ||||
-rw-r--r-- | shared/shadow.h | 3 | ||||
-rw-r--r-- | shared/standardPaths.cpp | 4 | ||||
-rw-r--r-- | shared/standardPaths.h | 2 | ||||
-rw-r--r-- | shared/zstring.cpp | 65 | ||||
-rw-r--r-- | shared/zstring.h | 3 |
16 files changed, 700 insertions, 135 deletions
diff --git a/shared/customComboBox.cpp b/shared/customComboBox.cpp new file mode 100644 index 00000000..f2eec7a9 --- /dev/null +++ b/shared/customComboBox.cpp @@ -0,0 +1,73 @@ +#include "customComboBox.h" + + +CustomComboBox::CustomComboBox(wxWindow* parent, + wxWindowID id, + const wxString& value, + const wxPoint& pos, + const wxSize& size, + int n, + const wxString choices[], + long style, + const wxValidator& validator, + const wxString& name) : + wxComboBox(parent, id, value, pos, size, n, choices, style, validator, name) +{ + //register key event to enable item deletion + this->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CustomComboBox::OnKeyEvent), NULL, this ); +} + + +void CustomComboBox::OnKeyEvent(wxKeyEvent& event) +{ + const int keyCode = event.GetKeyCode(); + if (keyCode == WXK_DELETE || keyCode == WXK_NUMPAD_DELETE) + { + //try to delete the currently selected config history item + const int selectedItem = this->GetCurrentSelection(); + if (0 <= selectedItem && selectedItem < static_cast<int>(this->GetCount()) && + (GetValue() != GetString(selectedItem) || //avoid problems when letter shall be deleted instead of list item + GetValue() == wxEmptyString) //exception: always allow removing empty entry + ) + { + //save old (selected) value: deletion seems to have influence on this + const wxString currentVal = this->GetValue(); + this->SetSelection(wxNOT_FOUND); + + //delete selected row + this->Delete(selectedItem); + + //(re-)set value + this->SetValue(currentVal); + + //eat up key event + return; + } + } + event.Skip(); +} + + +void CustomComboBox::addPairToFolderHistory(const wxString& newFolder, unsigned int maxHistSize) +{ + const wxString oldVal = this->GetValue(); + + //insert new folder or put it to the front if already existing +#ifdef FFS_WIN //don't respect case in windows build + const int pos = FindString(newFolder, false); +#elif defined FFS_LINUX + const int pos = FindString(newFolder, true); +#endif + if (pos != wxNOT_FOUND) + this->Delete(pos); + + this->Insert(newFolder, 0); + + //keep maximal size of history list + if (this->GetCount() > maxHistSize) + this->Delete(maxHistSize); + + this->SetSelection(wxNOT_FOUND); //don't select anything + this->SetValue(oldVal); //but preserve main text! +} + diff --git a/shared/customComboBox.h b/shared/customComboBox.h new file mode 100644 index 00000000..b6af43bf --- /dev/null +++ b/shared/customComboBox.h @@ -0,0 +1,29 @@ +#ifndef CUSTOMCOMBOBOX_H_INCLUDED +#define CUSTOMCOMBOBOX_H_INCLUDED + +#include <wx/combobox.h> + +//combobox with history function + functionality to delete items (DEL) + +class CustomComboBox : public wxComboBox +{ +public: + CustomComboBox(wxWindow* parent, + wxWindowID id, + const wxString& value = wxEmptyString, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + int n = 0, + const wxString choices[] = (const wxString *) NULL, + long style = 0, + const wxValidator& validator = wxDefaultValidator, + const wxString& name = wxComboBoxNameStr); + + void addPairToFolderHistory(const wxString& newFolder, unsigned int maxHistSize); + +private: + void OnKeyEvent(wxKeyEvent& event); +}; + + +#endif // CUSTOMCOMBOBOX_H_INCLUDED diff --git a/shared/dllLoader.cpp b/shared/dllLoader.cpp new file mode 100644 index 00000000..e37ded54 --- /dev/null +++ b/shared/dllLoader.cpp @@ -0,0 +1,44 @@ +#include "dllLoader.h" +#include <wx/msw/wrapwin.h> //includes "windows.h" + +namespace +{ +class KernelDllHandler //dynamically load "kernel32.dll" +{ +public: + static const KernelDllHandler& getInstance() + { + static KernelDllHandler instance; + return instance; + } + + HINSTANCE getHandle() const + { + return hKernel; + } + +private: + KernelDllHandler() : + hKernel(NULL) + { + //get a handle to the DLL module containing required functionality + hKernel = ::LoadLibrary(L"kernel32.dll"); + } + + ~KernelDllHandler() + { + if (hKernel) ::FreeLibrary(hKernel); + } + + HINSTANCE hKernel; +}; +} + + +void* Utility::loadSymbolKernel(const std::string& functionName) +{ + if (KernelDllHandler::getInstance().getHandle() != NULL) + return reinterpret_cast<void*>(::GetProcAddress(KernelDllHandler::getInstance().getHandle(), functionName.c_str())); + else + return NULL; +} diff --git a/shared/dllLoader.h b/shared/dllLoader.h new file mode 100644 index 00000000..bf62b542 --- /dev/null +++ b/shared/dllLoader.h @@ -0,0 +1,40 @@ +#ifndef DLLLOADER_H_INCLUDED +#define DLLLOADER_H_INCLUDED + +#include <string> + +namespace Utility +{ + //load kernel dll functions +template <typename FunctionType> +FunctionType loadDllFunKernel(const std::string& functionName); + + + + + + + + + + + + + +//---------------Inline Implementation--------------------------------------------------- +void* loadSymbolKernel(const std::string& functionName); + +template <typename FunctionType> +inline +FunctionType loadDllFunKernel(const std::string& functionName) +{ + return reinterpret_cast<FunctionType>(loadSymbolKernel(functionName)); +} + +#ifndef FFS_WIN +use in windows build only! +#endif + +} + +#endif // DLLLOADER_H_INCLUDED diff --git a/shared/fileHandling.cpp b/shared/fileHandling.cpp index 495e3d49..4b9901e0 100644 --- a/shared/fileHandling.cpp +++ b/shared/fileHandling.cpp @@ -11,8 +11,10 @@ #include <wx/log.h> #include <wx/datetime.h> #include "stringConv.h" +#include <wx/utils.h> #ifdef FFS_WIN +#include "dllLoader.h" #include <wx/msw/wrapwin.h> //includes "windows.h" #include "shadow.h" @@ -30,10 +32,70 @@ using FreeFileSync::FileError; +bool replaceMacro(wxString& macro) //macro without %-characters, return true if replaced successfully +{ + if (macro.IsEmpty()) + return false; + + //there are equally named environment variables %TIME%, %DATE% existing, so replace these first! + if (macro.CmpNoCase(wxT("time")) == 0) + { + macro = wxDateTime::Now().FormatISOTime(); + macro.Replace(wxT(":"), wxT("-")); + return true; + } + + if (macro.CmpNoCase(wxT("date")) == 0) + { + macro = wxDateTime::Now().FormatISODate(); + return true; + } + + //try to apply environment variables + wxString envValue; + if (wxGetEnv(macro, &envValue)) + { + macro = envValue; + return true; + } + + return false; +} + + +void expandMacros(wxString& text) +{ + const wxChar SEPARATOR = '%'; + + if (text.Find(SEPARATOR) != wxNOT_FOUND) + { + wxString prefix = text.BeforeFirst(SEPARATOR); + wxString postfix = text.AfterFirst(SEPARATOR); + if (postfix.Find(SEPARATOR) != wxNOT_FOUND) + { + wxString potentialMacro = postfix.BeforeFirst(SEPARATOR); + wxString rest = postfix.AfterFirst(SEPARATOR); //text == prefix + SEPARATOR + potentialMacro + SEPARATOR + rest + + if (replaceMacro(potentialMacro)) + { + expandMacros(rest); + text = prefix + potentialMacro + rest; + } + else + { + rest = wxString() + SEPARATOR + rest; + expandMacros(rest); + text = prefix + SEPARATOR + potentialMacro + rest; + } + } + } +} + + Zstring FreeFileSync::getFormattedDirectoryName(const Zstring& dirname) { //Formatting is needed since functions expect the directory to end with '\' to be able to split the relative names. - //Also improves usability. + //note: don't do directory formatting with wxFileName, as it doesn't respect //?/ - prefix! wxString dirnameTmp = zToWx(dirname); dirnameTmp.Trim(true); //remove whitespace characters from right @@ -46,14 +108,8 @@ Zstring FreeFileSync::getFormattedDirectoryName(const Zstring& dirname) dirnameTmp += zToWx(globalFunctions::FILE_NAME_SEPARATOR); //replace macros - wxString timeNow = wxDateTime::Now().FormatISOTime(); - timeNow.Replace(wxT(":"), wxT("-")); - dirnameTmp.Replace(wxT("%time%"), timeNow.c_str()); - - const wxString dateToday = wxDateTime::Now().FormatISODate(); - dirnameTmp.Replace(wxT("%date%"), dateToday.c_str()); + expandMacros(dirnameTmp); - //don't do directory formatting with wxFileName, as it doesn't respect //?/ - prefix return wxToZ(dirnameTmp); } @@ -717,57 +773,16 @@ void FreeFileSync::copyFileTimes(const Zstring& sourceDir, const Zstring& target #ifdef FFS_WIN -class KernelDllHandler //dynamically load windows API functions -{ - typedef DWORD (WINAPI *GetFinalPath)( - HANDLE hFile, - LPTSTR lpszFilePath, - DWORD cchFilePath, - DWORD dwFlags); - -public: - static const KernelDllHandler& getInstance() //lazy creation of KernelDllHandler - { - static KernelDllHandler instance; - - if (instance.getFinalPathNameByHandle == NULL) - throw FileError(wxString(_("Error loading library function:")) + wxT("\n\"") + wxT("GetFinalPathNameByHandleW") + wxT("\"")); - - return instance; - } - - GetFinalPath getFinalPathNameByHandle; - -private: - KernelDllHandler() : - getFinalPathNameByHandle(NULL), - hKernel(NULL) - { - //get a handle to the DLL module containing required functionality - hKernel = ::LoadLibrary(wxT("kernel32.dll")); - if (hKernel) - getFinalPathNameByHandle = reinterpret_cast<GetFinalPath>(::GetProcAddress(hKernel, "GetFinalPathNameByHandleW")); //load unicode version! - } - - ~KernelDllHandler() - { - if (hKernel) ::FreeLibrary(hKernel); - } - - HINSTANCE hKernel; -}; - - Zstring resolveDirectorySymlink(const Zstring& dirLinkName) //get full target path of symbolic link to a directory { //open handle to target of symbolic link - HANDLE hDir = CreateFile(dirLinkName.c_str(), - 0, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, - NULL); + HANDLE hDir = ::CreateFile(dirLinkName.c_str(), + 0, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL); if (hDir == INVALID_HANDLE_VALUE) return Zstring(); @@ -776,7 +791,20 @@ Zstring resolveDirectorySymlink(const Zstring& dirLinkName) //get full target pa const unsigned int BUFFER_SIZE = 10000; TCHAR targetPath[BUFFER_SIZE]; - const DWORD rv = KernelDllHandler::getInstance().getFinalPathNameByHandle( + + //dynamically load windows API function + typedef DWORD (WINAPI *GetFinalPathNameByHandleWFunc)( + HANDLE hFile, + LPTSTR lpszFilePath, + DWORD cchFilePath, + DWORD dwFlags); + static const GetFinalPathNameByHandleWFunc getFinalPathNameByHandle = + Utility::loadDllFunKernel<GetFinalPathNameByHandleWFunc>("GetFinalPathNameByHandleW"); + + if (getFinalPathNameByHandle == NULL) + throw FileError(wxString(_("Error loading library function:")) + wxT("\n\"") + wxT("GetFinalPathNameByHandleW") + wxT("\"")); + + const DWORD rv = (*getFinalPathNameByHandle)( hDir, targetPath, BUFFER_SIZE, @@ -987,7 +1015,7 @@ void FreeFileSync::createDirectory(const Zstring& directory, const Zstring& temp Zstring createTempName(const Zstring& filename) { - Zstring output = filename + DefaultStr(".tmp"); + Zstring output = filename + DefaultStr(".ffs_tmp"); //ensure uniqueness if (FreeFileSync::fileExists(output)) @@ -1007,7 +1035,7 @@ Zstring createTempName(const Zstring& filename) #ifdef FFS_WIN #ifndef COPY_FILE_COPY_SYMLINK -const DWORD COPY_FILE_COPY_SYMLINK = 0x00000800; +#define COPY_FILE_COPY_SYMLINK 0x00000800 #endif DWORD CALLBACK copyCallbackInternal( @@ -1063,7 +1091,26 @@ bool supportForSymbolicLinks() //symbolic links are supported starting with Vista if (GetVersionEx(&osvi)) return osvi.dwMajorVersion > 5; //XP has majorVersion == 5, minorVersion == 1, Vista majorVersion == 6 + //overview: http://msdn.microsoft.com/en-us/library/ms724834(VS.85).aspx + return false; +} + +#ifndef COPY_FILE_ALLOW_DECRYPTED_DESTINATION +#define COPY_FILE_ALLOW_DECRYPTED_DESTINATION 0x00000008 +#endif + + +bool supportForNonEncryptedDestination() +{ + OSVERSIONINFO osvi; + ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + + //symbolic links are supported starting with Vista + if (GetVersionEx(&osvi)) + return osvi.dwMajorVersion >= 5 && osvi.dwMinorVersion >= 1; //XP has majorVersion == 5, minorVersion == 1, Vista majorVersion == 6 + //overview: http://msdn.microsoft.com/en-us/library/ms724834(VS.85).aspx return false; } @@ -1081,6 +1128,12 @@ void FreeFileSync::copyFile(const Zstring& sourceFile, if (copyFileSymLinks && symlinksSupported) copyFlags |= COPY_FILE_COPY_SYMLINK; + //allow copying from encrypted to non-encrytped location + static const bool nonEncSupported = supportForNonEncryptedDestination(); + if (nonEncSupported) + copyFlags |= COPY_FILE_ALLOW_DECRYPTED_DESTINATION; + + const Zstring temporary = createTempName(targetFile); //use temporary file until a correct date has been set if (!::CopyFileEx( //same performance as CopyFile() sourceFile.c_str(), @@ -1312,3 +1365,4 @@ bool FreeFileSync::isFatDrive(const Zstring& directoryName) } #endif //FFS_WIN */ + diff --git a/shared/globalFunctions.h b/shared/globalFunctions.h index 74387959..06238236 100644 --- a/shared/globalFunctions.h +++ b/shared/globalFunctions.h @@ -10,10 +10,7 @@ #include <memory> #include <sstream> #include <fstream> -#include <wx/stream.h> -class wxInputStream; -class wxOutputStream; class wxStopWatch; @@ -61,9 +58,6 @@ unsigned int getDigitCount(const unsigned int number); //count number of digits template <class T> T readNumber(std::ifstream& stream); template <class T> void writeNumber(std::ofstream& stream, T number); -template <class T> T readNumber(wxInputStream& stream); -template <class T> void writeNumber(wxOutputStream& stream, T number); - inline wxLongLong convertToSigned(const wxULongLong number) { @@ -221,24 +215,6 @@ void globalFunctions::writeNumber(std::ofstream& stream, T number) } -template <class T> -inline -T globalFunctions::readNumber(wxInputStream& stream) -{ - T result = 0; - stream.Read(&result, sizeof(T)); - return result; -} - - -template <class T> -inline -void globalFunctions::writeNumber(wxOutputStream& stream, T number) -{ - stream.Write(&number, sizeof(T)); -} - - inline wxString globalFunctions::numberToWxString(const unsigned int number) { diff --git a/shared/inotify/inotify-cxx.cpp b/shared/inotify/inotify-cxx.cpp index 7870e825..7c523afb 100644 --- a/shared/inotify/inotify-cxx.cpp +++ b/shared/inotify/inotify-cxx.cpp @@ -18,7 +18,9 @@ * please visit http://www.gnu.org/licenses/license-list.html. * */ - + +//added by ZenJu +#include <cstdio> #include <errno.h> #include <unistd.h> diff --git a/shared/localization.cpp b/shared/localization.cpp index ff14c980..ad3cbb99 100644 --- a/shared/localization.cpp +++ b/shared/localization.cpp @@ -127,6 +127,13 @@ LocalizationInfo::LocalizationInfo() newEntry.languageFlag = wxT("slovakia.png"); locMapping.push_back(newEntry); + newEntry.languageID = wxLANGUAGE_FINNISH; + newEntry.languageName = wxT("Suomi"); + newEntry.languageFile = wxT("finnish.lng"); + newEntry.translatorName = wxT("Nalle Juslén"); + newEntry.languageFlag = wxT("finland.png"); + locMapping.push_back(newEntry); + newEntry.languageID = wxLANGUAGE_TURKISH; newEntry.languageName = wxT("Türkçe"); newEntry.languageFile = wxT("turkish.lng"); @@ -224,6 +231,7 @@ int mapLanguageDialect(const int language) return wxLANGUAGE_SPANISH; //case wxLANGUAGE_CZECH: + //case wxLANGUAGE_FINNISH: //case wxLANGUAGE_JAPANESE: //case wxLANGUAGE_POLISH: //case wxLANGUAGE_SLOVENIAN: @@ -378,8 +386,8 @@ void CustomLocale::setLanguage(const int language) translationDB->clear(); if (!languageFile.empty()) { - UnicodeFileReader langFile(FreeFileSync::getInstallationDir() + zToWx(globalFunctions::FILE_NAME_SEPARATOR) + - wxT("Languages") + zToWx(globalFunctions::FILE_NAME_SEPARATOR) + languageFile); + UnicodeFileReader langFile(FreeFileSync::getInstallationDir() + wxT("Languages") + + zToWx(globalFunctions::FILE_NAME_SEPARATOR) + languageFile); if (langFile.isOkay()) { int rowNumber = 0; diff --git a/shared/serialize.cpp b/shared/serialize.cpp new file mode 100644 index 00000000..616d244d --- /dev/null +++ b/shared/serialize.cpp @@ -0,0 +1,50 @@ +#include "serialize.h" +#include <wx/intl.h> + +using namespace Utility; + + +void ReadInputStream::throwReadError() //throw FileError() +{ + throw FreeFileSync::FileError(wxString(_("Error reading from synchronization database:")) + wxT(" \n") + + wxT("\"") + errorObjName_ + wxT("\"")); +} + + +ReadInputStream::CharArray ReadInputStream::readArrayC() +{ + CharArray buffer(new std::vector<char>); + const size_t byteCount = readNumberC<size_t>(); + if (byteCount > 0) + { + buffer->resize(byteCount); + stream_.Read(&(*buffer)[0], byteCount); + check(); + if (stream_.LastRead() != byteCount) //some additional check + throwReadError(); + } + return buffer; +} + + +//-------------------------------------------------------------------------------------------------------- +void WriteOutputStream::throwWriteError() //throw FileError() +{ + throw FreeFileSync::FileError(wxString(_("Error writing to synchronization database:")) + wxT(" \n") + + wxT("\"") + errorObjName_ + wxT("\"")); +} + + +void WriteOutputStream::writeArrayC(const std::vector<char>& buffer) +{ + writeNumberC<size_t>(buffer.size()); + if (buffer.size() > 0) + { + stream_.Write(&buffer[0], buffer.size()); + check(); + if (stream_.LastWrite() != buffer.size()) //some additional check + throwWriteError(); + } +} + + diff --git a/shared/serialize.h b/shared/serialize.h new file mode 100644 index 00000000..85f57370 --- /dev/null +++ b/shared/serialize.h @@ -0,0 +1,198 @@ +#ifndef SERIALIZE_H_INCLUDED +#define SERIALIZE_H_INCLUDED + +#include "zstring.h" +#include <wx/stream.h> +#include "fileError.h" +#include <boost/scoped_array.hpp> +#include <boost/shared_ptr.hpp> + +namespace Utility +{ +template <class T> +T readNumber(wxInputStream& stream); + +template <class T> +void writeNumber(wxOutputStream& stream, T number); + + +Zstring readString(wxInputStream& stream); +void writeString(wxOutputStream& stream, const Zstring& str); + + +class ReadInputStream //throw FileError() +{ +protected: + ReadInputStream(wxInputStream& stream, const wxString& errorObjName) : stream_(stream), errorObjName_(errorObjName) {} + + template <class T> + T readNumberC(); //checked read operation + + Zstring readStringC(); //checked read operation + + typedef boost::shared_ptr<std::vector<char> > CharArray; + CharArray readArrayC(); + + void check(); + +protected: + wxInputStream& stream_; + +private: + void throwReadError(); //throw FileError() + const wxString& errorObjName_; //used for error text only +}; + + +class WriteOutputStream //throw FileError() +{ +protected: + WriteOutputStream(const wxString& errorObjName, wxOutputStream& stream) : stream_(stream), errorObjName_(errorObjName) {} + + template <class T> + void writeNumberC(T number); //checked write operation + + void writeStringC(const Zstring& str); //checked write operation + + void writeArrayC(const std::vector<char>& buffer); + + void check(); + +protected: + wxOutputStream& stream_; + +private: + void throwWriteError(); //throw FileError() + const wxString& errorObjName_; //used for error text only! +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +//---------------Inline Implementation--------------------------------------------------- +template <class T> +inline +T readNumber(wxInputStream& stream) +{ + T result = 0; + stream.Read(&result, sizeof(T)); + return result; +} + + +template <class T> +inline +void writeNumber(wxOutputStream& stream, T number) +{ + stream.Write(&number, sizeof(T)); +} + + +inline +Zstring readString(wxInputStream& stream) //read string from file stream +{ + const size_t strLength = readNumber<size_t>(stream); + if (strLength <= 1000) + { + DefaultChar buffer[1000]; + stream.Read(buffer, sizeof(DefaultChar) * strLength); + return Zstring(buffer, strLength); + } + else + { + boost::scoped_array<DefaultChar> buffer(new DefaultChar[strLength]); + stream.Read(buffer.get(), sizeof(DefaultChar) * strLength); + return Zstring(buffer.get(), strLength); + } +} + + +inline +void writeString(wxOutputStream& stream, const Zstring& str) //write string to filestream +{ + writeNumber<size_t>(stream, str.length()); + stream.Write(str.c_str(), sizeof(DefaultChar) * str.length()); +} + + +inline +void ReadInputStream::check() +{ + if (stream_.GetLastError() != wxSTREAM_NO_ERROR) + throwReadError(); +} + + +template <class T> +inline +T ReadInputStream::readNumberC() //checked read operation +{ + T output = readNumber<T>(stream_); + check(); + return output; +} + + +inline +Zstring ReadInputStream::readStringC() //checked read operation +{ + Zstring output = readString(stream_); + check(); + return output; +} + + +template <class T> +inline +void WriteOutputStream::writeNumberC(T number) //checked write operation +{ + writeNumber<T>(stream_, number); + check(); +} + + +inline +void WriteOutputStream::writeStringC(const Zstring& str) //checked write operation +{ + writeString(stream_, str); + check(); +} + + + +inline +void WriteOutputStream::check() +{ + if (stream_.GetLastError() != wxSTREAM_NO_ERROR) + throwWriteError(); +} + + +} + +#endif // SERIALIZE_H_INCLUDED diff --git a/shared/shadow.cpp b/shared/shadow.cpp index da7cfd99..29eec53b 100644 --- a/shared/shadow.cpp +++ b/shared/shadow.cpp @@ -6,7 +6,43 @@ using FreeFileSync::ShadowCopy; -class ShadowlDllHandler //dynamically load windows API functions +bool newerThanXP() +{ + OSVERSIONINFO osvi; + ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + + //symbolic links are supported starting with Vista + if (GetVersionEx(&osvi)) + return osvi.dwMajorVersion > 5 || + (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion > 1) ; + //XP has majorVersion == 5, minorVersion == 1 + //Server 2003 has majorVersion == 5, minorVersion == 2 + //version overview: http://msdn.microsoft.com/en-us/library/ms724834(VS.85).aspx + return false; +} + + +bool runningWOW64() //test if process is running under WOW64 (reference http://msdn.microsoft.com/en-us/library/ms684139(VS.85).aspx) +{ + typedef BOOL (WINAPI *IsWow64ProcessFunc)( + HANDLE hProcess, + PBOOL Wow64Process); + + const IsWow64ProcessFunc isWow64Process = reinterpret_cast<IsWow64ProcessFunc>( + ::GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process")); + if (isWow64Process != NULL) + { + BOOL isWow64 = FALSE; + if ((*isWow64Process)(::GetCurrentProcess(), &isWow64)) + return isWow64 == TRUE; + } + + return false; +} + + +class ShadowCopy::ShadowlDllHandler //dynamically load windows API functions { typedef bool (*CreateShadowCopyFct)( //volumeName must end with "\", while shadowVolName does not end with "\" const wchar_t* volumeName, @@ -19,23 +55,33 @@ class ShadowlDllHandler //dynamically load windows API functions typedef void (*ReleaseShadowCopyFct)(void* backupHandle); public: - static const ShadowlDllHandler& getInstance() + static const wxString& getShadowDllName() { - static ShadowlDllHandler instance; - return instance; + /* + distinguish a bunch of VSS builds: we use XP and Server 2003 implementations... + VSS version and compatibility overview: http://msdn.microsoft.com/en-us/library/aa384627(VS.85).aspx + */ +#if defined _WIN64 //note: _WIN32 is defined for 64-bit compilations, too, while _WIN64 only for 64-bit + static const wxString filename(newerThanXP() ? + wxT("Shadow_Server2003_x64.dll") : + wxT("Shadow_XP_x64.dll")); +#elif defined(_WIN32) + static const wxString filename(newerThanXP() ? + wxT("Shadow_Server2003_win32.dll") : + wxT("Shadow_XP_win32.dll")); +#else + Are we at 128 bit already? +#endif + return filename; } - CreateShadowCopyFct createShadowCopy; - ReleaseShadowCopyFct releaseShadowCopy; - -private: ShadowlDllHandler() : createShadowCopy(NULL), releaseShadowCopy(NULL), hShadow(NULL) { //get a handle to the DLL module containing the required functionality - hShadow = ::LoadLibrary(L"Shadow.dll"); + hShadow = ::LoadLibrary(getShadowDllName().c_str()); if (hShadow) { createShadowCopy = reinterpret_cast<CreateShadowCopyFct>(::GetProcAddress(hShadow, "createShadowCopy")); @@ -48,41 +94,56 @@ private: if (hShadow) ::FreeLibrary(hShadow); } + CreateShadowCopyFct createShadowCopy; + ReleaseShadowCopyFct releaseShadowCopy; + +private: HINSTANCE hShadow; }; +//############################################################################################################# ShadowCopy::ShadowCopy() : - backupHandle(NULL) {} + backupHandle(NULL) +{ + shadowDll = new ShadowlDllHandler; +} ShadowCopy::~ShadowCopy() { if (backupHandle != NULL) - ShadowlDllHandler::getInstance().releaseShadowCopy(backupHandle); -} - + shadowDll->releaseShadowCopy(backupHandle); -bool ShadowCopy::isOkay() -{ - //check that all functions could be loaded - return ShadowlDllHandler::getInstance().createShadowCopy != NULL && - ShadowlDllHandler::getInstance().releaseShadowCopy != NULL; + delete shadowDll; } Zstring ShadowCopy::makeShadowCopy(const Zstring& inputFile) { //check if shadow copy dll was loaded correctly - if (!isOkay()) + if ( shadowDll->createShadowCopy == NULL || + shadowDll->releaseShadowCopy == NULL) { wxString errorMsg = _("Error copying locked file %x!"); errorMsg.Replace(wxT("%x"), wxString(wxT("\"")) + inputFile.c_str() + wxT("\"")); throw FileError(errorMsg + wxT("\n\n") + _("Error starting Volume Shadow Copy Service!") + wxT("\n") + - _("Please copy the appropriate \"Shadow.dll\" (located in \"Shadow.zip\" archive) into the FreeFileSync installation directory to enable this feature.")); + _("Could not load a required DLL:") + wxT(" \"") + ShadowlDllHandler::getShadowDllName() + wxT("\"")); + } + + //VSS does not support running under WOW64 except for Windows XP and Windows Server 2003 + //(Reference: http://msdn.microsoft.com/en-us/library/aa384627(VS.85).aspx) + static const bool wow64Active = runningWOW64(); + if (wow64Active) + { + wxString errorMsg = _("Error copying locked file %x!"); + errorMsg.Replace(wxT("%x"), wxString(wxT("\"")) + inputFile.c_str() + wxT("\"")); + throw FileError(errorMsg + wxT("\n\n") + _("Error starting Volume Shadow Copy Service!") + wxT("\n") + + _("Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version.")); } +//--------------------------------------------------------------------------------------------------------- wchar_t volumeNameRaw[1000]; if (!GetVolumePathName(inputFile.c_str(), //__in LPCTSTR lpszFileName, @@ -103,7 +164,7 @@ Zstring ShadowCopy::makeShadowCopy(const Zstring& inputFile) //release old shadow copy if (backupHandle != NULL) { - ShadowlDllHandler::getInstance().releaseShadowCopy(backupHandle); + shadowDll->releaseShadowCopy(backupHandle); backupHandle = NULL; } realVolumeLast.clear(); //...if next call fails... @@ -114,7 +175,7 @@ Zstring ShadowCopy::makeShadowCopy(const Zstring& inputFile) void* backupHandleTmp = NULL; wchar_t errorMessage[1000]; - if (!ShadowlDllHandler::getInstance().createShadowCopy( + if (!shadowDll->createShadowCopy( volumeNameFormatted.c_str(), shadowVolName, 1000, @@ -149,10 +210,3 @@ Zstring ShadowCopy::makeShadowCopy(const Zstring& inputFile) } - - - - - - - diff --git a/shared/shadow.h b/shared/shadow.h index ddb329bd..79e0e59c 100644 --- a/shared/shadow.h +++ b/shared/shadow.h @@ -23,7 +23,8 @@ private: ShadowCopy(const ShadowCopy&); ShadowCopy& operator=(const ShadowCopy&); - bool isOkay(); + class ShadowlDllHandler; + const ShadowlDllHandler* shadowDll; Zstring realVolumeLast; //buffer last volume name Zstring shadowVolumeLast; //buffer last created shadow volume diff --git a/shared/standardPaths.cpp b/shared/standardPaths.cpp index 3d5cfdb5..3c57f5b9 100644 --- a/shared/standardPaths.cpp +++ b/shared/standardPaths.cpp @@ -9,7 +9,7 @@ using namespace FreeFileSync; wxString assembleFileForUserData(const wxString fileName) { - static const bool isPortableVersion = !wxFileExists(FreeFileSync::getInstallationDir() + zToWx(globalFunctions::FILE_NAME_SEPARATOR) + wxT("uninstall.exe")); //this check is a bit lame... + static const bool isPortableVersion = !wxFileExists(FreeFileSync::getInstallationDir() + wxT("uninstall.exe")); //this check is a bit lame... if (isPortableVersion) //use current working directory return wxString(wxT(".")) + zToWx(globalFunctions::FILE_NAME_SEPARATOR) + fileName; @@ -51,7 +51,7 @@ const wxString& FreeFileSync::getLastErrorTxtFile() const wxString& FreeFileSync::getInstallationDir() { - static wxString instance = wxFileName(wxStandardPaths::Get().GetExecutablePath()).GetPath(); + static wxString instance = wxFileName(wxStandardPaths::Get().GetExecutablePath()).GetPath() + zToWx(globalFunctions::FILE_NAME_SEPARATOR); return instance; } diff --git a/shared/standardPaths.h b/shared/standardPaths.h index 34f6ab48..2af802a9 100644 --- a/shared/standardPaths.h +++ b/shared/standardPaths.h @@ -12,7 +12,7 @@ namespace FreeFileSync const wxString& getGlobalConfigFile(); const wxString& getDefaultLogDirectory(); const wxString& getLastErrorTxtFile(); -const wxString& getInstallationDir(); //FreeFileSync installation directory without path separator +const wxString& getInstallationDir(); //FreeFileSync installation directory WITH path separator at end const wxString& getConfigDir(); //------------------------------------------------------------------------------ } diff --git a/shared/zstring.cpp b/shared/zstring.cpp index 04c79b6f..cb288ea2 100644 --- a/shared/zstring.cpp +++ b/shared/zstring.cpp @@ -3,6 +3,7 @@ #ifdef FFS_WIN #include <wx/msw/wrapwin.h> //includes "windows.h" +#include "dllLoader.h" #endif //FFS_WIN #ifdef __WXDEBUG__ @@ -46,24 +47,58 @@ AllocationCount& AllocationCount::getInstance() #ifdef FFS_WIN + +#ifndef LOCALE_INVARIANT +#define LOCALE_INVARIANT 0x007f +#endif + + inline int compareStringsWin32(const wchar_t* a, const wchar_t* b, const int aCount = -1, const int bCount = -1) { - //DON'T use lstrcmpi() here! It uses word sort, which unfortunately is NOT always a strict weak sorting function for some locales (e.g. swedish) - //Use CompareString() with "SORT_STRINGSORT" instead!!! - - const int rv = CompareString( - LOCALE_USER_DEFAULT, //locale identifier - NORM_IGNORECASE | SORT_STRINGSORT, //comparison-style options - a, //pointer to first string - aCount, //size, in bytes or characters, of first string - b, //pointer to second string - bCount); //size, in bytes or characters, of second string - - if (rv == 0) - throw std::runtime_error("Error comparing strings!"); - else - return rv - 2; //convert to C-style string compare result + //try to call "CompareStringOrdinal" first for low-level string comparison: unfortunately available not before Windows Vista! + typedef int (WINAPI *CompareStringOrdinalFunc)( + LPCWSTR lpString1, + int cchCount1, + LPCWSTR lpString2, + int cchCount2, + BOOL bIgnoreCase); + static const CompareStringOrdinalFunc ordinalCompare = Utility::loadDllFunKernel<CompareStringOrdinalFunc>("CompareStringOrdinal"); + + + //we're lucky here! This additional test for "CompareStringOrdinal" has no noticeable performance impact!! + if (ordinalCompare != NULL) + { + const int rv = (*ordinalCompare)( + a, //pointer to first string + aCount, //size, in bytes or characters, of first string + b, //pointer to second string + bCount, //size, in bytes or characters, of second string + true); //ignore case + + if (rv == 0) + throw std::runtime_error("Error comparing strings (ordinal)!"); + else + return rv - 2; //convert to C-style string compare result + } + else //fallback to "CompareString". Attention: this function is NOT accurate: for example "weiß" == "weiss"!!! + { + //DON'T use lstrcmpi() here! It uses word sort and is locale dependent! + //Use CompareString() with "SORT_STRINGSORT" instead!!! + + const int rv = CompareString( + LOCALE_INVARIANT, //locale independent + NORM_IGNORECASE | SORT_STRINGSORT, //comparison-style options + a, //pointer to first string + aCount, //size, in bytes or characters, of first string + b, //pointer to second string + bCount); //size, in bytes or characters, of second string + + if (rv == 0) + throw std::runtime_error("Error comparing strings!"); + else + return rv - 2; //convert to C-style string compare result + } } #endif diff --git a/shared/zstring.h b/shared/zstring.h index 68b72060..d0be30bf 100644 --- a/shared/zstring.h +++ b/shared/zstring.h @@ -61,7 +61,7 @@ public: Zstring BeforeLast( DefaultChar ch) const; //returns empty string if ch not found Zstring AfterFirst( DefaultChar ch) const; //returns empty string if ch not found Zstring BeforeFirst(DefaultChar ch) const; //returns the whole string if ch not found - size_t Find(DefaultChar ch, bool fromEnd) const; + size_t Find(DefaultChar ch, bool fromEnd) const; //returns npos if not found bool Matches(const DefaultChar* mask) const; static bool Matches(const DefaultChar* name, const DefaultChar* mask); Zstring& Trim(bool fromRight); //from right or left @@ -333,6 +333,7 @@ Zstring::~Zstring() inline void Zstring::initAndCopy(const DefaultChar* source, size_t sourceLen) { + assert(source); descr = allocate(sourceLen); ::memcpy(data(), source, sourceLen * sizeof(DefaultChar)); data()[sourceLen] = 0; |