diff --git a/src/tl/tl/tlFileUtils.cc b/src/tl/tl/tlFileUtils.cc index a555ab2f0..163df8aaf 100644 --- a/src/tl/tl/tlFileUtils.cc +++ b/src/tl/tl/tlFileUtils.cc @@ -594,6 +594,14 @@ std::string current_dir () #endif } +bool chdir (const std::string &path) +{ +#if defined(_WIN32) + return _wchdir (tl::to_wstring (path).c_str ()) == 0; +#else + return ::chdir (tl::to_local (path).c_str ()) == 0; +#endif +} static std::pair absolute_path_of_existing (const std::string &s) { diff --git a/src/tl/tl/tlFileUtils.h b/src/tl/tl/tlFileUtils.h index b5530b8a6..4b628006c 100644 --- a/src/tl/tl/tlFileUtils.h +++ b/src/tl/tl/tlFileUtils.h @@ -170,6 +170,11 @@ std::string TL_PUBLIC combine_path (const std::string &p1, const std::string &p2 */ std::string TL_PUBLIC current_dir (); +/** + * @brief Change the current directory and returns true if the change was successful + */ +bool TL_PUBLIC chdir (const std::string &path); + /** * @brief This function splits the path into it's components * On Windows, the first component may be the drive prefix ("C:") or diff --git a/src/tl/tl/tlStream.cc b/src/tl/tl/tlStream.cc index cd449abde..06b45849f 100644 --- a/src/tl/tl/tlStream.cc +++ b/src/tl/tl/tlStream.cc @@ -938,7 +938,7 @@ OutputFileBase::OutputFileBase (const std::string &path, int keep_backups) } } if (! m_backup_path.empty ()) { - if (! tl::rename_file (path, m_backup_path)) { + if (! tl::rename_file (path, tl::filename (m_backup_path))) { tl::warn << tl::sprintf (tl::to_string (tr ("Could not create backup file: unable to rename original file '%s' to backup file")), path, m_backup_path); m_backup_path = std::string (); } diff --git a/src/tl/unit_tests/tlStreamTests.cc b/src/tl/unit_tests/tlStreamTests.cc index 5520ac15d..236f7a72f 100644 --- a/src/tl/unit_tests/tlStreamTests.cc +++ b/src/tl/unit_tests/tlStreamTests.cc @@ -260,6 +260,48 @@ TEST(SafeOutput) } } +TEST(SafeOutput2) +{ + std::string cd = tl::current_dir (); + tl_assert (tl::chdir (tmp_file ("."))); + + try { + + std::string tmp_path = "x"; + tl::rm_dir_recursive (tmp_path); + tl::mkpath (tmp_path); + std::string tp = tl::combine_path (tmp_path, "y"); + + { + tl::OutputStream os (tp); + os << "blabla\n"; + } + + EXPECT_EQ (tl::file_exists (tp + ".~backup"), false); + EXPECT_EQ (tl::file_exists (tp), true); + + { + tl::OutputStream os (tp); + EXPECT_EQ (tl::file_exists (tp + ".~backup"), true); + EXPECT_EQ (tl::file_exists (tp), true); + os << "Hello, world!\n"; + } + + EXPECT_EQ (tl::file_exists (tp + ".~backup"), false); + EXPECT_EQ (tl::file_exists (tp), true); + + { + tl::InputStream is (tp); + EXPECT_EQ (is.read_all (), "Hello, world!\n"); + } + + tl::chdir (cd); + + } catch (...) { + tl::chdir (cd); + throw; + } +} TEST(Backups) {