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