Skip to content

Commit

Permalink
Implement rcutils_mkdir. (#166)
Browse files Browse the repository at this point in the history
* Implement rcutils_mkdir.

Needed for the spdlog logging backend.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>

* Add in tests for rcutils_mkdir.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>

* Fix small nit for documentation.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>

* Add in a warning that the thread isn't thread-safe.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
  • Loading branch information
clalancette authored Sep 30, 2019
1 parent 54ecb72 commit 8983a69
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 0 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ if(BUILD_TESTING)
if(TARGET test_filesystem)
ament_target_dependencies(test_filesystem "osrf_testing_tools_cpp")
target_link_libraries(test_filesystem ${PROJECT_NAME})
target_compile_definitions(test_filesystem PRIVATE BUILD_DIR="${CMAKE_CURRENT_BINARY_DIR}")
endif()

rcutils_custom_add_gtest(test_strdup
Expand Down
23 changes: 23 additions & 0 deletions include/rcutils/filesystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,29 @@ rcutils_to_native_path(
const char * path,
rcutils_allocator_t allocator);

/// Create the specified directory.
/**
* This function creates an absolutely-specified directory.
* If any of the intermediate directories do not exist, this function will
* return False.
* If the abs_path already exists, and is a directory, this function will
* return True.
*
* This function is not thread-safe due to mkdir races as described in the
* openat(2) documentation.
*
* \param[in] abs_path
* \param[in] allocator
* \return bool True if making the directory was successful, False otherwise
* False if path is NULL
* False if path is empty
* False if path is not absolute
* False if any intermediate directories don't exist
*/
RCUTILS_PUBLIC
bool
rcutils_mkdir(const char * abs_path);

#ifdef __cplusplus
}
#endif
Expand Down
33 changes: 33 additions & 0 deletions src/filesystem.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ extern "C"
#endif
#include "rcutils/filesystem.h"

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Expand Down Expand Up @@ -177,6 +178,38 @@ rcutils_to_native_path(
return rcutils_repl_str(path, "/", RCUTILS_PATH_DELIMITER, &allocator);
}

bool
rcutils_mkdir(const char * abs_path)
{
if (NULL == abs_path) {
return false;
}

if (abs_path[0] == '\0') {
return false;
}

bool success = false;
#ifdef _WIN32
// TODO(clalancette): Check to ensure that the path is absolute on Windows.
// In theory we can use PathRelativeA to do this, but I was unable to make
// it work. Needs further investigation.

int ret = _mkdir(abs_path);
#else
if (abs_path[0] != '/') {
return false;
}

int ret = mkdir(abs_path, 0775);
#endif
if (ret == 0 || (errno == EEXIST && rcutils_is_directory(abs_path))) {
success = true;
}

return success;
}

#ifdef __cplusplus
}
#endif
44 changes: 44 additions & 0 deletions test/test_filesystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,3 +236,47 @@ TEST_F(TestFilesystemFixture, is_readable_and_writable) {
EXPECT_FALSE(rcutils_is_readable_and_writable(path));
}
}

TEST_F(TestFilesystemFixture, mkdir) {
{
// Make a new directory
char * path =
rcutils_join_path(BUILD_DIR, "mkdir_test_dir", g_allocator);
ASSERT_FALSE(nullptr == path);
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
g_allocator.deallocate(path, g_allocator.state);
});
ASSERT_TRUE(rcutils_mkdir(path));
}
{
// Purposely do it again, to make sure mkdir handles the case where the
// directory already exists
char * path =
rcutils_join_path(BUILD_DIR, "mkdir_test_dir", g_allocator);
ASSERT_FALSE(nullptr == path);
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
g_allocator.deallocate(path, g_allocator.state);
});
ASSERT_TRUE(rcutils_mkdir(path));
}
{
ASSERT_FALSE(rcutils_mkdir(nullptr));
}
{
ASSERT_FALSE(rcutils_mkdir("foo/bar"));
}
{
// Make sure it throws an error when the intermediate path doesn't exist
char * path =
rcutils_join_path(BUILD_DIR, "mkdir_test_dir2", g_allocator);
ASSERT_FALSE(nullptr == path);
char * path2 =
rcutils_join_path(path, "mkdir_test_dir3", g_allocator);
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
g_allocator.deallocate(path2, g_allocator.state);
g_allocator.deallocate(path, g_allocator.state);
});
ASSERT_FALSE(nullptr == path2);
ASSERT_FALSE(rcutils_mkdir(path2));
}
}

0 comments on commit 8983a69

Please sign in to comment.