Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement rcutils_mkdir. #166

Merged
merged 4 commits into from
Sep 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
clalancette marked this conversation as resolved.
Show resolved Hide resolved
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));
}
}