diff --git a/Foundation/include/Poco/File.h b/Foundation/include/Poco/File.h index afecf3212..d62be6fcd 100644 --- a/Foundation/include/Poco/File.h +++ b/Foundation/include/Poco/File.h @@ -70,6 +70,12 @@ public: LINK_SYMBOLIC = 1 /// symbolic link }; + enum Options + /// Options for File Copy/Movement + { + OPT_FAIL_ON_OVERWRITE = OPT_FAIL_ON_OVERWRITE_IMPL + }; + File(); /// Creates the file. @@ -183,18 +189,24 @@ public: /// /// Does nothing on Windows. - void copyTo(const std::string& path) const; + void copyTo(const std::string& path, int options = 0) const; /// Copies the file (or directory) to the given path. /// The target path can be a directory. /// /// A directory is copied recursively. + /// If options is set to OPT_FAIL_ON_OVERWRITE the Method throws an FileExists Exception + /// if the File already exists. - void moveTo(const std::string& path); + void moveTo(const std::string& path, int options = 0); /// Copies the file (or directory) to the given path and /// removes the original file. The target path can be a directory. + /// If options is set to OPT_FAIL_ON_OVERWRITE the Method throws an FileExists Exception + /// if the File already exists. - void renameTo(const std::string& path); + void renameTo(const std::string& path, int options = 0); /// Renames the file to the new name. + /// If options is set to OPT_FAIL_ON_OVERWRITE the Method throws an FileExists Exception + /// if the File already exists. void linkTo(const std::string& path, LinkType type = LINK_SYMBOLIC) const; /// Creates a link (symbolic or hard, depending on type argument) @@ -253,7 +265,7 @@ public: /// exception for the last file-related error. protected: - void copyDirectory(const std::string& path) const; + void copyDirectory(const std::string& path, int options = 0) const; /// Copies a directory. Used internally by copyTo(). }; diff --git a/Foundation/include/Poco/File_UNIX.h b/Foundation/include/Poco/File_UNIX.h index 34a15c573..ced4a9d52 100644 --- a/Foundation/include/Poco/File_UNIX.h +++ b/Foundation/include/Poco/File_UNIX.h @@ -27,6 +27,11 @@ namespace Poco { class FileImpl { protected: + + enum Options { + OPT_FAIL_ON_OVERWRITE_IMPL = 0x01 + }; + typedef UInt64 FileSizeImpl; FileImpl(); @@ -51,8 +56,8 @@ protected: void setSizeImpl(FileSizeImpl size); void setWriteableImpl(bool flag = true); void setExecutableImpl(bool flag = true); - void copyToImpl(const std::string& path) const; - void renameToImpl(const std::string& path); + void copyToImpl(const std::string& path, int options = 0) const; + void renameToImpl(const std::string& path, int options = 0); void linkToImpl(const std::string& path, int type) const; void removeImpl(); bool createFileImpl(); diff --git a/Foundation/include/Poco/File_VX.h b/Foundation/include/Poco/File_VX.h index 3d66f9664..8b2f90973 100644 --- a/Foundation/include/Poco/File_VX.h +++ b/Foundation/include/Poco/File_VX.h @@ -27,6 +27,11 @@ namespace Poco { class FileImpl { protected: + + enum Options { + OPT_FAIL_ON_OVERWRITE_IMPL = 0x01 + }; + typedef UInt64 FileSizeImpl; FileImpl(); @@ -51,8 +56,8 @@ protected: void setSizeImpl(FileSizeImpl size); void setWriteableImpl(bool flag = true); void setExecutableImpl(bool flag = true); - void copyToImpl(const std::string& path) const; - void renameToImpl(const std::string& path); + void copyToImpl(const std::string& path, int options = 0) const; + void renameToImpl(const std::string& path, int options = 0); void linkToImpl(const std::string& path, int type) const; void removeImpl(); bool createFileImpl(); diff --git a/Foundation/include/Poco/File_WIN32.h b/Foundation/include/Poco/File_WIN32.h index 2d8b88807..b5e9459b2 100644 --- a/Foundation/include/Poco/File_WIN32.h +++ b/Foundation/include/Poco/File_WIN32.h @@ -28,6 +28,11 @@ namespace Poco { class Foundation_API FileImpl { protected: + + enum Options { + OPT_FAIL_ON_OVERWRITE_IMPL = 0x01 + }; + typedef UInt64 FileSizeImpl; FileImpl(); @@ -52,8 +57,8 @@ protected: void setSizeImpl(FileSizeImpl size); void setWriteableImpl(bool flag = true); void setExecutableImpl(bool flag = true); - void copyToImpl(const std::string& path) const; - void renameToImpl(const std::string& path); + void copyToImpl(const std::string& path, int options = 0) const; + void renameToImpl(const std::string& path, int options = 0); void linkToImpl(const std::string& path, int type) const; void removeImpl(); bool createFileImpl(); diff --git a/Foundation/include/Poco/File_WIN32U.h b/Foundation/include/Poco/File_WIN32U.h index 835da87a1..d77e4db8f 100644 --- a/Foundation/include/Poco/File_WIN32U.h +++ b/Foundation/include/Poco/File_WIN32U.h @@ -28,6 +28,11 @@ namespace Poco { class Foundation_API FileImpl { protected: + + enum Options { + OPT_FAIL_ON_OVERWRITE_IMPL = 0x01 + }; + typedef UInt64 FileSizeImpl; FileImpl(); @@ -52,8 +57,8 @@ protected: void setSizeImpl(FileSizeImpl size); void setWriteableImpl(bool flag = true); void setExecutableImpl(bool flag = true); - void copyToImpl(const std::string& path) const; - void renameToImpl(const std::string& path); + void copyToImpl(const std::string& path, int options = 0) const; + void renameToImpl(const std::string& path, int options = 0); void linkToImpl(const std::string& path, int type) const; void removeImpl(); bool createFileImpl(); diff --git a/Foundation/include/Poco/File_WINCE.h b/Foundation/include/Poco/File_WINCE.h index c1ba4f350..336ff6ef3 100644 --- a/Foundation/include/Poco/File_WINCE.h +++ b/Foundation/include/Poco/File_WINCE.h @@ -28,6 +28,11 @@ namespace Poco { class Foundation_API FileImpl { protected: + + enum Options { + OPT_FAIL_ON_OVERWRITE_IMPL = 0x01 + }; + typedef UInt64 FileSizeImpl; FileImpl(); @@ -52,8 +57,8 @@ protected: void setSizeImpl(FileSizeImpl size); void setWriteableImpl(bool flag = true); void setExecutableImpl(bool flag = true); - void copyToImpl(const std::string& path) const; - void renameToImpl(const std::string& path); + void copyToImpl(const std::string& path, int options = 0) const; + void renameToImpl(const std::string& path, int options = 0); void linkToImpl(const std::string& path, int type) const; void removeImpl(); bool createFileImpl(); diff --git a/Foundation/src/File.cpp b/Foundation/src/File.cpp index ec198d139..07571c5a5 100644 --- a/Foundation/src/File.cpp +++ b/Foundation/src/File.cpp @@ -208,7 +208,7 @@ File& File::setExecutable(bool flag) } -void File::copyTo(const std::string& path) const +void File::copyTo(const std::string& path, int options) const { Path src(getPathImpl()); Path dest(path); @@ -219,13 +219,13 @@ void File::copyTo(const std::string& path) const dest.setFileName(src.getFileName()); } if (isDirectory()) - copyDirectory(dest.toString()); + copyDirectory(dest.toString(), options); else - copyToImpl(dest.toString()); + copyToImpl(dest.toString(), options); } -void File::copyDirectory(const std::string& path) const +void File::copyDirectory(const std::string& path, int options) const { File target(path); target.createDirectories(); @@ -236,22 +236,22 @@ void File::copyDirectory(const std::string& path) const DirectoryIterator end; for (; it != end; ++it) { - it->copyTo(path); + it->copyTo(path, options); } } -void File::moveTo(const std::string& path) +void File::moveTo(const std::string& path, int options) { - copyTo(path); + copyTo(path, options); remove(true); setPathImpl(path); } -void File::renameTo(const std::string& path) +void File::renameTo(const std::string& path, int options) { - renameToImpl(path); + renameToImpl(path, options); setPathImpl(path); } diff --git a/Foundation/src/File_UNIX.cpp b/Foundation/src/File_UNIX.cpp index f345eb88b..4cccb623e 100644 --- a/Foundation/src/File_UNIX.cpp +++ b/Foundation/src/File_UNIX.cpp @@ -326,7 +326,7 @@ void FileImpl::setExecutableImpl(bool flag) } -void FileImpl::copyToImpl(const std::string& path) const +void FileImpl::copyToImpl(const std::string& path, int options) const { poco_assert (!_path.empty()); @@ -340,8 +340,12 @@ void FileImpl::copyToImpl(const std::string& path) const handleLastErrorImpl(_path); } const long blockSize = st.st_blksize; - - int dd = open(path.c_str(), O_CREAT | O_TRUNC | O_WRONLY, st.st_mode); + int dd; + if (options & OPT_FAIL_ON_OVERWRITE_IMPL) { + dd = open(path.c_str(), O_CREAT | O_TRUNC | O_EXCL | O_WRONLY, st.st_mode); + } else { + dd = open(path.c_str(), O_CREAT | O_TRUNC | O_WRONLY, st.st_mode); + } if (dd == -1) { close(sd); @@ -376,10 +380,15 @@ void FileImpl::copyToImpl(const std::string& path) const } -void FileImpl::renameToImpl(const std::string& path) +void FileImpl::renameToImpl(const std::string& path, int options) { poco_assert (!_path.empty()); + struct stat st; + + if (stat(path.c_str(), &st) == 0 && (options & OPT_FAIL_ON_OVERWRITE_IMPL)) + throw FileExistsException(path, EEXIST); + if (rename(_path.c_str(), path.c_str()) != 0) handleLastErrorImpl(_path); } diff --git a/Foundation/src/File_VX.cpp b/Foundation/src/File_VX.cpp index 9f59b478a..97f2461e6 100644 --- a/Foundation/src/File_VX.cpp +++ b/Foundation/src/File_VX.cpp @@ -232,7 +232,7 @@ void FileImpl::setExecutableImpl(bool flag) } -void FileImpl::copyToImpl(const std::string& path) const +void FileImpl::copyToImpl(const std::string& path, int options) const { poco_assert (!_path.empty()); @@ -247,7 +247,13 @@ void FileImpl::copyToImpl(const std::string& path) const } const long blockSize = st.st_blksize; - int dd = open(path.c_str(), O_CREAT | O_TRUNC | O_WRONLY, st.st_mode & S_IRWXU); + int dd; + if (options & OPT_FAIL_ON_OVERWRITE_IMPL) { + dd = open(path.c_str(), O_CREAT | O_TRUNC | O_EXCL | O_WRONLY, st.st_mode & S_IRWXU); + } else { + dd = open(path.c_str(), O_CREAT | O_TRUNC | O_WRONLY, st.st_mode & S_IRWXU); + } + if (dd == -1) { close(sd); @@ -276,10 +282,15 @@ void FileImpl::copyToImpl(const std::string& path) const } -void FileImpl::renameToImpl(const std::string& path) +void FileImpl::renameToImpl(const std::string& path, int options) { poco_assert (!_path.empty()); + struct stat st; + + if (stat(path.c_str(), &st) == 0 && (options &OPT_FAIL_ON_OVERWRITE_IMPL)) + throw FileExistsException(path, EEXIST); + if (rename(_path.c_str(), path.c_str()) != 0) handleLastErrorImpl(_path); } diff --git a/Foundation/src/File_WIN32.cpp b/Foundation/src/File_WIN32.cpp index 2c569e369..32b56ccf0 100644 --- a/Foundation/src/File_WIN32.cpp +++ b/Foundation/src/File_WIN32.cpp @@ -288,21 +288,27 @@ void FileImpl::setExecutableImpl(bool flag) } -void FileImpl::copyToImpl(const std::string& path) const +void FileImpl::copyToImpl(const std::string& path, int options) const { poco_assert (!_path.empty()); - if (CopyFileA(_path.c_str(), path.c_str(), FALSE) == 0) + if (CopyFileA(_path.c_str(), path.c_str(), (options & OPT_FAIL_ON_OVERWRITE_IMPL) != 0) == 0) handleLastErrorImpl(_path); } -void FileImpl::renameToImpl(const std::string& path) +void FileImpl::renameToImpl(const std::string& path, int options) { poco_assert (!_path.empty()); - if (MoveFileExA(_path.c_str(), path.c_str(), MOVEFILE_REPLACE_EXISTING) == 0) - handleLastErrorImpl(_path); + if (options & OPT_FAIL_ON_OVERWRITE_IMPL) { + if (MoveFileExA(_path.c_str(), path.c_str(), NULL) == 0) + handleLastErrorImpl(_path); + } else { + if (MoveFileExA(_path.c_str(), path.c_str(), MOVEFILE_REPLACE_EXISTING) == 0) + handleLastErrorImpl(_path); + } + } diff --git a/Foundation/src/File_WIN32U.cpp b/Foundation/src/File_WIN32U.cpp index f8609f17c..75b5da85c 100644 --- a/Foundation/src/File_WIN32U.cpp +++ b/Foundation/src/File_WIN32U.cpp @@ -291,25 +291,30 @@ void FileImpl::setExecutableImpl(bool flag) } -void FileImpl::copyToImpl(const std::string& path) const +void FileImpl::copyToImpl(const std::string& path, int options) const { poco_assert (!_path.empty()); std::wstring upath; convertPath(path, upath); - if (CopyFileW(_upath.c_str(), upath.c_str(), FALSE) == 0) + if (CopyFileW(_upath.c_str(), upath.c_str(), (options & OPT_FAIL_ON_OVERWRITE_IMPL) != 0) == 0) handleLastErrorImpl(_path); } -void FileImpl::renameToImpl(const std::string& path) +void FileImpl::renameToImpl(const std::string& path, int options) { poco_assert (!_path.empty()); std::wstring upath; convertPath(path, upath); - if (MoveFileExW(_upath.c_str(), upath.c_str(), MOVEFILE_REPLACE_EXISTING) == 0) - handleLastErrorImpl(_path); + if (options & OPT_FAIL_ON_OVERWRITE_IMPL) { + if (MoveFileExW(_upath.c_str(), upath.c_str(), NULL) == 0) + handleLastErrorImpl(_path); + } else { + if (MoveFileExW(_upath.c_str(), upath.c_str(), MOVEFILE_REPLACE_EXISTING) == 0) + handleLastErrorImpl(_path); + } } diff --git a/Foundation/src/File_WINCE.cpp b/Foundation/src/File_WINCE.cpp index ea726c4bc..9ce78a41f 100644 --- a/Foundation/src/File_WINCE.cpp +++ b/Foundation/src/File_WINCE.cpp @@ -277,25 +277,31 @@ void FileImpl::setExecutableImpl(bool flag) } -void FileImpl::copyToImpl(const std::string& path) const +void FileImpl::copyToImpl(const std::string& path, int options) const { poco_assert (!_path.empty()); std::wstring upath; convertPath(path, upath); - if (CopyFileW(_upath.c_str(), upath.c_str(), FALSE) == 0) + if (CopyFileW(_upath.c_str(), upath.c_str(), (options & OPT_FAIL_ON_OVERWRITE_IMPL) != 0) == 0) handleLastErrorImpl(_path); } -void FileImpl::renameToImpl(const std::string& path) +void FileImpl::renameToImpl(const std::string& path, int options) { poco_assert (!_path.empty()); std::wstring upath; convertPath(path, upath); - if (MoveFileW(_upath.c_str(), upath.c_str()) == 0) - handleLastErrorImpl(_path); + if (options & OPT_FAIL_ON_OVERWRITE_IMPL) { + if (MoveFileW(_upath.c_str(), upath.c_str()) == 0) + handleLastErrorImpl(_path); + } else { + if (MoveFileW(_upath.c_str(), upath.c_str(), MOVEFILE_REPLACE_EXISTING) == 0) + handleLastErrorImpl(_path); + } + } diff --git a/Foundation/testsuite/src/FileTest.cpp b/Foundation/testsuite/src/FileTest.cpp index 3e1d4a47d..4ec038673 100644 --- a/Foundation/testsuite/src/FileTest.cpp +++ b/Foundation/testsuite/src/FileTest.cpp @@ -380,6 +380,23 @@ void FileTest::testCopy() f1.setWriteable().remove(); } +void FileTest::testCopyFailIfDestinationFileExists() +{ + std::ofstream ostr("testfile.dat"); + ostr << "Hello, world!" << std::endl; + ostr.close(); + + File f1("testfile.dat"); + TemporaryFile f2; + f2.createFile(); + try { + f1.setReadOnly().copyTo(f2.path(), File::OPT_FAIL_ON_OVERWRITE); + failmsg("file exist - must throw exception"); + } catch (Exception&) { + } + f1.setWriteable().remove(); +} + void FileTest::testMove() { @@ -397,6 +414,21 @@ void FileTest::testMove() assertTrue (f1 == f2); } +void FileTest::testMoveFailIfDestinationFileExists() { + std::ofstream ostr("testfile.dat"); + ostr << "Hello, world!" << std::endl; + ostr.close(); + + File f1("testfile.dat"); + TemporaryFile f2; + f2.createFile(); + try { + f1.moveTo(f2.path(), File::OPT_FAIL_ON_OVERWRITE); + failmsg("file exist - must throw exception"); + } catch (Exception&) { + } + f1.setWriteable().remove(); +} void FileTest::testCopyDirectory() { @@ -467,6 +499,44 @@ void FileTest::testCopyDirectory() fd3.remove(true); } +void FileTest::testCopyDirectoryFailIfExists() +{ + Path pd1("testdir"); + File fd1(pd1); + try { + fd1.remove(true); + } catch (...) { + } + fd1.createDirectories(); + Path pf1(pd1, "testfile1.dat"); + std::ofstream ostr1(pf1.toString().c_str()); + ostr1 << "Hello, world!" << std::endl; + ostr1.close(); + Path pf2(pd1, "testfile2.dat"); + std::ofstream ostr2(pf2.toString().c_str()); + ostr2 << "Hello, world!" << std::endl; + ostr2.close(); + + Path pd2("destination"); + File fd2(pd2); + try { + fd2.remove(true); + } catch (...) { + } + fd2.createDirectories(); + Path pd3(pd2, "testdir"); + File fd3(pd3); + fd3.createDirectories(); + + try { + fd1.copyTo("testdir", File::OPT_FAIL_ON_OVERWRITE); + failmsg("Destination Directory exists - must throw exception"); + } catch (Exception&) { + } + + fd1.remove(true); + fd2.remove(true); +} void FileTest::testRename() { @@ -485,6 +555,32 @@ void FileTest::testRename() f2.remove(); } +void FileTest::testRenameFailIfExists() { + std::ofstream ostr("testfile.dat"); + ostr << "Hello, world!" << std::endl; + ostr.close(); + + File f1("testfile.dat"); + File f2("testfile2.dat"); + f2.createFile(); + + try { + f1.renameTo(f2.path(), File::OPT_FAIL_ON_OVERWRITE); + failmsg("file exists - must throw exception"); + } catch (Exception&) { + } + + f1.renameTo(f2.path()); + + assertTrue(f2.exists()); + assertTrue(f1.exists()); + assertTrue(f1 == f2); + + f2.remove(); +} + + + void FileTest::testLongPath() { @@ -549,9 +645,13 @@ CppUnit::Test* FileTest::suite() CppUnit_addTest(pSuite, FileTest, testSize); CppUnit_addTest(pSuite, FileTest, testDirectory); CppUnit_addTest(pSuite, FileTest, testCopy); + CppUnit_addTest(pSuite, FileTest, testCopyFailIfDestinationFileExists); CppUnit_addTest(pSuite, FileTest, testMove); + CppUnit_addTest(pSuite, FileTest, testMoveFailIfDestinationFileExists); CppUnit_addTest(pSuite, FileTest, testCopyDirectory); + CppUnit_addTest(pSuite, FileTest, testCopyDirectoryFailIfExists); CppUnit_addTest(pSuite, FileTest, testRename); + CppUnit_addTest(pSuite, FileTest, testRenameFailIfExists); CppUnit_addTest(pSuite, FileTest, testRootDir); CppUnit_addTest(pSuite, FileTest, testLongPath); diff --git a/Foundation/testsuite/src/FileTest.h b/Foundation/testsuite/src/FileTest.h index 64c229df9..04a859723 100644 --- a/Foundation/testsuite/src/FileTest.h +++ b/Foundation/testsuite/src/FileTest.h @@ -33,9 +33,13 @@ public: void testSize(); void testDirectory(); void testCopy(); + void testCopyFailIfDestinationFileExists(); void testMove(); + void testMoveFailIfDestinationFileExists(); void testCopyDirectory(); + void testCopyDirectoryFailIfExists(); void testRename(); + void testRenameFailIfExists(); void testRootDir(); void testLongPath();