1 /**
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0.
4 */
5 #include "crt.h"
6 #include "java_class_ids.h"
7 #include <aws/common/file.h>
8 #include <aws/common/string.h>
9
10 struct directory_traversal_callback_ctx {
11 JNIEnv *env;
12 jobject handler;
13 };
14
s_on_directory_entry(const struct aws_directory_entry * entry,void * user_data)15 static bool s_on_directory_entry(const struct aws_directory_entry *entry, void *user_data) {
16
17 struct directory_traversal_callback_ctx *ctx = user_data;
18
19 /* this callback is synchronous, therefore no need to use aws_jni_get_thread_env() */
20 JNIEnv *env = ctx->env;
21
22 jobject directory_entry_object = (*env)->NewObject(
23 env,
24 directory_entry_properties.directory_entry_class,
25 directory_entry_properties.directory_entry_constructor_method_id);
26 if ((*env)->ExceptionCheck(env) || directory_entry_object == NULL) {
27 return false;
28 }
29
30 /* aws_jni_string_from_cursor() does not return NULL */
31 jstring path = aws_jni_string_from_cursor(env, &entry->path);
32 jstring relativePath = aws_jni_string_from_cursor(env, &entry->relative_path);
33
34 (*env)->SetObjectField(env, directory_entry_object, directory_entry_properties.path_field_id, path);
35 (*env)->SetObjectField(
36 env, directory_entry_object, directory_entry_properties.relative_path_field_id, relativePath);
37 (*env)->SetBooleanField(
38 env,
39 directory_entry_object,
40 directory_entry_properties.is_directory_field_id,
41 (entry->file_type & AWS_FILE_TYPE_DIRECTORY) != 0);
42 (*env)->SetBooleanField(
43 env,
44 directory_entry_object,
45 directory_entry_properties.is_symlink_field_id,
46 (entry->file_type & AWS_FILE_TYPE_SYM_LINK) != 0);
47 (*env)->SetBooleanField(
48 env,
49 directory_entry_object,
50 directory_entry_properties.is_file_field_id,
51 (entry->file_type & AWS_FILE_TYPE_FILE) != 0);
52 (*env)->SetLongField(
53 env, directory_entry_object, directory_entry_properties.file_size_field_id, (jlong)entry->file_size);
54
55 jboolean callback_result = (*env)->CallBooleanMethod(
56 env, ctx->handler, directory_traversal_handler_properties.on_directory_entry_method_id, directory_entry_object);
57
58 if ((*env)->ExceptionCheck(env)) {
59 /* If an exception is thrown by the user callback, the traversal is cancelled.
60 Cancelling the iteration either via the user callback returning false or throwing, results
61 in DirectoryTraversal.traverse() throwing an exception to notify user about incomplete results. */
62 callback_result = JNI_FALSE;
63 }
64
65 /* clean-up */
66 (*env)->DeleteLocalRef(env, directory_entry_object);
67
68 if (path != NULL) {
69 (*env)->DeleteLocalRef(env, path);
70 }
71
72 if (relativePath != NULL) {
73 (*env)->DeleteLocalRef(env, relativePath);
74 }
75
76 return (bool)callback_result;
77 }
78
Java_software_amazon_awssdk_crt_io_DirectoryTraversal_crtTraverse(JNIEnv * env,jclass jni_class,jstring path,jboolean recursive,jobject handler)79 JNIEXPORT void JNICALL Java_software_amazon_awssdk_crt_io_DirectoryTraversal_crtTraverse(
80 JNIEnv *env,
81 jclass jni_class,
82 jstring path,
83 jboolean recursive,
84 jobject handler) {
85 (void)jni_class;
86 aws_cache_jni_ids(env);
87
88 struct aws_string *path_str = aws_jni_new_string_from_jstring(env, path);
89 if (path_str == NULL) {
90 aws_jni_throw_runtime_exception(env, "failed to get path string");
91 return;
92 }
93
94 struct directory_traversal_callback_ctx ctx = {
95 .env = env,
96 .handler = handler,
97 };
98
99 struct aws_allocator *allocator = aws_jni_get_allocator();
100 if (aws_directory_traverse(allocator, path_str, (bool)recursive, s_on_directory_entry, &ctx)) {
101 /* If there's already a Java exception being thrown from the callback, then we don't need to throw another */
102 if (!(*env)->ExceptionCheck(env)) {
103 aws_jni_throw_runtime_exception(env, "Directory traversal failed");
104 }
105 }
106
107 aws_string_destroy(path_str);
108 }
109