Implement mkdir(), rmdir(), getcwd() and chdir()
authorThomas Jarosch <thomas.jarosch@intra2net.com>
Thu, 8 Jul 2010 14:21:13 +0000 (16:21 +0200)
committerThomas Jarosch <thomas.jarosch@intra2net.com>
Thu, 22 Sep 2011 14:25:30 +0000 (16:25 +0200)
src/filefunc.cpp
src/filefunc.hxx
test/test_filefunc.cpp

index bfba003..908b693 100644 (file)
@@ -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<char> 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
index d49fd47..453c1d3 100644 (file)
@@ -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);
 
 }
 
index fb03723..dda31db 100644 (file)
@@ -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()