-
Notifications
You must be signed in to change notification settings - Fork 107
Add an API for directory iteration #323
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
Merged
Merged
Changes from 5 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
42677e0
Add an API for directory iteration
cottsay 9837765
Add rcutils_list_directory function
cottsay e63db31
Move rcutils_get_file_size to the end to clean up diff
cottsay 1242828
Doh, this is C++ so we can clean this up quite a bit
cottsay 58d66e8
Drop some unnecessary stuff
cottsay e524090
Revert "Add rcutils_list_directory function"
cottsay cbda7e6
Update include/rcutils/filesystem.h
cottsay File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -45,6 +45,7 @@ extern "C" | |
#include "rcutils/error_handling.h" | ||
#include "rcutils/format_string.h" | ||
#include "rcutils/get_env.h" | ||
#include "rcutils/logging_macros.h" | ||
#include "rcutils/repl_str.h" | ||
#include "rcutils/strdup.h" | ||
|
||
|
@@ -54,6 +55,16 @@ extern "C" | |
# define RCUTILS_PATH_DELIMITER "/" | ||
#endif // _WIN32 | ||
|
||
typedef struct rcutils_dir_iter_state_t | ||
{ | ||
#ifdef _WIN32 | ||
HANDLE handle; | ||
WIN32_FIND_DATA data; | ||
#else | ||
DIR * dir; | ||
#endif | ||
} rcutils_dir_iter_state_t; | ||
|
||
bool | ||
rcutils_get_cwd(char * buffer, size_t max_length) | ||
{ | ||
|
@@ -337,6 +348,7 @@ rcutils_calculate_directory_size_with_recursion( | |
{ | ||
dir_list_t * dir_list = NULL; | ||
rcutils_ret_t ret = RCUTILS_RET_OK; | ||
rcutils_dir_iter_t * iter = NULL; | ||
|
||
if (NULL == directory_path) { | ||
RCUTILS_SAFE_FWRITE_TO_STDERR("directory_path is NULL !"); | ||
|
@@ -370,89 +382,202 @@ rcutils_calculate_directory_size_with_recursion( | |
|
||
*size = 0; | ||
|
||
#ifdef _WIN32 | ||
HANDLE handle = INVALID_HANDLE_VALUE; | ||
char * dir_path = NULL; | ||
|
||
do { | ||
dir_path = rcutils_join_path(dir_list->path, "*", allocator); | ||
if (NULL == dir_path) { | ||
RCUTILS_SAFE_FWRITE_TO_STDERR("Failed to duplicate directory path !\n"); | ||
ret = RCUTILS_RET_BAD_ALLOC; | ||
goto fail; | ||
} | ||
|
||
WIN32_FIND_DATA data; | ||
handle = FindFirstFile(dir_path, &data); | ||
if (INVALID_HANDLE_VALUE == handle) { | ||
RCUTILS_SAFE_FWRITE_TO_STDERR_WITH_FORMAT_STRING( | ||
"Can't open directory %s. Error code: %lu\n", dir_list->path, GetLastError()); | ||
iter = rcutils_dir_iter_start(dir_list->path, allocator); | ||
if (NULL == iter) { | ||
ret = RCUTILS_RET_ERROR; | ||
goto fail; | ||
} | ||
|
||
do { | ||
ret = check_and_calculate_size(data.cFileName, size, max_depth, dir_list, allocator); | ||
ret = check_and_calculate_size(iter->entry_name, size, max_depth, dir_list, allocator); | ||
if (RCUTILS_RET_OK != ret) { | ||
goto fail; | ||
} | ||
} while (FindNextFile(handle, &data)); | ||
} while (rcutils_dir_iter_next(iter)); | ||
|
||
FindClose(handle); | ||
cottsay marked this conversation as resolved.
Show resolved
Hide resolved
|
||
allocator.deallocate(dir_path, allocator.state); | ||
rcutils_dir_iter_end(iter); | ||
|
||
remove_first_dir_from_list(&dir_list, allocator); | ||
} while (dir_list); | ||
|
||
return ret; | ||
|
||
fail: | ||
if (NULL != dir_path) { | ||
allocator.deallocate(dir_path, allocator.state); | ||
rcutils_dir_iter_end(iter); | ||
free_dir_list(dir_list, allocator); | ||
return ret; | ||
} | ||
|
||
rcutils_dir_iter_t * | ||
rcutils_dir_iter_start(const char * directory_path, const rcutils_allocator_t allocator) | ||
{ | ||
RCUTILS_CHECK_ARGUMENT_FOR_NULL(directory_path, NULL); | ||
RCUTILS_CHECK_ALLOCATOR_WITH_MSG( | ||
&allocator, "allocator is invalid", return NULL); | ||
|
||
rcutils_dir_iter_t * iter = (rcutils_dir_iter_t *)allocator.zero_allocate( | ||
1, sizeof(rcutils_dir_iter_t), allocator.state); | ||
if (NULL == iter) { | ||
return NULL; | ||
} | ||
iter->allocator = allocator; | ||
|
||
if (INVALID_HANDLE_VALUE != handle) { | ||
FindClose(handle); | ||
rcutils_dir_iter_state_t * state = (rcutils_dir_iter_state_t *)allocator.zero_allocate( | ||
1, sizeof(rcutils_dir_iter_state_t), allocator.state); | ||
if (NULL == state) { | ||
RCUTILS_SET_ERROR_MSG( | ||
"Failed to allocate memory.\n"); | ||
goto rcutils_dir_iter_start_fail; | ||
} | ||
iter->state = (void *)state; | ||
|
||
#ifdef _WIN32 | ||
char * search_path = rcutils_join_path(directory_path, "*", allocator); | ||
if (NULL == search_path) { | ||
goto rcutils_dir_iter_start_fail; | ||
} | ||
state->handle = FindFirstFile(search_path, &state->data); | ||
allocator.deallocate(search_path, allocator.state); | ||
if (INVALID_HANDLE_VALUE == state->handle) { | ||
DWORD error = GetLastError(); | ||
if (ERROR_FILE_NOT_FOUND != error || !rcutils_is_directory(directory_path)) { | ||
RCUTILS_SET_ERROR_MSG_WITH_FORMAT_STRING( | ||
"Can't open directory %s. Error code: %d\n", directory_path, error); | ||
goto rcutils_dir_iter_start_fail; | ||
} | ||
} else { | ||
iter->entry_name = state->data.cFileName; | ||
} | ||
free_dir_list(dir_list, allocator); | ||
return ret; | ||
#else | ||
DIR * dir = NULL; | ||
state->dir = opendir(directory_path); | ||
if (NULL == state->dir) { | ||
RCUTILS_SET_ERROR_MSG_WITH_FORMAT_STRING( | ||
"Can't open directory %s. Error code: %d\n", directory_path, errno); | ||
goto rcutils_dir_iter_start_fail; | ||
} | ||
|
||
errno = 0; | ||
struct dirent * entry = readdir(state->dir); | ||
if (NULL != entry) { | ||
iter->entry_name = entry->d_name; | ||
} else if (0 != errno) { | ||
RCUTILS_SET_ERROR_MSG_WITH_FORMAT_STRING( | ||
"Can't iterate directory %s. Error code: %d\n", directory_path, errno); | ||
goto rcutils_dir_iter_start_fail; | ||
} | ||
#endif | ||
|
||
struct dirent * entry; | ||
do { | ||
dir = opendir(dir_list->path); | ||
if (NULL == dir) { | ||
RCUTILS_SAFE_FWRITE_TO_STDERR_WITH_FORMAT_STRING( | ||
"Can't open directory %s. Error code: %d\n", dir_list->path, errno); | ||
ret = RCUTILS_RET_ERROR; | ||
goto fail; | ||
return iter; | ||
|
||
rcutils_dir_iter_start_fail: | ||
rcutils_dir_iter_end(iter); | ||
return NULL; | ||
} | ||
|
||
bool | ||
rcutils_dir_iter_next(rcutils_dir_iter_t * iter) | ||
{ | ||
RCUTILS_CHECK_ARGUMENT_FOR_NULL(iter, false); | ||
rcutils_dir_iter_state_t * state = (rcutils_dir_iter_state_t *)iter->state; | ||
RCUTILS_CHECK_FOR_NULL_WITH_MSG(state, "iter is invalid", false); | ||
|
||
#ifdef _WIN32 | ||
if (FindNextFile(state->handle, &state->data)) { | ||
iter->entry_name = state->data.cFileName; | ||
return true; | ||
} | ||
FindClose(state->handle); | ||
#else | ||
struct dirent * entry = readdir(state->dir); | ||
if (NULL != entry) { | ||
iter->entry_name = entry->d_name; | ||
return true; | ||
} | ||
#endif | ||
|
||
iter->entry_name = NULL; | ||
return false; | ||
} | ||
|
||
void | ||
rcutils_dir_iter_end(rcutils_dir_iter_t * iter) | ||
{ | ||
if (NULL == iter) { | ||
return; | ||
} | ||
|
||
rcutils_allocator_t allocator = iter->allocator; | ||
rcutils_dir_iter_state_t * state = (rcutils_dir_iter_state_t *)iter->state; | ||
if (NULL != state) { | ||
#ifdef _WIN32 | ||
FindClose(state->handle); | ||
#else | ||
if (NULL != state->dir) { | ||
closedir(state->dir); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TIL that |
||
#endif | ||
|
||
allocator.deallocate(state, allocator.state); | ||
} | ||
|
||
allocator.deallocate(iter, allocator.state); | ||
} | ||
|
||
rcutils_ret_t | ||
rcutils_list_directory( | ||
const char * directory_path, | ||
rcutils_allocator_t allocator, | ||
rcutils_string_array_t * string_array) | ||
{ | ||
RCUTILS_CHECK_FOR_NULL_WITH_MSG( | ||
directory_path, "directory_path is null", return RCUTILS_RET_INVALID_ARGUMENT); | ||
RCUTILS_CHECK_FOR_NULL_WITH_MSG( | ||
string_array, "string_array is null", return RCUTILS_RET_INVALID_ARGUMENT); | ||
|
||
// Scan in specified path | ||
// If found directory, add to dir_list | ||
// If found file, calculate file size | ||
while (NULL != (entry = readdir(dir))) { | ||
ret = check_and_calculate_size(entry->d_name, size, max_depth, dir_list, allocator); | ||
// Start with 8 entries | ||
rcutils_ret_t ret = rcutils_string_array_init(string_array, 8, &allocator); | ||
if (RCUTILS_RET_OK != ret) { | ||
return ret; | ||
} | ||
|
||
size_t count = 0; | ||
|
||
rcutils_dir_iter_t * iter = rcutils_dir_iter_start(directory_path, allocator); | ||
if (NULL == iter) { | ||
return RCUTILS_RET_ERROR; | ||
} | ||
|
||
do { | ||
if (count >= string_array->size) { | ||
ret = rcutils_string_array_resize(string_array, count * 2); | ||
if (RCUTILS_RET_OK != ret) { | ||
goto fail; | ||
} | ||
} | ||
|
||
closedir(dir); | ||
|
||
remove_first_dir_from_list(&dir_list, allocator); | ||
} while (dir_list); | ||
string_array->data[count] = rcutils_strdup(iter->entry_name, allocator); | ||
if (NULL == string_array->data[count]) { | ||
goto fail; | ||
} | ||
} while (++count, rcutils_dir_iter_next(iter)); | ||
|
||
return ret; | ||
// Shrink the array back down | ||
if (count != string_array->size) { | ||
ret = rcutils_string_array_resize(string_array, count); | ||
if (RCUTILS_RET_OK == ret) { | ||
return RCUTILS_RET_OK; | ||
} | ||
} | ||
|
||
fail: | ||
if (NULL != dir) { | ||
closedir(dir); | ||
rcutils_dir_iter_end(iter); | ||
|
||
if (RCUTILS_RET_OK != rcutils_string_array_fini(string_array)) { | ||
RCUTILS_LOG_ERROR( | ||
"failed to clean up on error (leaking memory): '%s'", rcutils_get_error_string().str); | ||
} | ||
free_dir_list(dir_list, allocator); | ||
return ret; | ||
#endif | ||
} | ||
|
||
size_t | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.