in source/windows/file.c [213:375]
int aws_directory_traverse(
struct aws_allocator *allocator,
const struct aws_string *path,
bool recursive,
aws_on_directory_entry *on_entry,
void *user_data) {
struct aws_wstring *w_path_wchar = aws_string_convert_to_wstring(allocator, path);
struct aws_wstring *long_path_wchar = s_to_long_path(allocator, w_path_wchar);
aws_wstring_destroy(w_path_wchar);
/* windows doesn't fail in FindFirstFile if it's not a directory. Do the check here. We don't call the perfectly
good function for this check because the string is already converted to utf-16 and it's trivial to reuse it. */
DWORD attributes = GetFileAttributesW(aws_wstring_c_str(long_path_wchar));
if (!(attributes & FILE_ATTRIBUTE_DIRECTORY)) {
aws_wstring_destroy(long_path_wchar);
return aws_raise_error(AWS_ERROR_FILE_INVALID_PATH);
}
WIN32_FIND_DATAW ffd;
HANDLE find_handle = FindFirstFileW(aws_wstring_c_str(long_path_wchar), &ffd);
if (find_handle == INVALID_HANDLE_VALUE) {
aws_wstring_destroy(long_path_wchar);
int error = GetLastError();
if (error == ERROR_FILE_NOT_FOUND) {
return aws_raise_error(AWS_ERROR_FILE_INVALID_PATH);
}
return aws_raise_error(AWS_ERROR_UNKNOWN);
}
FindClose(find_handle);
/* create search path string */
struct aws_byte_cursor path_wchar_cur =
aws_byte_cursor_from_array(aws_wstring_c_str(long_path_wchar), aws_wstring_size_bytes(long_path_wchar));
struct aws_byte_buf search_wchar_buf;
aws_byte_buf_init_copy_from_cursor(&search_wchar_buf, allocator, path_wchar_cur);
wchar_t search_wchar_pattern[] = L"\\*";
struct aws_byte_cursor search_char_wchar =
aws_byte_cursor_from_array((uint8_t *)search_wchar_pattern, sizeof(search_wchar_pattern));
aws_byte_buf_append_dynamic(&search_wchar_buf, &search_char_wchar);
struct aws_byte_cursor search_wchar_cur = aws_byte_cursor_from_buf(&search_wchar_buf);
/* it's already converted to wide string */
struct aws_wstring *search_wchar_string = aws_wstring_new_from_cursor(allocator, &search_wchar_cur);
find_handle = FindFirstFileW(aws_wstring_c_str(search_wchar_string), &ffd);
aws_wstring_destroy(search_wchar_string);
aws_byte_buf_clean_up(&search_wchar_buf);
int ret_val = AWS_OP_SUCCESS;
/* iterate each entry in the directory. Do a bunch of utf-16 conversions. Figure out the paths etc....
invoke the visitor, and continue recursing if the flag was set. */
do {
struct aws_string *name_component_multi_char_str =
aws_string_convert_from_wchar_c_str(allocator, ffd.cFileName);
struct aws_byte_cursor name_component_multi_char = aws_byte_cursor_from_string(name_component_multi_char_str);
/* disgard . and .. */
char *ascend_mark = "..";
char *cd_mark = ".";
struct aws_byte_cursor ascend_mark_cur = aws_byte_cursor_from_c_str(ascend_mark);
struct aws_byte_cursor cd_mark_cur = aws_byte_cursor_from_c_str(cd_mark);
if (aws_byte_cursor_eq(&name_component_multi_char, &ascend_mark_cur) ||
aws_byte_cursor_eq(&name_component_multi_char, &cd_mark_cur)) {
aws_string_destroy(name_component_multi_char_str);
continue;
}
/* get the relative path as utf-16, so we can talk to windows. */
struct aws_byte_buf relative_path_wchar;
aws_byte_buf_init_copy_from_cursor(&relative_path_wchar, allocator, path_wchar_cur);
wchar_t unicode_delim[] = L"\\";
struct aws_byte_cursor delimiter_cur =
aws_byte_cursor_from_array((uint8_t *)unicode_delim, sizeof(unicode_delim) - 2);
aws_byte_buf_append_dynamic(&relative_path_wchar, &delimiter_cur);
struct aws_byte_cursor name_str =
aws_byte_cursor_from_array(ffd.cFileName, wcsnlen(ffd.cFileName, sizeof(ffd.cFileName)) * sizeof(wchar_t));
aws_byte_buf_append_dynamic(&relative_path_wchar, &name_str);
aws_byte_buf_append_byte_dynamic(&relative_path_wchar, 0);
aws_byte_buf_append_byte_dynamic(&relative_path_wchar, 0);
relative_path_wchar.len -= 2;
/* now get the absolute path from the relative path we just computed. */
DWORD path_res = GetFullPathNameW((wchar_t *)relative_path_wchar.buffer, 0, NULL, NULL);
AWS_FATAL_ASSERT(path_res > 0);
struct aws_byte_buf full_path_wchar_buf;
aws_byte_buf_init(&full_path_wchar_buf, allocator, (size_t)path_res * sizeof(wchar_t) + 2);
full_path_wchar_buf.len = full_path_wchar_buf.capacity - 2;
path_res = GetFullPathNameW(
(wchar_t *)relative_path_wchar.buffer, (DWORD)path_res + 1, (wchar_t *)full_path_wchar_buf.buffer, NULL);
AWS_FATAL_ASSERT(path_res > 0);
aws_byte_buf_append_byte_dynamic(&full_path_wchar_buf, 0);
aws_byte_buf_append_byte_dynamic(&full_path_wchar_buf, 0);
/* now we have the data, convert the utf-16 strings we used to communicate with windows back to
utf-8 for the user to actually consume. */
struct aws_string *full_path_name_multi_char =
aws_string_convert_from_wchar_c_str(allocator, (wchar_t *)full_path_wchar_buf.buffer);
aws_byte_buf_clean_up(&full_path_wchar_buf);
struct aws_string *relative_path_multi_char =
aws_string_convert_from_wchar_c_str(allocator, (wchar_t *)relative_path_wchar.buffer);
struct aws_directory_entry entry;
AWS_ZERO_STRUCT(entry);
entry.relative_path = aws_byte_cursor_from_string(relative_path_multi_char);
entry.path = aws_byte_cursor_from_string(full_path_name_multi_char);
LARGE_INTEGER file_size;
file_size.HighPart = ffd.nFileSizeHigh;
file_size.LowPart = ffd.nFileSizeLow;
entry.file_size = (int64_t)file_size.QuadPart;
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
entry.file_type |= AWS_FILE_TYPE_DIRECTORY;
} else {
entry.file_type |= AWS_FILE_TYPE_FILE;
}
if (recursive && entry.file_type & AWS_FILE_TYPE_DIRECTORY) {
ret_val = aws_directory_traverse(allocator, relative_path_multi_char, recursive, on_entry, user_data);
}
/* post order traversal, if a node below us ended the traversal, don't call the visitor again. */
if (ret_val && aws_last_error() == AWS_ERROR_OPERATION_INTERUPTED) {
goto cleanup;
}
if (!on_entry(&entry, user_data)) {
ret_val = aws_raise_error(AWS_ERROR_OPERATION_INTERUPTED);
goto cleanup;
}
if (ret_val) {
goto cleanup;
}
cleanup:
aws_string_destroy(relative_path_multi_char);
aws_string_destroy(full_path_name_multi_char);
aws_byte_buf_clean_up(&relative_path_wchar);
aws_string_destroy(name_component_multi_char_str);
} while (ret_val == AWS_OP_SUCCESS && FindNextFileW(find_handle, &ffd));
aws_wstring_destroy(long_path_wchar);
if (find_handle != INVALID_HANDLE_VALUE) {
FindClose(find_handle);
}
return ret_val;
}