summaryrefslogtreecommitdiff
path: root/shared
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 17:09:24 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 17:09:24 +0200
commitb5f042a6c132c1b97cf03c4615bab966c23f57d2 (patch)
tree1cb057a0ffd51264bb3c9807e2133505ce312eb1 /shared
parent3.11 (diff)
downloadFreeFileSync-b5f042a6c132c1b97cf03c4615bab966c23f57d2.tar.gz
FreeFileSync-b5f042a6c132c1b97cf03c4615bab966c23f57d2.tar.bz2
FreeFileSync-b5f042a6c132c1b97cf03c4615bab966c23f57d2.zip
3.12
Diffstat (limited to 'shared')
-rw-r--r--shared/IFileOperation/file_op.cpp1
-rw-r--r--shared/com_ptr.h23
-rw-r--r--shared/custom_combo_box.cpp39
-rw-r--r--shared/custom_combo_box.h7
-rw-r--r--shared/custom_tooltip.cpp3
-rw-r--r--shared/dir_name.cpp2
-rw-r--r--shared/file_handling.cpp178
-rw-r--r--shared/file_io.cpp2
-rw-r--r--shared/file_traverser.cpp144
-rw-r--r--shared/global_func.h2
-rw-r--r--shared/localization.cpp29
-rw-r--r--shared/localization.h2
-rw-r--r--shared/recycler.cpp10
-rw-r--r--shared/serialize.cpp2
-rw-r--r--shared/serialize.h5
-rw-r--r--shared/signal_processing.h166
-rw-r--r--shared/symlink_target.h146
-rw-r--r--shared/system_func.cpp17
-rw-r--r--shared/zbase.h20
19 files changed, 427 insertions, 371 deletions
diff --git a/shared/IFileOperation/file_op.cpp b/shared/IFileOperation/file_op.cpp
index 6180a561..cc8c58bc 100644
--- a/shared/IFileOperation/file_op.cpp
+++ b/shared/IFileOperation/file_op.cpp
@@ -53,6 +53,7 @@ bool fileop::moveToRecycleBin(const wchar_t* fileNames[],
hr = fileOp->SetOperationFlags(FOF_ALLOWUNDO |
FOF_NOCONFIRMATION |
FOF_SILENT |
+ FOFX_EARLYFAILURE |
FOF_NOERRORUI);
if (FAILED(hr))
{
diff --git a/shared/com_ptr.h b/shared/com_ptr.h
index 1ce7eae6..52a072fa 100644
--- a/shared/com_ptr.h
+++ b/shared/com_ptr.h
@@ -12,7 +12,7 @@
namespace util
{
-/*
+/*
ComPtr: RAII class handling COM objects
Example:
@@ -39,13 +39,20 @@ public:
~ComPtr();
T** init(); //get pointer for use with ::CoCreateInstance()
T* get() const;
- T* release();
+ T* release(); //throw()
void swap(ComPtr& rhs); //throw()
T* operator->() const;
- operator bool() const;
private:
T* ptr;
+
+ struct ConversionToBool
+ {
+ int dummy;
+ };
+
+public:
+ operator int ConversionToBool::*() const; //use member pointer as implicit conversion to bool (C++ Templates - Vandevoorde/Josuttis; chapter 20)
};
@@ -162,12 +169,22 @@ T* ComPtr<T>::operator->() const
}
+/*
template <class T>
inline
ComPtr<T>::operator bool() const
{
return ptr != NULL;
}
+*/
+
+
+template <class T>
+inline
+ComPtr<T>::operator int ComPtr<T>::ConversionToBool::*() const
+{
+ return ptr != NULL ? &ConversionToBool::dummy : NULL;
+}
template <class S, class T>
diff --git a/shared/custom_combo_box.cpp b/shared/custom_combo_box.cpp
index 3c2a118c..18adb38a 100644
--- a/shared/custom_combo_box.cpp
+++ b/shared/custom_combo_box.cpp
@@ -18,12 +18,36 @@ CustomComboBox::CustomComboBox(wxWindow* parent,
const wxValidator& validator,
const wxString& name) :
wxComboBox(parent, id, value, pos, size, n, choices, style, validator, name)
+#if wxCHECK_VERSION(2, 9, 1)
+ , dropDownShown(false)
+#endif
{
//register key event to enable item deletion
this->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CustomComboBox::OnKeyEvent), NULL, this );
+
+#if wxCHECK_VERSION(2, 9, 1)
+ this->Connect(wxEVT_COMMAND_COMBOBOX_DROPDOWN, wxCommandEventHandler(CustomComboBox::OnShowDropDown), NULL, this );
+ this->Connect(wxEVT_COMMAND_COMBOBOX_CLOSEUP, wxCommandEventHandler(CustomComboBox::OnHideDropDown), NULL, this );
+#endif
+}
+
+
+#if wxCHECK_VERSION(2, 9, 1)
+void CustomComboBox::OnShowDropDown(wxCommandEvent& event)
+{
+ dropDownShown = true;
+ event.Skip();
}
+void CustomComboBox::OnHideDropDown(wxCommandEvent& event)
+{
+ dropDownShown = false;
+ event.Skip();
+}
+#endif
+
+
void CustomComboBox::OnKeyEvent(wxKeyEvent& event)
{
const int keyCode = event.GetKeyCode();
@@ -32,11 +56,16 @@ void CustomComboBox::OnKeyEvent(wxKeyEvent& event)
//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 a character 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();
+#if wxCHECK_VERSION(2, 9, 1)
+ dropDownShown)
+#else
+ //what a mess...:
+ (GetValue() != GetString(selectedItem) || //avoid problems when a character shall be deleted instead of list item
+ GetValue() == wxEmptyString)) //exception: always allow removing empty entry
+#endif
+ {
+ //save old (selected) value: deletion seems to have influence on this
+ const wxString currentVal = this->GetValue();
this->SetSelection(wxNOT_FOUND);
//delete selected row
diff --git a/shared/custom_combo_box.h b/shared/custom_combo_box.h
index 7db8cecf..28361a30 100644
--- a/shared/custom_combo_box.h
+++ b/shared/custom_combo_box.h
@@ -29,6 +29,13 @@ public:
private:
void OnKeyEvent(wxKeyEvent& event);
+
+#if wxCHECK_VERSION(2, 9, 1)
+ void OnShowDropDown(wxCommandEvent& event);
+ void OnHideDropDown(wxCommandEvent& event);
+
+ bool dropDownShown;
+#endif
};
diff --git a/shared/custom_tooltip.cpp b/shared/custom_tooltip.cpp
index be2d11b5..5b4e5e40 100644
--- a/shared/custom_tooltip.cpp
+++ b/shared/custom_tooltip.cpp
@@ -34,7 +34,8 @@ CustomTooltip::PopupFrameGenerated::PopupFrameGenerated(
long style ) : wxFrame(parent, id, title, pos, size, style)
{
this->SetSizeHints( wxDefaultSize, wxDefaultSize );
- this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK));
+ this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK)); //both required: on Ubuntu background is black, foreground white!
+ this->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOTEXT)); //
wxBoxSizer* bSizer158;
bSizer158 = new wxBoxSizer( wxHORIZONTAL );
diff --git a/shared/dir_name.cpp b/shared/dir_name.cpp
index 40e840f5..28c1c413 100644
--- a/shared/dir_name.cpp
+++ b/shared/dir_name.cpp
@@ -52,7 +52,7 @@ void setDirectoryNameImpl(const wxString& dirname, wxDirPickerCtrl* dirPicker, w
const wxString dirFormatted = zToWx(getFormattedDirectoryName(wxToZ(dirname)));
- tooltipWnd.SetToolTip(dirFormatted);
+ tooltipWnd.SetToolTip(dirFormatted); //wxComboBox bug: the edit control is not updated... hope this will be fixed: http://trac.wxwidgets.org/ticket/12659
if (staticBox)
{
diff --git a/shared/file_handling.cpp b/shared/file_handling.cpp
index 5c6ce856..b05b9cf8 100644
--- a/shared/file_handling.cpp
+++ b/shared/file_handling.cpp
@@ -21,6 +21,7 @@
#include "loki/TypeManip.h"
#include "loki/ScopeGuard.h"
#include <map>
+#include "symlink_target.h"
#ifdef FFS_WIN
#include "dll_loader.h"
@@ -36,6 +37,10 @@
#include <utime.h>
#include <cerrno>
#include <sys/time.h>
+
+#ifdef HAVE_SELINUX
+#include <selinux/selinux.h>
+#endif
#endif
using ffs3::FileError;
@@ -1129,7 +1134,7 @@ void ffs3::copyFileTimes(const Zstring& sourceObj, const Zstring& targetObj, boo
namespace
{
#ifdef FFS_WIN
-Zstring resolveDirectorySymlink(const Zstring& dirLinkName) //get full target path of symbolic link to a directory
+Zstring resolveDirectorySymlink(const Zstring& dirLinkName) //get full target path of symbolic link to a directory; throw (FileError)
{
//open handle to target of symbolic link
const HANDLE hDir = ::CreateFile(ffs3::applyLongPathPrefix(dirLinkName).c_str(),
@@ -1140,7 +1145,10 @@ Zstring resolveDirectorySymlink(const Zstring& dirLinkName) //get full target pa
FILE_FLAG_BACKUP_SEMANTICS, //needed to open a directory
NULL);
if (hDir == INVALID_HANDLE_VALUE)
- return Zstring();
+ {
+ wxString errorMessage = wxString(_("Error resolving symbolic link:")) + wxT("\n\"") + ffs3::zToWx(dirLinkName) + wxT("\"");
+ throw FileError(errorMessage + wxT("\n\n") + ffs3::getLastErrorFormatted());
+ }
boost::shared_ptr<void> dummy(hDir, ::CloseHandle);
@@ -1159,13 +1167,17 @@ Zstring resolveDirectorySymlink(const Zstring& dirLinkName) //get full target pa
if (getFinalPathNameByHandle == NULL)
throw FileError(wxString(_("Error loading library function:")) + wxT("\n\"") + wxT("GetFinalPathNameByHandleW") + wxT("\""));
- const DWORD rv = (*getFinalPathNameByHandle)(
+ const DWORD rv = getFinalPathNameByHandle(
hDir, //__in HANDLE hFile,
targetPath, //__out LPTSTR lpszFilePath,
BUFFER_SIZE,//__in DWORD cchFilePath,
0); //__in DWORD dwFlags
if (rv >= BUFFER_SIZE || rv == 0)
- return Zstring();
+ {
+ wxString errorMessage = wxString(_("Error resolving symbolic link:")) + wxT("\n\"") + ffs3::zToWx(dirLinkName) + wxT("\"");
+ if (rv == 0) errorMessage += wxT("\n\n") + ffs3::getLastErrorFormatted();
+ throw FileError(errorMessage);
+ }
return targetPath;
}
@@ -1351,6 +1363,58 @@ void Privileges::setPrivilege(LPCTSTR privilege, bool enable) //throw FileError(
}
+#ifdef HAVE_SELINUX
+//copy SELinux security context
+void copySecurityContext(const Zstring& source, const Zstring& target, bool derefSymlinks) //throw FileError()
+{
+ using ffs3::zToWx;
+
+ security_context_t contextSource = NULL;
+ const int rv = derefSymlinks ?
+ ::getfilecon (source.c_str(), &contextSource) :
+ ::lgetfilecon(source.c_str(), &contextSource);
+ if (rv < 0)
+ {
+ if ( errno == ENODATA || //no security context (allegedly) is not an error condition on SELinux
+ errno == EOPNOTSUPP) //extended attributes are not supported by the filesystem
+ return;
+
+ wxString errorMessage = wxString(_("Error reading security context:")) + wxT("\n\"") + zToWx(source) + wxT("\"");
+ throw FileError(errorMessage + wxT("\n\n") + ffs3::getLastErrorFormatted());
+ }
+ boost::shared_ptr<char> dummy1(contextSource, ::freecon);
+
+ {
+ security_context_t contextTarget = NULL;
+ const int rv2 = derefSymlinks ?
+ ::getfilecon (target.c_str(), &contextTarget) :
+ ::lgetfilecon(target.c_str(), &contextTarget);
+ if (rv2 < 0)
+ {
+ if (errno == EOPNOTSUPP)
+ return;
+ //else: still try to set security context
+ }
+ else
+ {
+ boost::shared_ptr<char> dummy2(contextTarget, ::freecon);
+ if (::strcmp(contextSource, contextTarget) == 0) //nothing to do
+ return;
+ }
+ }
+
+ const int rv3 = derefSymlinks ?
+ ::setfilecon (target.c_str(), contextSource) :
+ ::lsetfilecon(target.c_str(), contextSource);
+ if (rv3 < 0)
+ {
+ wxString errorMessage = wxString(_("Error writing security context:")) + wxT("\n\"") + zToWx(target) + wxT("\"");
+ throw FileError(errorMessage + wxT("\n\n") + ffs3::getLastErrorFormatted());
+ }
+}
+#endif //HAVE_SELINUX
+
+
//copy permissions for files, directories or symbolic links
void ffs3::copyObjectPermissions(const Zstring& source, const Zstring& target, bool derefSymlinks) //throw FileError(); probably requires admin rights
{
@@ -1379,8 +1443,10 @@ void ffs3::copyObjectPermissions(const Zstring& source, const Zstring& target, b
FILE_FLAG_BACKUP_SEMANTICS | (derefSymlinks ? 0 : FILE_FLAG_OPEN_REPARSE_POINT), //FILE_FLAG_BACKUP_SEMANTICS needed to open a directory
NULL);
if (hSource == INVALID_HANDLE_VALUE)
- throw FileError(wxString(_("Error opening file:")) + wxT("\n\"") + zToWx(source) + wxT("\"") +
- wxT("\n\n") + ffs3::getLastErrorFormatted());
+ {
+ const wxString errorMessage = wxString(_("Error copying file permissions:")) + wxT("\n\"") + zToWx(source) + wxT("\" ->\n\"") + zToWx(target) + wxT("\"") + wxT("\n\n");
+ throw FileError(errorMessage + ffs3::getLastErrorFormatted() + wxT(" (OR)"));
+ }
boost::shared_ptr<void> dummy(hSource, ::CloseHandle);
// DWORD rc = ::GetNamedSecurityInfo(const_cast<WCHAR*>(applyLongPathPrefix(source).c_str()), -> does NOT dereference symlinks!
@@ -1396,7 +1462,7 @@ void ffs3::copyObjectPermissions(const Zstring& source, const Zstring& target, b
if (rc != ERROR_SUCCESS)
{
const wxString errorMessage = wxString(_("Error copying file permissions:")) + wxT("\n\"") + zToWx(source) + wxT("\" ->\n\"") + zToWx(target) + wxT("\"") + wxT("\n\n");
- throw FileError(errorMessage + ffs3::getLastErrorFormatted(rc));
+ throw FileError(errorMessage + ffs3::getLastErrorFormatted(rc) + wxT(" (R)"));
}
boost::shared_ptr<void> dummy2(buffer, ::LocalFree);
@@ -1413,7 +1479,7 @@ void ffs3::copyObjectPermissions(const Zstring& source, const Zstring& target, b
resetAttributes.Dismiss();
- HANDLE hTarget = ::CreateFile( targetFmt.c_str(), // lpFileName
+ const HANDLE hTarget = ::CreateFile( targetFmt.c_str(), // lpFileName
FILE_GENERIC_WRITE | WRITE_OWNER | WRITE_DAC | ACCESS_SYSTEM_SECURITY, // dwDesiredAccess: all four seem to be required!!!
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, // dwShareMode
NULL, // lpSecurityAttributes
@@ -1421,8 +1487,10 @@ void ffs3::copyObjectPermissions(const Zstring& source, const Zstring& target, b
FILE_FLAG_BACKUP_SEMANTICS | (derefSymlinks ? 0 : FILE_FLAG_OPEN_REPARSE_POINT), // dwFlagsAndAttributes
NULL); // hTemplateFile
if (hTarget == INVALID_HANDLE_VALUE)
- throw FileError(wxString(_("Error opening file:")) + wxT("\n\"") + zToWx(target) + wxT("\"") +
- wxT("\n\n") + ffs3::getLastErrorFormatted());
+ {
+ const wxString errorMessage = wxString(_("Error copying file permissions:")) + wxT("\n\"") + zToWx(source) + wxT("\" ->\n\"") + zToWx(target) + wxT("\"") + wxT("\n\n");
+ throw FileError(errorMessage + ffs3::getLastErrorFormatted() + wxT(" (OW)"));
+ }
boost::shared_ptr<void> dummy3(hTarget, ::CloseHandle);
// rc = ::SetNamedSecurityInfo(const_cast<WCHAR*>(applyLongPathPrefix(target).c_str()), //__in LPTSTR pObjectName, -> does NOT dereference symlinks!
@@ -1438,10 +1506,15 @@ void ffs3::copyObjectPermissions(const Zstring& source, const Zstring& target, b
if (rc != ERROR_SUCCESS)
{
const wxString errorMessage = wxString(_("Error copying file permissions:")) + wxT("\n\"") + zToWx(source) + wxT("\" ->\n\"") + zToWx(target) + wxT("\"") + wxT("\n\n");
- throw FileError(errorMessage + ffs3::getLastErrorFormatted(rc));
+ throw FileError(errorMessage + ffs3::getLastErrorFormatted(rc) + wxT(" (W)"));
}
#elif defined FFS_LINUX
+
+#ifdef HAVE_SELINUX //copy SELinux security context
+ copySecurityContext(source, target, derefSymlinks); //throw FileError()
+#endif
+
if (derefSymlinks)
{
struct stat fileInfo;
@@ -1450,7 +1523,7 @@ void ffs3::copyObjectPermissions(const Zstring& source, const Zstring& target, b
::chmod(target.c_str(), fileInfo.st_mode) != 0)
{
const wxString errorMessage = wxString(_("Error copying file permissions:")) + wxT("\n\"") + zToWx(source) + wxT("\" ->\n\"") + zToWx(target) + wxT("\"") + wxT("\n\n");
- throw FileError(errorMessage + ffs3::getLastErrorFormatted());
+ throw FileError(errorMessage + ffs3::getLastErrorFormatted() + wxT(" (R)"));
}
}
else
@@ -1461,7 +1534,7 @@ void ffs3::copyObjectPermissions(const Zstring& source, const Zstring& target, b
(!symlinkExists(target) && ::chmod(target.c_str(), fileInfo.st_mode) != 0)) //setting access permissions doesn't make sense for symlinks on Linux: there is no lchmod()
{
const wxString errorMessage = wxString(_("Error copying file permissions:")) + wxT("\n\"") + zToWx(source) + wxT("\" ->\n\"") + zToWx(target) + wxT("\"") + wxT("\n\n");
- throw FileError(errorMessage + ffs3::getLastErrorFormatted());
+ throw FileError(errorMessage + ffs3::getLastErrorFormatted() + wxT(" (W)"));
}
}
#endif
@@ -1518,39 +1591,74 @@ void createDirectoryRecursively(const Zstring& directory, const Zstring& templat
const bool isSymlink = (templateAttr & FILE_ATTRIBUTE_REPARSE_POINT) != 0; //syntax required to shut MSVC up
//symbolic link handling
- if (!copyDirectorySymLinks && isSymlink) //create directory based on target of symbolic link
+ if (isSymlink)
{
- //get target directory of symbolic link
- const Zstring linkPath = resolveDirectorySymlink(templateDir);
- if (linkPath.empty())
+ if (!copyDirectorySymLinks) //create directory based on target of symbolic link
{
- if (level != 0) return;
- throw FileError(wxString(_("Error resolving symbolic link:")) + wxT("\n\"") + templateDir.c_str() + wxT("\""));
- }
+ //get target directory of symbolic link
+ Zstring linkPath;
+ try
+ {
+ linkPath = resolveDirectorySymlink(templateDir); //throw (FileError)
+ }
+ catch (FileError&)
+ {
+ //dereferencing a symbolic link usually fails if it is located on network drive or client is XP: NOT really an error...
+ if (!::CreateDirectory(applyLongPathPrefixCreateDir(directory).c_str(), // pointer to a directory path string
+ NULL))
+ {
+ if (level != 0) return;
+ const wxString errorMessage = wxString(_("Error creating directory:")) + wxT("\n\"") + directory.c_str() + wxT("\"");
+ throw FileError(errorMessage + wxT("\n\n") + ffs3::getLastErrorFormatted());
+ }
+ return;
+ }
- if (!::CreateDirectoryEx( // this function automatically copies symbolic links if encountered
- applyLongPathPrefix(linkPath).c_str(), // pointer to path string of template directory
- applyLongPathPrefixCreateDir(directory).c_str(), // pointer to a directory path string
- NULL))
+ if (!::CreateDirectoryEx( // this function automatically copies symbolic links if encountered
+ applyLongPathPrefix(linkPath).c_str(), // pointer to path string of template directory
+ applyLongPathPrefixCreateDir(directory).c_str(), // pointer to a directory path string
+ NULL))
+ {
+ if (level != 0) return;
+ const wxString errorMessage = wxString(_("Error creating directory:")) + wxT("\n\"") + directory.c_str() + wxT("\"");
+ throw FileError(errorMessage + wxT("\n\n") + ffs3::getLastErrorFormatted());
+ }
+ }
+ else //copy symbolic link
{
- if (level != 0) return;
- const wxString errorMessage = wxString(_("Error creating directory:")) + wxT("\n\"") + directory.c_str() + wxT("\"");
- throw FileError(errorMessage + wxT("\n\n") + ffs3::getLastErrorFormatted());
+ const Zstring linkPath = getSymlinkRawTargetString(templateDir); //accept broken symlinks; throw (FileError)
+
+ //dynamically load windows API function
+ typedef BOOLEAN (WINAPI *CreateSymbolicLinkFunc)(
+ LPCTSTR lpSymlinkFileName,
+ LPCTSTR lpTargetFileName,
+ DWORD dwFlags);
+ static const CreateSymbolicLinkFunc createSymbolicLink = util::getDllFun<CreateSymbolicLinkFunc>(L"kernel32.dll", "CreateSymbolicLinkW");
+ if (createSymbolicLink == NULL)
+ throw FileError(wxString(_("Error loading library function:")) + wxT("\n\"") + wxT("CreateSymbolicLinkW") + wxT("\""));
+
+ if (!createSymbolicLink( //seems no long path prefix is required...
+ directory.c_str(), //__in LPTSTR lpSymlinkFileName,
+ linkPath.c_str(), //__in LPTSTR lpTargetFileName,
+ SYMBOLIC_LINK_FLAG_DIRECTORY)) //__in DWORD dwFlags
+ {
+ //if (level != 0) return;
+ const wxString errorMessage = wxString(_("Error copying symbolic link:")) + wxT("\n\"") + templateDir.c_str() + wxT("\" ->\n\"") + directory.c_str() + wxT("\"");
+ throw FileError(errorMessage + wxT("\n\n") + ffs3::getLastErrorFormatted());
+ }
}
}
- else //in all other cases
+ else //no symbolic link
{
- if (!::CreateDirectoryEx( // this function automatically copies symbolic links if encountered
+ //automatically copies symbolic links if encountered: unfortunately it doesn't copy symlinks over network shares but silently creates empty folders instead (on XP)!
+ //also it isn't able to copy most junctions because of missing permissions (although target path can be retrieved!)
+ if (!::CreateDirectoryEx(
applyLongPathPrefix(templateDir).c_str(), // pointer to path string of template directory
applyLongPathPrefixCreateDir(directory).c_str(), // pointer to a directory path string
NULL))
{
if (level != 0) return;
- const wxString errorMessage = isSymlink ?
- //give a more meaningful errormessage if copying a symbolic link failed, e.g. "C:\Users\ZenJu\Application Data"
- (wxString(_("Error copying symbolic link:")) + wxT("\n\"") + templateDir.c_str() + wxT("\" ->\n\"") + directory.c_str() + wxT("\"")) :
-
- (wxString(_("Error creating directory:")) + wxT("\n\"") + directory.c_str() + wxT("\""));
+ const wxString errorMessage = wxString(_("Error creating directory:")) + wxT("\n\"") + directory.c_str() + wxT("\"");
throw FileError(errorMessage + wxT("\n\n") + ffs3::getLastErrorFormatted());
}
}
@@ -1868,7 +1976,6 @@ void ffs3::copyFile(const Zstring& sourceFile,
//invoke callback method to update progress indicators
if (callback != NULL)
- {
switch (callback->updateCopyStatus(totalBytesTransferred))
{
case CopyFileCallback::CONTINUE:
@@ -1878,7 +1985,6 @@ void ffs3::copyFile(const Zstring& sourceFile,
throw FileError(wxString(_("Error copying file:")) + wxT("\n\"") + zToWx(sourceFile) + wxT("\" ->\n\"") +
zToWx(targetFile) + wxT("\"\n\n") + _("Operation aborted!"));
}
- }
}
while (!fileIn.eof());
diff --git a/shared/file_io.cpp b/shared/file_io.cpp
index 95c14c49..78796bbe 100644
--- a/shared/file_io.cpp
+++ b/shared/file_io.cpp
@@ -12,7 +12,7 @@
#ifdef FFS_WIN
#include "long_path_prefix.h"
#elif defined FFS_LINUX
-#include <errno.h>
+#include <cerrno>
#endif
using namespace ffs3;
diff --git a/shared/file_traverser.cpp b/shared/file_traverser.cpp
index 5d3f75f4..f2b531e9 100644
--- a/shared/file_traverser.cpp
+++ b/shared/file_traverser.cpp
@@ -5,18 +5,16 @@
// **************************************************************************
//
#include "file_traverser.h"
+#include <limits>
#include "system_constants.h"
#include "system_func.h"
#include <wx/intl.h>
#include "string_conv.h"
-#include <boost/shared_ptr.hpp>
-#include <boost/scoped_array.hpp>
#include "assert_static.h"
-#include <limits>
+#include "symlink_target.h"
#ifdef FFS_WIN
#include <wx/msw/wrapwin.h> //includes "windows.h"
-#include "WinIoCtl.h"
#include "long_path_prefix.h"
#include "dst_hack.h"
@@ -27,130 +25,6 @@
#endif
-//Note: this class is superfluous for 64 bit applications!
-//class DisableWow64Redirection
-//{
-//public:
-// DisableWow64Redirection() :
-// wow64DisableWow64FsRedirection(util::getDllFun<Wow64DisableWow64FsRedirectionFunc>(L"kernel32.dll", "Wow64DisableWow64FsRedirection")),
-// wow64RevertWow64FsRedirection(util::getDllFun<Wow64RevertWow64FsRedirectionFunc>(L"kernel32.dll", "Wow64RevertWow64FsRedirection")),
-// oldValue(NULL)
-// {
-// if ( wow64DisableWow64FsRedirection &&
-// wow64RevertWow64FsRedirection)
-// (*wow64DisableWow64FsRedirection)(&oldValue); //__out PVOID *OldValue
-// }
-//
-// ~DisableWow64Redirection()
-// {
-// if ( wow64DisableWow64FsRedirection &&
-// wow64RevertWow64FsRedirection)
-// (*wow64RevertWow64FsRedirection)(oldValue); //__in PVOID OldValue
-// }
-//
-//private:
-// typedef BOOL (WINAPI *Wow64DisableWow64FsRedirectionFunc)(PVOID* OldValue);
-// typedef BOOL (WINAPI *Wow64RevertWow64FsRedirectionFunc)(PVOID OldValue);
-//
-// const Wow64DisableWow64FsRedirectionFunc wow64DisableWow64FsRedirection;
-// const Wow64RevertWow64FsRedirectionFunc wow64RevertWow64FsRedirection;
-//
-// PVOID oldValue;
-//};
-
-#ifdef _MSC_VER //I don't have Windows Driver Kit at hands right now, so unfortunately we need to redefine this structures and cross fingers...
-typedef struct _REPARSE_DATA_BUFFER
-{
- ULONG ReparseTag;
- USHORT ReparseDataLength;
- USHORT Reserved;
- union
- {
- struct
- {
- USHORT SubstituteNameOffset;
- USHORT SubstituteNameLength;
- USHORT PrintNameOffset;
- USHORT PrintNameLength;
- ULONG Flags;
- WCHAR PathBuffer[1];
- } SymbolicLinkReparseBuffer;
- struct
- {
- USHORT SubstituteNameOffset;
- USHORT SubstituteNameLength;
- USHORT PrintNameOffset;
- USHORT PrintNameLength;
- WCHAR PathBuffer[1];
- } MountPointReparseBuffer;
- struct
- {
- UCHAR DataBuffer[1];
- } GenericReparseBuffer;
- };
-} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
-#define REPARSE_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer)
-#endif
-
-
-Zstring getSymlinkTarget(const Zstring& linkPath) //throw(); returns empty string on error
-{
-#ifdef FFS_WIN
-//FSCTL_GET_REPARSE_POINT: http://msdn.microsoft.com/en-us/library/aa364571(VS.85).aspx
-
- const HANDLE hLink = ::CreateFile(linkPath.c_str(),
- GENERIC_READ,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- NULL,
- OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
- NULL);
- if (hLink == INVALID_HANDLE_VALUE)
- return Zstring();
-
- boost::shared_ptr<void> dummy(hLink, ::CloseHandle);
-
- //respect alignment issues...
- const size_t bufferSize = REPARSE_DATA_BUFFER_HEADER_SIZE + MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
- boost::scoped_array<char> buffer(new char[bufferSize]);
-
- DWORD bytesReturned; //dummy value required by FSCTL_GET_REPARSE_POINT!
- if (!::DeviceIoControl(hLink, //__in HANDLE hDevice,
- FSCTL_GET_REPARSE_POINT, //__in DWORD dwIoControlCode,
- NULL, //__in_opt LPVOID lpInBuffer,
- 0, //__in DWORD nInBufferSize,
- buffer.get(), //__out_opt LPVOID lpOutBuffer,
- bufferSize, //__in DWORD nOutBufferSize,
- &bytesReturned, //__out_opt LPDWORD lpBytesReturned,
- NULL)) //__inout_opt LPOVERLAPPED lpOverlapped
- return Zstring();
-
- REPARSE_DATA_BUFFER& reparseData = *reinterpret_cast<REPARSE_DATA_BUFFER*>(buffer.get()); //REPARSE_DATA_BUFFER needs to be artificially enlarged!
-
- if (reparseData.ReparseTag == IO_REPARSE_TAG_SYMLINK)
- return Zstring(reparseData.SymbolicLinkReparseBuffer.PathBuffer + reparseData.SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR),
- reparseData.SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(WCHAR));
- else if (reparseData.ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
- return Zstring(reparseData.MountPointReparseBuffer.PathBuffer + reparseData.MountPointReparseBuffer.SubstituteNameOffset / sizeof(WCHAR),
- reparseData.MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR));
- else
- return Zstring(); //unknown reparse point
-
-#elif defined FFS_LINUX
- const int BUFFER_SIZE = 10000;
- char buffer[BUFFER_SIZE];
-
- const int bytesWritten = ::readlink(linkPath.c_str(), buffer, BUFFER_SIZE);
- if (bytesWritten < 0 || bytesWritten >= BUFFER_SIZE)
- return Zstring(); //error
-
- buffer[bytesWritten] = 0; //set null-terminating char
-
- return buffer;
-#endif
-}
-
-
#ifdef FFS_WIN
inline
wxLongLong getWin32TimeInformation(const FILETIME& lastWriteTime)
@@ -292,8 +166,13 @@ private:
if (isSymbolicLink && !followSymlinks) //evaluate symlink directly
{
TraverseCallback::SymlinkInfo details;
+ try
+ {
+ details.targetPath = getSymlinkRawTargetString(fullName); //throw (FileError)
+ }
+ catch (FileError&) {}
+
details.lastWriteTimeRaw = getWin32TimeInformation(fileMetaData.ftLastWriteTime);
- details.targetPath = getSymlinkTarget(fullName); //throw(); returns empty string on error
details.dirLink = (fileMetaData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; //directory symlinks have this flag on Windows
sink.onSymlink(shortName, fullName, details);
}
@@ -418,8 +297,13 @@ private:
else //evaluate symlink directly
{
TraverseCallback::SymlinkInfo details;
+ try
+ {
+ details.targetPath = getSymlinkRawTargetString(fullName); //throw (FileError)
+ }
+ catch (FileError&) {}
+
details.lastWriteTimeRaw = fileInfo.st_mtime; //UTC time(ANSI C format); unit: 1 second
- details.targetPath = getSymlinkTarget(fullName); //throw(); returns empty string on error
details.dirLink = ::stat(fullName.c_str(), &fileInfo) == 0 && S_ISDIR(fileInfo.st_mode); //S_ISDIR and S_ISLNK are mutually exclusive on Linux => need to follow link
sink.onSymlink(shortName, fullName, details);
continue;
diff --git a/shared/global_func.h b/shared/global_func.h
index c3994ca0..20221f63 100644
--- a/shared/global_func.h
+++ b/shared/global_func.h
@@ -192,7 +192,7 @@ template <class ForwardIterator, class T, typename Compare>
inline
ForwardIterator common::custom_binary_search(ForwardIterator first, ForwardIterator last, const T& value, Compare comp)
{
- first = lower_bound(first, last, value, comp);
+ first = std::lower_bound(first, last, value, comp);
if (first != last && !comp(value, *first))
return first;
else
diff --git a/shared/localization.cpp b/shared/localization.cpp
index ef3e02d2..ae9b5143 100644
--- a/shared/localization.cpp
+++ b/shared/localization.cpp
@@ -48,7 +48,7 @@ const std::vector<ffs3::LocInfoLine>& LocalizationInfo::getMapping()
namespace
{
-struct CompareByName
+ struct CompareByName : public std::binary_function<ffs3::LocInfoLine, ffs3::LocInfoLine, bool>
{
bool operator()(const ffs3::LocInfoLine& lhs, const ffs3::LocInfoLine& rhs) const
{
@@ -121,7 +121,7 @@ LocalizationInfo::LocalizationInfo()
newEntry.languageID = wxLANGUAGE_DUTCH;
newEntry.languageName = wxT("Nederlands");
newEntry.languageFile = wxT("dutch.lng");
- newEntry.translatorName = wxT("Mikhail Frolov");
+ newEntry.translatorName = wxT("Dion van Lieshout");
newEntry.languageFlag = wxT("holland.png");
locMapping.push_back(newEntry);
@@ -184,7 +184,7 @@ LocalizationInfo::LocalizationInfo()
newEntry.languageID = wxLANGUAGE_TURKISH;
newEntry.languageName = wxT("Türkçe");
newEntry.languageFile = wxT("turkish.lng");
- newEntry.translatorName = wxT("H.Barbaros BIÇAKCI");
+ newEntry.translatorName = wxT("Kaya Zeren");
newEntry.languageFlag = wxT("turkey.png");
locMapping.push_back(newEntry);
@@ -481,7 +481,7 @@ private:
};
-void CustomLocale::setLanguage(const int language)
+void CustomLocale::setLanguage(int language)
{
currentLanguage = language;
@@ -544,3 +544,24 @@ const wxChar* CustomLocale::GetString(const wxChar* szOrigString, const wxChar*
//fallback
return szOrigString;
}
+
+
+
+/*
+
+wxWidgets 2.9.1:
+
+class CustomTranslation : public wxTranslations
+{
+ virtual const wxString& GetString(const wxString& origString,
+ const wxString& domain = wxEmptyString) const
+ {
+ static const wxString blah = "map origString to translation by some arbitrary means";
+ return blah;
+ }
+
+ wxTranslations::Set(new CustomTranslation);
+
+};
+
+*/
diff --git a/shared/localization.h b/shared/localization.h
index 1c1773e9..9435030d 100644
--- a/shared/localization.h
+++ b/shared/localization.h
@@ -49,7 +49,7 @@ class CustomLocale : public wxLocale
public:
static CustomLocale& getInstance();
- void setLanguage(const int language);
+ void setLanguage(int language);
int getLanguage() const
{
diff --git a/shared/recycler.cpp b/shared/recycler.cpp
index 31257a65..2ee23462 100644
--- a/shared/recycler.cpp
+++ b/shared/recycler.cpp
@@ -88,11 +88,13 @@ void moveToWindowsRecycler(const std::vector<Zstring>& filesToDelete) //throw (
using namespace fileop;
- static const MoveToRecycleBinFct moveToRecycler =
- util::getDllFun<MoveToRecycleBinFct>(getRecyclerDllName().c_str(), moveToRecycleBinFctName);
+ static MoveToRecycleBinFct moveToRecycler = NULL;
+ if (!moveToRecycler)
+ moveToRecycler = util::getDllFun<MoveToRecycleBinFct>(getRecyclerDllName().c_str(), moveToRecycleBinFctName);
- static const GetLastErrorFct getLastError =
- util::getDllFun<GetLastErrorFct>(getRecyclerDllName().c_str(), getLastErrorFctName);
+ static GetLastErrorFct getLastError = NULL;
+ if (!getLastError)
+ getLastError = util::getDllFun<GetLastErrorFct>(getRecyclerDllName().c_str(), getLastErrorFctName);
if (moveToRecycler == NULL || getLastError == NULL)
throw FileError(wxString(_("Error moving to Recycle Bin:")) + wxT("\n\"") + fileNames[0] + wxT("\"\n\n") + //report first file only... better than nothing
diff --git a/shared/serialize.cpp b/shared/serialize.cpp
index cf6d96b1..f5765d3d 100644
--- a/shared/serialize.cpp
+++ b/shared/serialize.cpp
@@ -51,5 +51,3 @@ void WriteOutputStream::writeArrayC(const std::vector<char>& buffer) const
throwWriteError();
}
}
-
-
diff --git a/shared/serialize.h b/shared/serialize.h
index 7c4fcd5e..5f1d5fbf 100644
--- a/shared/serialize.h
+++ b/shared/serialize.h
@@ -12,6 +12,7 @@
#include "file_error.h"
#include <boost/scoped_array.hpp>
#include <boost/shared_ptr.hpp>
+#include <boost/cstdint.hpp>
namespace util
{
@@ -126,7 +127,7 @@ void writeNumber(wxOutputStream& stream, T number)
inline
-Zstring readString(wxInputStream& stream) //read string from file stream
+Zstring readString(wxInputStream& stream)
{
const size_t strLength = readNumber<size_t>(stream);
if (strLength <= 1000)
@@ -145,7 +146,7 @@ Zstring readString(wxInputStream& stream) //read string from file stream
inline
-void writeString(wxOutputStream& stream, const Zstring& str) //write string to filestream
+void writeString(wxOutputStream& stream, const Zstring& str)
{
writeNumber<size_t>(stream, str.length());
stream.Write(str.c_str(), sizeof(Zchar) * str.length());
diff --git a/shared/signal_processing.h b/shared/signal_processing.h
deleted file mode 100644
index 857d0b12..00000000
--- a/shared/signal_processing.h
+++ /dev/null
@@ -1,166 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) 2008-2010 ZenJu (zhnmju123 AT gmx.de) *
-// **************************************************************************
-//
-#include <algorithm>
-#include <limits>
-#include <numeric>
-
-
-namespace util
-{
-template <class T>
-T abs(T value);
-
-int round(double d); //little rounding function
-
-template <class T>
-bool isNull(T number);
-
-//----------------------------------------------------------------------------------
-// smoothen data ranges through a window around each data point |
-//----------------------------------------------------------------------------------
-template <class InputIterator, class OutputIterator>
-void smoothen(InputIterator first, InputIterator last, OutputIterator result, size_t windowSize); //default implementation: averaging
-
-template <class InputIterator, class OutputIterator, class DataProcessor>
-void smoothen(InputIterator first, InputIterator last, OutputIterator result, size_t windowSize, DataProcessor proc);
-/*
-DataProcessor is an abstraction for data evaluation. A valid implementation needs to support three properties:
-- add data entry at window front: operator+=(ValueType value)
-- remove data entry at window back: operator-=(ValueType value)
-- evaluate smoothed middle value: ValueType operator()(size_t windowSize)
-*/
-//----------------------------------------------------------------------------------
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-//################# inline implementation #########################
-template <class T>
-inline
-T abs(T value)
-{
- return value < 0 ? -value : value;
-}
-
-
-template <class T>
-inline
-bool isNull(T value)
-{
- return abs(number) <= std::numeric_limits<T>::epsilon(); //epsilon == 0 for integer types, therefore less-equal(!)
-}
-
-
-inline
-int round(double d)
-{
- return static_cast<int>(d < 0 ? d - .5 : d + .5);
-}
-
-
-template <class InputIterator, class OutputIterator, class DataProcessor>
-inline
-void smoothen(InputIterator first, InputIterator last, OutputIterator result, size_t windowSize, DataProcessor proc)
-{
- windowSize = std::min(windowSize, static_cast<size_t>(last - first)); //std::distance() not used to enforce random access iterator requirement
-
- if (windowSize <= 1)
- {
- std::copy(first, last, result);
- return;
- }
-
- const size_t firstHalf = windowSize / 2;
- const size_t secondHalf = windowSize - firstHalf;
-
- //preparation
- for (InputIterator i = first; i != first + secondHalf; ++i)
- proc += *i;
-
- //beginning
- for (InputIterator i = first; i != first + firstHalf; ++i)
- {
- *result++ = proc(i - first + secondHalf);
- proc += *(i + secondHalf);
- }
-
- //main
- for (InputIterator i = first + firstHalf; i != last - secondHalf; ++i)
- {
- *result++ = proc(windowSize);
- proc += *(i + secondHalf);
- proc -= *(i - firstHalf);
- }
-
- //ending
- for (InputIterator i = last - secondHalf; i != last; ++i)
- {
- *result++ = proc(windowSize - (i - last + secondHalf));
- proc -= *(i - firstHalf);
- }
-}
-
-
-template <class ValueType>
-class ProcessorAverage
-{
-public:
- ProcessorAverage() : valueAcc() {}
-
- //add front data entry
- ProcessorAverage& operator+=(ValueType value)
- {
- valueAcc += value;
- return *this;
- }
-
- //remove rear data entry
- ProcessorAverage& operator-=(ValueType value)
- {
- valueAcc -= value;
- return *this;
- }
-
- //evaluate smoothed value
- ValueType operator()(size_t windowSize) const
- {
- return valueAcc / windowSize;
- }
-
-private:
- ValueType valueAcc; //accumulated values
-};
-
-
-
-template <class InputIterator, class OutputIterator>
-inline
-void smoothen(InputIterator first, InputIterator last, OutputIterator result, size_t windowSize)
-{
- typedef typename std::iterator_traits<InputIterator>::value_type ValueType;
- smoothen(first, last, result, windowSize, ProcessorAverage<ValueType>());
-}
-
-} \ No newline at end of file
diff --git a/shared/symlink_target.h b/shared/symlink_target.h
new file mode 100644
index 00000000..c68d5229
--- /dev/null
+++ b/shared/symlink_target.h
@@ -0,0 +1,146 @@
+// **************************************************************************
+// * This file is part of the FreeFileSync project. It is distributed under *
+// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
+// * Copyright (C) 2008-2010 ZenJu (zhnmju123 AT gmx.de) *
+// **************************************************************************
+//
+#ifndef SYMLINK_WIN_H_INCLUDED
+#define SYMLINK_WIN_H_INCLUDED
+
+#include <boost/shared_ptr.hpp>
+#include <boost/scoped_array.hpp>
+#include "system_func.h"
+#include <wx/intl.h>
+#include "string_conv.h"
+#include "file_error.h"
+
+#ifdef FFS_WIN
+#include <wx/msw/wrapwin.h> //includes "windows.h"
+#include "WinIoCtl.h"
+#include "long_path_prefix.h"
+
+#elif defined FFS_LINUX
+#include <unistd.h>
+#endif
+
+
+#ifdef _MSC_VER //I don't have Windows Driver Kit at hands right now, so unfortunately we need to redefine this structures and cross fingers...
+typedef struct _REPARSE_DATA_BUFFER
+{
+ ULONG ReparseTag;
+ USHORT ReparseDataLength;
+ USHORT Reserved;
+ union
+ {
+ struct
+ {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ ULONG Flags;
+ WCHAR PathBuffer[1];
+ } SymbolicLinkReparseBuffer;
+ struct
+ {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ WCHAR PathBuffer[1];
+ } MountPointReparseBuffer;
+ struct
+ {
+ UCHAR DataBuffer[1];
+ } GenericReparseBuffer;
+ };
+} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
+#define REPARSE_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer)
+#endif
+
+namespace
+{
+ //retrieve raw target data of symlink or junction
+Zstring getSymlinkRawTargetString(const Zstring& linkPath) //throw (FileError)
+{
+ using ffs3::zToWx;
+ using ffs3::FileError;
+#ifdef FFS_WIN
+//FSCTL_GET_REPARSE_POINT: http://msdn.microsoft.com/en-us/library/aa364571(VS.85).aspx
+
+ const HANDLE hLink = ::CreateFile(ffs3::applyLongPathPrefix(linkPath).c_str(),
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
+ NULL);
+ if (hLink == INVALID_HANDLE_VALUE)
+ {
+ wxString errorMessage = wxString(_("Error resolving symbolic link:")) + wxT("\n\"") + ffs3::zToWx(linkPath) + wxT("\"");
+ throw FileError(errorMessage + wxT("\n\n") + ffs3::getLastErrorFormatted());
+ }
+ boost::shared_ptr<void> dummy(hLink, ::CloseHandle);
+
+ //respect alignment issues...
+ const size_t bufferSize = REPARSE_DATA_BUFFER_HEADER_SIZE + MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
+ boost::scoped_array<char> buffer(new char[bufferSize]);
+
+ DWORD bytesReturned; //dummy value required by FSCTL_GET_REPARSE_POINT!
+ if (!::DeviceIoControl(hLink, //__in HANDLE hDevice,
+ FSCTL_GET_REPARSE_POINT, //__in DWORD dwIoControlCode,
+ NULL, //__in_opt LPVOID lpInBuffer,
+ 0, //__in DWORD nInBufferSize,
+ buffer.get(), //__out_opt LPVOID lpOutBuffer,
+ bufferSize, //__in DWORD nOutBufferSize,
+ &bytesReturned, //__out_opt LPDWORD lpBytesReturned,
+ NULL)) //__inout_opt LPOVERLAPPED lpOverlapped
+ {
+ wxString errorMessage = wxString(_("Error resolving symbolic link:")) + wxT("\n\"") + ffs3::zToWx(linkPath) + wxT("\"");
+ throw FileError(errorMessage + wxT("\n\n") + ffs3::getLastErrorFormatted());
+ }
+
+ REPARSE_DATA_BUFFER& reparseData = *reinterpret_cast<REPARSE_DATA_BUFFER*>(buffer.get()); //REPARSE_DATA_BUFFER needs to be artificially enlarged!
+
+ Zstring output;
+ if (reparseData.ReparseTag == IO_REPARSE_TAG_SYMLINK)
+ {
+ output = Zstring(reparseData.SymbolicLinkReparseBuffer.PathBuffer + reparseData.SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR),
+ reparseData.SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(WCHAR));
+ }
+ else if (reparseData.ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
+ {
+ output = Zstring(reparseData.MountPointReparseBuffer.PathBuffer + reparseData.MountPointReparseBuffer.SubstituteNameOffset / sizeof(WCHAR),
+ reparseData.MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR));
+ }
+ else
+ {
+ wxString errorMessage = wxString(_("Error resolving symbolic link:")) + wxT("\n\"") + ffs3::zToWx(linkPath) + wxT("\"");
+ throw FileError(errorMessage + wxT("\n\n") + wxT("Not a symbolic link or junction!"));
+ }
+
+ //absolute symlinks and junctions technically start with \??\ while relative ones do not
+ if (output.StartsWith(Zstr("\\??\\")))
+ output = Zstring(output.c_str() + 4, output.length() - 4);
+
+ return output;
+
+#elif defined FFS_LINUX
+ const int BUFFER_SIZE = 10000;
+ char buffer[BUFFER_SIZE];
+
+ const int bytesWritten = ::readlink(linkPath.c_str(), buffer, BUFFER_SIZE);
+ if (bytesWritten < 0 || bytesWritten >= BUFFER_SIZE)
+ {
+ wxString errorMessage = wxString(_("Error resolving symbolic link:")) + wxT("\n\"") + zToWx(linkPath) + wxT("\"");
+ if (bytesWritten < 0) errorMessage += wxString(wxT("\n\n")) + ffs3::getLastErrorFormatted();
+ throw FileError(errorMessage);
+ }
+ buffer[bytesWritten] = 0; //set null-terminating char
+
+ return buffer;
+#endif
+}
+}
+
+#endif // SYMLINK_WIN_H_INCLUDED
diff --git a/shared/system_func.cpp b/shared/system_func.cpp
index 71335d71..4f60f724 100644
--- a/shared/system_func.cpp
+++ b/shared/system_func.cpp
@@ -25,11 +25,20 @@ wxString ffs3::getLastErrorFormatted(unsigned long lastError) //try to get addit
wxString output = wxString(wxT("Windows Error Code ")) + wxString::Format(wxT("%u"), lastError);
- WCHAR buffer[1001];
- if (::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_MAX_WIDTH_MASK, 0, lastError, 0, buffer, 1001, NULL) != 0)
- output += wxString(wxT(": ")) + buffer;
+ LPWSTR buffer = NULL;
+ if (::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_MAX_WIDTH_MASK |
+ FORMAT_MESSAGE_IGNORE_INSERTS | //important: without this flag ::FormatMessage() will fail if message contains placeholders
+ FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, lastError, 0, reinterpret_cast<LPWSTR>(&buffer), 0, NULL) != 0)
+ {
+ if (buffer) //just to be sure
+ {
+ output += wxString(wxT(": ")) + buffer;
+ ::LocalFree(buffer);
+ }
+ }
+ ::SetLastError(lastError); //restore last error
- ::SetLastError(lastError); //restore last error
return output;
}
diff --git a/shared/zbase.h b/shared/zbase.h
index efaa103c..1caf0e44 100644
--- a/shared/zbase.h
+++ b/shared/zbase.h
@@ -289,22 +289,22 @@ private:
};
template <class T, template <class, class> class SP, class AP> bool operator==(const Zbase<T, SP, AP>& lhs, const Zbase<T, SP, AP>& rhs);
-template <class T, template <class, class> class SP, class AP> bool operator==(const Zbase<T, SP, AP>& lhs, const T* rhs);
-template <class T, template <class, class> class SP, class AP> bool operator==(const T* lhs, const Zbase<T, SP, AP>& rhs);
+template <class T, template <class, class> class SP, class AP> bool operator==(const Zbase<T, SP, AP>& lhs, const T* rhs);
+template <class T, template <class, class> class SP, class AP> bool operator==(const T* lhs, const Zbase<T, SP, AP>& rhs);
template <class T, template <class, class> class SP, class AP> bool operator!=(const Zbase<T, SP, AP>& lhs, const Zbase<T, SP, AP>& rhs);
-template <class T, template <class, class> class SP, class AP> bool operator!=(const Zbase<T, SP, AP>& lhs, const T* rhs);
-template <class T, template <class, class> class SP, class AP> bool operator!=(const T* lhs, const Zbase<T, SP, AP>& rhs);
+template <class T, template <class, class> class SP, class AP> bool operator!=(const Zbase<T, SP, AP>& lhs, const T* rhs);
+template <class T, template <class, class> class SP, class AP> bool operator!=(const T* lhs, const Zbase<T, SP, AP>& rhs);
template <class T, template <class, class> class SP, class AP> bool operator< (const Zbase<T, SP, AP>& lhs, const Zbase<T, SP, AP>& rhs);
-template <class T, template <class, class> class SP, class AP> bool operator< (const Zbase<T, SP, AP>& lhs, const T* rhs);
-template <class T, template <class, class> class SP, class AP> bool operator< (const T* lhs, const Zbase<T, SP, AP>& rhs);
+template <class T, template <class, class> class SP, class AP> bool operator< (const Zbase<T, SP, AP>& lhs, const T* rhs);
+template <class T, template <class, class> class SP, class AP> bool operator< (const T* lhs, const Zbase<T, SP, AP>& rhs);
template <class T, template <class, class> class SP, class AP> const Zbase<T, SP, AP> operator+(const Zbase<T, SP, AP>& lhs, const Zbase<T, SP, AP>& rhs);
-template <class T, template <class, class> class SP, class AP> const Zbase<T, SP, AP> operator+(const Zbase<T, SP, AP>& lhs, const T* rhs);
-template <class T, template <class, class> class SP, class AP> const Zbase<T, SP, AP> operator+(const T* lhs, const Zbase<T, SP, AP>& rhs);
-template <class T, template <class, class> class SP, class AP> const Zbase<T, SP, AP> operator+( T lhs, const Zbase<T, SP, AP>& rhs);
-template <class T, template <class, class> class SP, class AP> const Zbase<T, SP, AP> operator+(const Zbase<T, SP, AP>& lhs, T rhs);
+template <class T, template <class, class> class SP, class AP> const Zbase<T, SP, AP> operator+(const Zbase<T, SP, AP>& lhs, const T* rhs);
+template <class T, template <class, class> class SP, class AP> const Zbase<T, SP, AP> operator+(const T* lhs, const Zbase<T, SP, AP>& rhs);
+template <class T, template <class, class> class SP, class AP> const Zbase<T, SP, AP> operator+( T lhs, const Zbase<T, SP, AP>& rhs);
+template <class T, template <class, class> class SP, class AP> const Zbase<T, SP, AP> operator+(const Zbase<T, SP, AP>& lhs, T rhs);
bgstack15