From 4472553278f9bce1514109197e154d19d01f0f08 Mon Sep 17 00:00:00 2001 From: Thomas Jarosch Date: Thu, 8 Jul 2010 16:21:13 +0200 Subject: [PATCH] Implement mkdir(), rmdir(), getcwd() and chdir() --- src/filefunc.cpp | 98 +++++++++++++++++++++++++++++++++++++++++++++-- src/filefunc.hxx | 7 +++- test/test_filefunc.cpp | 44 +++++++++++++++++++++ 3 files changed, 143 insertions(+), 6 deletions(-) diff --git a/src/filefunc.cpp b/src/filefunc.cpp index bfba003..908b693 100644 --- a/src/filefunc.cpp +++ b/src/filefunc.cpp @@ -303,7 +303,7 @@ std::vector< std::string > get_dir(const std::string& path, bool include_dot_nam /** * @brief removes a file from a filesystem. * @param path path to the file. - * @return @a true iff the unlink was successful. + * @return @a true if the unlink was successful. */ bool unlink( const std::string& path ) { @@ -690,7 +690,7 @@ bool chown(const std::string& path, const I2n::User& user, const I2n::Group& gro /** * Recursive delete of files and directories * @param path File or directory to delete - * @param error Will contain the error if the return value is false + * @param error Will contain the error if the return value is false [optional] * @return true on success, false otherwise */ bool recursive_delete(const std::string &path, std::string *error) @@ -724,11 +724,11 @@ bool recursive_delete(const std::string &path, std::string *error) } closedir(dir); - if (rmdir(path.c_str()) != 0) { + if (!rmdir(path)) { throw runtime_error("can't remove directory " + path); } } else { - if (unlink(path.c_str()) != 0) { + if (!unlink(path)) { throw runtime_error("can't unlink " + path); } } @@ -754,9 +754,10 @@ bool recursive_delete(const std::string &path, std::string *error) /** Create a unique temporary directory from path_template. @param Path template. The last six characters must be XXXXXX. + @param error Will contain the error if the return value is false [optional] @return Name of new directory or empty string on error. */ -std::string mkdtemp(const std::string &path_template) +std::string mkdtemp(const std::string &path_template, std::string *error) { boost::scoped_array buf( new char[path_template.size()+1] ); path_template.copy(buf.get(), path_template.size()); @@ -764,11 +765,98 @@ std::string mkdtemp(const std::string &path_template) char *unique_dir = ::mkdtemp(buf.get()); if (!unique_dir) + { + if (error) + *error = strerror(errno); return ""; + } // Scoped pointer is still valid return std::string(unique_dir); } +/** + Create directory + @param path Path to create + @param error Will contain the error if the return value is false [optional] + @return True on success, false on error +*/ +bool mkdir(const std::string &path, const mode_t &mode, std::string *error) +{ + if ( ::mkdir(path.c_str(), mode) == 0) + return true; + + if (error) + *error = strerror(errno); + return false; +} + +/** + Remove directory + @param path Path to removed + @param error Will contain the error if the return value is false [optional] + @return True on successs, false otherwise +*/ +bool rmdir(const std::string &path, std::string *error) +{ + if ( ::rmdir(path.c_str() ) == 0) + return true; + + if (error) + *error = strerror(errno); + return false; +} + +/// Small helper class for scoped free +class scoped_C_free +{ +public: + scoped_C_free(void *ptr) + : pointer_to_free(ptr) + { + } + + ~scoped_C_free() + { + free (pointer_to_free); + pointer_to_free = NULL; + } + +private: + void *pointer_to_free; +}; + +/** + Get current working directory + @return Current working directory. Empty string on error. +*/ +std::string getcwd() +{ + char *cwd = ::getcwd(NULL, 0); + if (!cwd) + return ""; + + // Make deallocation of cwd exception safe + scoped_C_free holder(cwd); + + string current_dir(cwd); + return current_dir; +} + +/** + Change current working directory + @param path Path to change to + @param error Will contain the error if the return value is false [optional] + @return True on successs, false otherwise +*/ +bool chdir(const std::string &path, std::string *error) +{ + if ( ::chdir(path.c_str() ) == 0) + return true; + + if (error) + *error = strerror(errno); + return false; +} } // eo namespace I2n diff --git a/src/filefunc.hxx b/src/filefunc.hxx index d49fd47..453c1d3 100644 --- a/src/filefunc.hxx +++ b/src/filefunc.hxx @@ -177,7 +177,12 @@ bool chown(const std::string& path, const I2n::User& user, const I2n::Group& gro bool recursive_delete(const std::string &path, std::string *error=NULL); -std::string mkdtemp(const std::string &path_template); +std::string mkdtemp(const std::string &path_template, std::string *error=NULL); +bool mkdir(const std::string &path, const mode_t &mode=0700, std::string *error=NULL); +bool rmdir(const std::string &path, std::string *error=NULL); + +std::string getcwd(); +bool chdir(const std::string &path, std::string *error=NULL); } diff --git a/test/test_filefunc.cpp b/test/test_filefunc.cpp index fb03723..dda31db 100644 --- a/test/test_filefunc.cpp +++ b/test/test_filefunc.cpp @@ -364,4 +364,48 @@ BOOST_AUTO_TEST_CASE(TestMkdtempBrokenTemplate) BOOST_CHECK_EQUAL("", unique_dir); } +BOOST_AUTO_TEST_CASE(DirectoryCreation) +{ + string dirname = "test_directory"; + + I2n::rmdir (dirname); + + BOOST_CHECK_EQUAL(true, I2n::mkdir(dirname)); + BOOST_CHECK_EQUAL(true, Stat(dirname).is_directory()); + // Verify default permissions + BOOST_CHECK_EQUAL(0700, Stat(dirname).mode()); + + BOOST_CHECK_EQUAL(true, I2n::rmdir(dirname)); + + // Second call must fail: Directory already deleted + BOOST_CHECK_EQUAL(false, I2n::rmdir(dirname)); +} + +BOOST_AUTO_TEST_CASE(DirectoryCreatePermission) +{ + string dirname = "test_directory"; + + // TODO: Save and fix umask + + I2n::rmdir (dirname); + BOOST_CHECK_EQUAL(true, I2n::mkdir(dirname, 0770)); + // TODO: Enable check + // BOOST_CHECK_EQUAL(0770, Stat(dirname).mode()); + I2n::rmdir (dirname); + + // TODO: Restore umask +} + +BOOST_AUTO_TEST_CASE(ChangeDirectory) +{ + string current_directory = I2n::getcwd(); + BOOST_REQUIRE(!current_directory.empty()); + + BOOST_CHECK_EQUAL(true, I2n::chdir("/")); + BOOST_CHECK_EQUAL("/", I2n::getcwd()); + + BOOST_CHECK_EQUAL(true, I2n::chdir(current_directory)); + BOOST_REQUIRE_EQUAL(current_directory, I2n::getcwd()); +} + BOOST_AUTO_TEST_SUITE_END() -- 1.7.1