diff --git a/Foundation/include/Poco/File.h b/Foundation/include/Poco/File.h index fd7f248a0..02601f084 100644 --- a/Foundation/include/Poco/File.h +++ b/Foundation/include/Poco/File.h @@ -60,6 +60,13 @@ class Foundation_API File: private FileImpl public: typedef FileSizeImpl FileSize; + enum LinkType + /// Type of link for linkTo(). + { + LINK_HARD = 0, /// hard link + LINK_SYMBOLIC = 1 /// symbolic link + }; + File(); /// Creates the file. @@ -186,6 +193,14 @@ public: void renameTo(const std::string& path); /// Renames the file to the new name. + void linkTo(const std::string& path, LinkType type = LINK_SYMBOLIC) const; + /// Creates a link (symbolic or hard, depending on type argument) + /// at the given path to the file or directory. + /// + /// May not be supported on all platforms. + /// Furthermore, some operating systems do not allow creating + /// hard links to directories. + void remove(bool recursive = false); /// Deletes the file. If recursive is true and the /// file is a directory, recursively deletes all diff --git a/Foundation/include/Poco/File_UNIX.h b/Foundation/include/Poco/File_UNIX.h index 47ad07525..cdf843b85 100644 --- a/Foundation/include/Poco/File_UNIX.h +++ b/Foundation/include/Poco/File_UNIX.h @@ -54,6 +54,7 @@ protected: void setExecutableImpl(bool flag = true); void copyToImpl(const std::string& path) const; void renameToImpl(const std::string& path); + void linkToImpl(const std::string& path, int type) const; void removeImpl(); bool createFileImpl(); bool createDirectoryImpl(); diff --git a/Foundation/include/Poco/File_VX.h b/Foundation/include/Poco/File_VX.h index 77869f72a..f4b195c4f 100644 --- a/Foundation/include/Poco/File_VX.h +++ b/Foundation/include/Poco/File_VX.h @@ -53,6 +53,7 @@ protected: void setExecutableImpl(bool flag = true); void copyToImpl(const std::string& path) const; void renameToImpl(const std::string& path); + void linkToImpl(const std::string& path, int type) const; void removeImpl(); bool createFileImpl(); bool createDirectoryImpl(); diff --git a/Foundation/include/Poco/File_WIN32.h b/Foundation/include/Poco/File_WIN32.h index a2f9e00d1..d979724b0 100644 --- a/Foundation/include/Poco/File_WIN32.h +++ b/Foundation/include/Poco/File_WIN32.h @@ -54,6 +54,7 @@ protected: void setExecutableImpl(bool flag = true); void copyToImpl(const std::string& path) const; void renameToImpl(const std::string& path); + void linkToImpl(const std::string& path, int type) const; void removeImpl(); bool createFileImpl(); bool createDirectoryImpl(); diff --git a/Foundation/include/Poco/File_WINCE.h b/Foundation/include/Poco/File_WINCE.h index e44f5398a..c036ff060 100644 --- a/Foundation/include/Poco/File_WINCE.h +++ b/Foundation/include/Poco/File_WINCE.h @@ -54,6 +54,7 @@ protected: void setExecutableImpl(bool flag = true); void copyToImpl(const std::string& path) const; void renameToImpl(const std::string& path); + void linkToImpl(const std::string& path, int type) const; void removeImpl(); bool createFileImpl(); bool createDirectoryImpl(); diff --git a/Foundation/src/File.cpp b/Foundation/src/File.cpp index d3e2e7dea..0f58a3471 100644 --- a/Foundation/src/File.cpp +++ b/Foundation/src/File.cpp @@ -260,6 +260,12 @@ void File::renameTo(const std::string& rPath) } +void File::linkTo(const std::string& rPath, LinkType type) const +{ + linkToImpl(rPath, type); +} + + void File::remove(bool recursive) { if (recursive && !isLink() && isDirectory()) diff --git a/Foundation/src/File_UNIX.cpp b/Foundation/src/File_UNIX.cpp index 28ec8619f..394f2024e 100644 --- a/Foundation/src/File_UNIX.cpp +++ b/Foundation/src/File_UNIX.cpp @@ -414,6 +414,23 @@ void FileImpl::renameToImpl(const std::string& path) } +void FileImpl::linkToImpl(const std::string& path, int type) const +{ + poco_assert (!_path.empty()); + + if (type == 0) + { + if (link(_path.c_str(), path.c_str()) != 0) + handleLastErrorImpl(_path); + } + else + { + if (symlink(_path.c_str(), path.c_str()) != 0) + handleLastErrorImpl(_path); + } +} + + void FileImpl::removeImpl() { poco_assert (!_path.empty()); diff --git a/Foundation/src/File_VX.cpp b/Foundation/src/File_VX.cpp index 316c439f6..714c25708 100644 --- a/Foundation/src/File_VX.cpp +++ b/Foundation/src/File_VX.cpp @@ -285,6 +285,12 @@ void FileImpl::renameToImpl(const std::string& path) } +void FileImpl::linkToImpl(const std::string& path, int type) const +{ + throw Poco::NotImplementedException("File::linkTo() is not available on this platform"); +} + + void FileImpl::removeImpl() { poco_assert (!_path.empty()); diff --git a/Foundation/src/File_WIN32.cpp b/Foundation/src/File_WIN32.cpp index b504392a5..1c3877a8d 100644 --- a/Foundation/src/File_WIN32.cpp +++ b/Foundation/src/File_WIN32.cpp @@ -167,7 +167,12 @@ bool FileImpl::isDirectoryImpl() const bool FileImpl::isLinkImpl() const { - return false; + poco_assert (!_path.empty()); + + DWORD attr = GetFileAttributesW(_upath.c_str()); + if (attr == INVALID_FILE_ATTRIBUTES) + handleLastErrorImpl(_path); + return (attr & FILE_ATTRIBUTE_DIRECTORY) == 0 && (attr & FILE_ATTRIBUTE_REPARSE_POINT) != 0; } @@ -308,6 +313,35 @@ void FileImpl::renameToImpl(const std::string& path) } +void FileImpl::linkToImpl(const std::string& path, int type) const +{ + poco_assert (!_path.empty()); + + std::wstring upath; + convertPath(path, upath); + + if (type == 0) + { + if (CreateHardLinkW(upath.c_str(), _upath.c_str(), NULL) == 0) + handleLastErrorImpl(_path); + } + else + { +#if _WIN32_WINNT >= 0x0600 && defined(SYMBOLIC_LINK_FLAG_DIRECTORY) + DWORD flags = 0; + if (isDirectoryImpl()) flags |= SYMBOLIC_LINK_FLAG_DIRECTORY; +#ifdef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE + flags |= SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE; +#endif + if (CreateSymbolicLinkW(upath.c_str(), _upath.c_str(), flags) == 0) + handleLastErrorImpl(_path); +#else + throw Poco::NotImplementedException("Symbolic link support not available in used version of the Windows SDK"); +#endif + } +} + + void FileImpl::removeImpl() { poco_assert (!_path.empty()); diff --git a/Foundation/src/File_WINCE.cpp b/Foundation/src/File_WINCE.cpp index c6b98066c..669b2a8c3 100644 --- a/Foundation/src/File_WINCE.cpp +++ b/Foundation/src/File_WINCE.cpp @@ -299,6 +299,12 @@ void FileImpl::renameToImpl(const std::string& path) } +void FileImpl::linkToImpl(const std::string& path, int type) const +{ + throw Poco::NotImplementedException("File::linkTo() is not available on this platform"); +} + + void FileImpl::removeImpl() { poco_assert (!_path.empty());