summaryrefslogtreecommitdiff
path: root/zen/symlink_target.h
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 17:24:35 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 17:24:35 +0200
commit460091fb0b2ff114cc741372f15bb43b702ea3b1 (patch)
tree0562c2eda4c66969c6e6d0910080db9f5b0def3e /zen/symlink_target.h
parent5.15 (diff)
downloadFreeFileSync-460091fb0b2ff114cc741372f15bb43b702ea3b1.tar.gz
FreeFileSync-460091fb0b2ff114cc741372f15bb43b702ea3b1.tar.bz2
FreeFileSync-460091fb0b2ff114cc741372f15bb43b702ea3b1.zip
5.16
Diffstat (limited to 'zen/symlink_target.h')
-rw-r--r--zen/symlink_target.h73
1 files changed, 61 insertions, 12 deletions
diff --git a/zen/symlink_target.h b/zen/symlink_target.h
index 95aa84fb..bbced0fa 100644
--- a/zen/symlink_target.h
+++ b/zen/symlink_target.h
@@ -4,8 +4,8 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef SYMLINK_WIN_H_INCLUDED
-#define SYMLINK_WIN_H_INCLUDED
+#ifndef SYMLINK_80178347019835748321473214
+#define SYMLINK_80178347019835748321473214
#include "scope_guard.h"
#include "file_error.h"
@@ -15,6 +15,7 @@
#include "WinIoCtl.h"
#include "privilege.h"
#include "long_path_prefix.h"
+#include "dll.h"
#elif defined FFS_LINUX || defined FFS_MAC
#include <unistd.h>
@@ -26,9 +27,11 @@ namespace zen
#ifdef FFS_WIN
bool isSymlink(const WIN32_FIND_DATA& data); //*not* a simple FILE_ATTRIBUTE_REPARSE_POINT check!
bool isSymlink(DWORD fileAttributes, DWORD reparseTag);
+
+Zstring getResolvedFilePath(const Zstring& filename); //throw FileError; requires Vista or later!
#endif
-Zstring getSymlinkRawTargetString(const Zstring& linkPath); //throw FileError
+Zstring getSymlinkTargetRaw(const Zstring& linkPath); //throw FileError
}
@@ -90,7 +93,7 @@ Zstring getSymlinkRawTargetString_impl(const Zstring& linkPath) //throw FileErro
catch (FileError&) {} //This shall not cause an error in user mode!
const HANDLE hLink = ::CreateFile(applyLongPathPrefix(linkPath).c_str(),
- GENERIC_READ,
+ 0, //it seems we do not even need GENERIC_READ!
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
nullptr,
OPEN_EXISTING,
@@ -138,32 +141,78 @@ Zstring getSymlinkRawTargetString_impl(const Zstring& linkPath) //throw FileErro
return output;
#elif defined FFS_LINUX || defined FFS_MAC
- const int BUFFER_SIZE = 10000;
+ const size_t BUFFER_SIZE = 10000;
std::vector<char> buffer(BUFFER_SIZE);
- const int bytesWritten = ::readlink(linkPath.c_str(), &buffer[0], BUFFER_SIZE);
- if (bytesWritten < 0 || bytesWritten >= BUFFER_SIZE)
+ const ssize_t bytesWritten = ::readlink(linkPath.c_str(), &buffer[0], BUFFER_SIZE);
+ if (bytesWritten < 0 || bytesWritten >= static_cast<ssize_t>(BUFFER_SIZE)) //detect truncation!
{
std::wstring errorMessage = replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtFileName(linkPath));
if (bytesWritten < 0)
errorMessage += L"\n\n" + getLastErrorFormatted();
throw FileError(errorMessage);
}
- buffer[bytesWritten] = 0; //set null-terminating char
-
- return Zstring(&buffer[0], bytesWritten);
+ return Zstring(&buffer[0], bytesWritten); //readlink does not append 0-termination!
#endif
}
+
+
+#ifdef FFS_WIN
+Zstring getResolvedFilePath_impl(const Zstring& filename) //throw FileError
+{
+ using namespace zen;
+
+ const HANDLE hDir = ::CreateFile(applyLongPathPrefix(filename).c_str(),
+ 0,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ nullptr,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, //needed to open a directory
+ nullptr);
+ if (hDir == INVALID_HANDLE_VALUE)
+ throw FileError(replaceCpy(_("Cannot determine final path for %x."), L"%x", fmtFileName(filename)) + L"\n\n" + getLastErrorFormatted() + L" (CreateFile)");
+ ZEN_ON_SCOPE_EXIT(::CloseHandle(hDir));
+
+ //GetFinalPathNameByHandle() is not available before Vista!
+ typedef DWORD (WINAPI* GetFinalPathNameByHandleWFunc)(HANDLE hFile, LPTSTR lpszFilePath, DWORD cchFilePath, DWORD dwFlags);
+ const SysDllFun<GetFinalPathNameByHandleWFunc> getFinalPathNameByHandle(L"kernel32.dll", "GetFinalPathNameByHandleW");
+
+ if (!getFinalPathNameByHandle)
+ throw FileError(replaceCpy(_("Cannot find system function %x."), L"%x", L"\"GetFinalPathNameByHandleW\""));
+
+ const DWORD bufferSize = getFinalPathNameByHandle(hDir, nullptr, 0, 0);
+ if (bufferSize == 0)
+ throw FileError(replaceCpy(_("Cannot determine final path for %x."), L"%x", fmtFileName(filename)) + L"\n\n" + getLastErrorFormatted());
+
+ std::vector<wchar_t> targetPath(bufferSize);
+ const DWORD charsWritten = getFinalPathNameByHandle(hDir, //__in HANDLE hFile,
+ &targetPath[0], //__out LPTSTR lpszFilePath,
+ bufferSize, //__in DWORD cchFilePath,
+ 0); //__in DWORD dwFlags
+ if (charsWritten == 0 || charsWritten >= bufferSize)
+ {
+ std::wstring errorMessage = replaceCpy(_("Cannot determine final path for %x."), L"%x", fmtFileName(filename));
+ if (charsWritten == 0)
+ errorMessage += L"\n\n" + getLastErrorFormatted();
+ throw FileError(errorMessage);
+ }
+
+ return Zstring(&targetPath[0], charsWritten);
+}
+#endif
}
namespace zen
{
inline
-Zstring getSymlinkRawTargetString(const Zstring& linkPath) { return getSymlinkRawTargetString_impl(linkPath); }
+Zstring getSymlinkTargetRaw(const Zstring& linkPath) { return getSymlinkRawTargetString_impl(linkPath); }
#ifdef FFS_WIN
+inline
+Zstring getResolvedFilePath(const Zstring& filename) { return getResolvedFilePath_impl(filename); }
+
/*
Reparse Point Tags
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365511(v=vs.85).aspx
@@ -190,4 +239,4 @@ bool isSymlink(const WIN32_FIND_DATA& data)
#endif
}
-#endif // SYMLINK_WIN_H_INCLUDED
+#endif //SYMLINK_80178347019835748321473214
bgstack15