From e2b5334db6f2a1741725c3124615794043e0d5dd Mon Sep 17 00:00:00 2001 From: Sven Date: Fri, 3 Apr 2026 15:38:20 +0200 Subject: [PATCH 1/4] Change naming of 2 variables --- src/utils.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/utils.c b/src/utils.c index 1132398..e8103c8 100644 --- a/src/utils.c +++ b/src/utils.c @@ -28,18 +28,18 @@ int is_config_path(const char* path) { return 0; } -char* substitute(const char* value, int dollar_sign_matched_index, size_t i, size_t env_len, const char *data) { +char* substitute(const char* value, int prefix_char_matched_index, size_t i, size_t env_len, const char *data) { size_t value_len = strlen(value); ssize_t len_diff = value_len - env_len; size_t data_len = strlen(data); size_t new_len = data_len+len_diff; char* new_data = malloc(new_len + 1); - size_t after_len = new_len - dollar_sign_matched_index - value_len; - memcpy(new_data, data, dollar_sign_matched_index); - memcpy(new_data+dollar_sign_matched_index, value, value_len); - memcpy(new_data+dollar_sign_matched_index+value_len, data+i, after_len); - assert(dollar_sign_matched_index+value_len+after_len == new_len); + size_t after_len = new_len - prefix_char_matched_index - value_len; + memcpy(new_data, data, prefix_char_matched_index); + memcpy(new_data+prefix_char_matched_index, value, value_len); + memcpy(new_data+prefix_char_matched_index+value_len, data+i, after_len); + assert(prefix_char_matched_index+value_len+after_len == new_len); new_data[new_len] = '\0'; return new_data; } @@ -73,11 +73,11 @@ void parse_file(char **data_ptr, size_t fsize, const char* filename) { } // +1 for the closing } - size_t afterClosingTagIndex = i + 1; + size_t after_closing_tag_index = i + 1; - size_t env_len = afterClosingTagIndex - begin_env_index; + size_t env_len = after_closing_tag_index - begin_env_index; - char* new_data = substitute(value, begin_env_index, afterClosingTagIndex, env_len, data); + char* new_data = substitute(value, begin_env_index, after_closing_tag_index, env_len, data); free(data); data = new_data; *data_ptr = new_data; -- 2.47.3 From 99b9a18ec3879c900ee828a57ee13b5e24c841ae Mon Sep 17 00:00:00 2001 From: Sven Date: Sun, 5 Apr 2026 18:22:33 +0200 Subject: [PATCH 2/4] Correctly set `i` and `fsize` after substitution --- src/utils.c | 13 ++++++++----- src/utils.h | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/utils.c b/src/utils.c index e8103c8..d3815a7 100644 --- a/src/utils.c +++ b/src/utils.c @@ -28,10 +28,7 @@ int is_config_path(const char* path) { return 0; } -char* substitute(const char* value, int prefix_char_matched_index, size_t i, size_t env_len, const char *data) { - size_t value_len = strlen(value); - ssize_t len_diff = value_len - env_len; - +char* substitute(const char* value, int prefix_char_matched_index, size_t i, size_t value_len, size_t len_diff, const char *data) { size_t data_len = strlen(data); size_t new_len = data_len+len_diff; char* new_data = malloc(new_len + 1); @@ -77,12 +74,18 @@ void parse_file(char **data_ptr, size_t fsize, const char* filename) { size_t env_len = after_closing_tag_index - begin_env_index; - char* new_data = substitute(value, begin_env_index, after_closing_tag_index, env_len, data); + size_t value_len = strlen(value); + ssize_t len_diff = value_len - env_len; + + char* new_data = substitute(value, begin_env_index, after_closing_tag_index, value_len, len_diff, data); free(data); data = new_data; *data_ptr = new_data; fprintf(stderr, "\033[0G[SubstAgent] Successfully expanded environment variable \"%s\" in file %s on line %d\n", env_var, filename, line_count); + + fsize += len_diff; + i += len_diff; begin_env_index = -1; env_var[0] = '\0'; continue; diff --git a/src/utils.h b/src/utils.h index 79495d3..9a3d5ed 100644 --- a/src/utils.h +++ b/src/utils.h @@ -8,7 +8,7 @@ extern jvmtiEnv* jvmti; void tag(jobject obj); int has_tag(jobject obj); int is_config_path(const char* path); -char* substitute(const char* value, int dollar_sign_matched_index, size_t i, size_t env_len, const char *data); +char* substitute(const char* value, int dollar_sign_matched_index, size_t i, size_t value_len, size_t len_diff, const char *data); void parse_file(char **data_ptr, size_t fsize, const char* filename); #define MIN(a, b) ((a) < (b) ? (a) : (b)) -- 2.47.3 From f1837e6c1aa342a82c69e251e41ca414c42768d9 Mon Sep 17 00:00:00 2001 From: Sven Date: Sun, 5 Apr 2026 18:27:22 +0200 Subject: [PATCH 3/4] Don't close env file when it doesn't exist --- src/substagent.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/substagent.c b/src/substagent.c index feb510b..4fdd844 100644 --- a/src/substagent.c +++ b/src/substagent.c @@ -120,13 +120,13 @@ static jint init_jvmti(JavaVM* vm) { } } free(line); + fclose(env_file); } else { if (errno != ENOENT) { perror("[SubstAgent] fopen failed"); exit(EXIT_FAILURE); } } - fclose(env_file); fprintf(stderr, "[SubstAgent] Loaded version %s\n", GIT_HASH); -- 2.47.3 From bdea9fec9be50626b34117fbd543907bfcdaf149 Mon Sep 17 00:00:00 2001 From: Sven Date: Sun, 5 Apr 2026 18:28:32 +0200 Subject: [PATCH 4/4] Format code --- src/fdi_hook.c | 194 ++++++++++---------- src/fdi_hook.h | 12 +- src/fis_hook.c | 448 ++++++++++++++++++++++++----------------------- src/fis_hook.h | 34 ++-- src/substagent.c | 248 +++++++++++++------------- src/utils.c | 189 +++++++++++--------- src/utils.h | 9 +- 7 files changed, 587 insertions(+), 547 deletions(-) diff --git a/src/fdi_hook.c b/src/fdi_hook.c index aefa377..b87e86b 100644 --- a/src/fdi_hook.c +++ b/src/fdi_hook.c @@ -11,117 +11,119 @@ und_close0_t und_real_close0 = NULL; fdi_read0_t fdi_real_read0 = NULL; struct fdi_file_data { - char* data; - size_t index; - size_t length; - int freed; - size_t inode; - size_t device; + char *data; + size_t index; + size_t length; + int freed; + size_t inode; + size_t device; }; struct file { - jint key; - struct fdi_file_data value; + jint key; + struct fdi_file_data value; } *fdi_files_map = NULL; -jint JNICALL und_open0_hook(JNIEnv *env, jobject thiz, jlong path_address, jint flags, jint mode) { - jint fd = und_real_open0(env, thiz, path_address, flags, mode); - const char *path = (const char *)(intptr_t)path_address; - if (!path || !is_config_path(path)) { - return fd; - } - - struct stat st; - if (fstat(fd, &st) != 0) { - jclass fileNotFoundException = - (*env)->FindClass(env, "java/io/FileNotFoundException"); - (*env)->ThrowNew(env, fileNotFoundException, path); - return fd; - } - size_t fsize = st.st_size; - - FILE *file = fopen(path, "rb"); - if (!file) { - jclass fileNotFoundException = - (*env)->FindClass(env, "java/io/FileNotFoundException"); - (*env)->ThrowNew(env, fileNotFoundException, path); - return fd; - } - - char *data = malloc(fsize + 1); - fread(data, fsize, 1, file); - fclose(file); - data[fsize] = '\0'; - - parse_file(&data, fsize, path); - - size_t fd_len = strlen(data); - - struct fdi_file_data file_data; - file_data.data = data; - file_data.length = fd_len; - file_data.index = 0; - file_data.freed = 0; - file_data.inode = st.st_ino; - file_data.device = st.st_dev; - hmput(fdi_files_map, fd, file_data); - +jint JNICALL und_open0_hook(JNIEnv *env, jobject thiz, jlong path_address, + jint flags, jint mode) { + jint fd = und_real_open0(env, thiz, path_address, flags, mode); + const char *path = (const char *)(intptr_t)path_address; + if (!path || !is_config_path(path)) { return fd; + } + + struct stat st; + if (fstat(fd, &st) != 0) { + jclass fileNotFoundException = + (*env)->FindClass(env, "java/io/FileNotFoundException"); + (*env)->ThrowNew(env, fileNotFoundException, path); + return fd; + } + size_t fsize = st.st_size; + + FILE *file = fopen(path, "rb"); + if (!file) { + jclass fileNotFoundException = + (*env)->FindClass(env, "java/io/FileNotFoundException"); + (*env)->ThrowNew(env, fileNotFoundException, path); + return fd; + } + + char *data = malloc(fsize + 1); + fread(data, fsize, 1, file); + fclose(file); + data[fsize] = '\0'; + + parse_file(&data, fsize, path); + + size_t fd_len = strlen(data); + + struct fdi_file_data file_data; + file_data.data = data; + file_data.length = fd_len; + file_data.index = 0; + file_data.freed = 0; + file_data.inode = st.st_ino; + file_data.device = st.st_dev; + hmput(fdi_files_map, fd, file_data); + + return fd; } -void JNICALL und_close0_hook(JNIEnv* env, jobject thiz, jint fd) { - struct file *file = hmgetp_null(fdi_files_map, fd); - if (file != NULL) { - free(file->value.data); - file->value.data = NULL; - hmdel(fdi_files_map, fd); - } +void JNICALL und_close0_hook(JNIEnv *env, jobject thiz, jint fd) { + struct file *file = hmgetp_null(fdi_files_map, fd); + if (file != NULL) { + free(file->value.data); + file->value.data = NULL; + hmdel(fdi_files_map, fd); + } } -jint JNICALL fdi_read0_hook(JNIEnv *env, jobject thiz, jobject fdObject, jlong address, jint len) { - jclass class = (*env)->GetObjectClass(env, fdObject); - jfieldID fieldID = (*env)->GetFieldID(env, class, "fd", "I"); - jint fd = (*env)->GetIntField(env, fdObject, fieldID); +jint JNICALL fdi_read0_hook(JNIEnv *env, jobject thiz, jobject fdObject, + jlong address, jint len) { + jclass class = (*env)->GetObjectClass(env, fdObject); + jfieldID fieldID = (*env)->GetFieldID(env, class, "fd", "I"); + jint fd = (*env)->GetIntField(env, fdObject, fieldID); - struct file *file = hmgetp_null(fdi_files_map, fd); - if (file == NULL) { - return fdi_real_read0(env, thiz, fdObject, address, len); - } - - struct fdi_file_data *file_data = &file->value; - struct stat st; - if (fstat(fd, &st) != 0) { - hmdel(fdi_files_map, fd); - return fdi_real_read0(env, thiz, fdObject, address, len); - } + struct file *file = hmgetp_null(fdi_files_map, fd); + if (file == NULL) { + return fdi_real_read0(env, thiz, fdObject, address, len); + } - // Check if it's still the same file - if (st.st_ino != file_data->inode || st.st_dev != file_data->device) { - hmdel(fdi_files_map, fd); - return fdi_real_read0(env, thiz, fdObject, address, len); - } + struct fdi_file_data *file_data = &file->value; + struct stat st; + if (fstat(fd, &st) != 0) { + hmdel(fdi_files_map, fd); + return fdi_real_read0(env, thiz, fdObject, address, len); + } - if (file_data->freed) { - return -1; - } + // Check if it's still the same file + if (st.st_ino != file_data->inode || st.st_dev != file_data->device) { + hmdel(fdi_files_map, fd); + return fdi_real_read0(env, thiz, fdObject, address, len); + } - if (file_data->length == 0) { - free(file_data->data); - file_data->data = NULL; - file_data->freed = 1; - return -1; - } + if (file_data->freed) { + return -1; + } - int n = MIN(len, file_data->length - file_data->index); - memcpy((void *)(intptr_t)address, file_data->data + file_data->index, n); + if (file_data->length == 0) { + free(file_data->data); + file_data->data = NULL; + file_data->freed = 1; + return -1; + } - if (n == file_data->length - file_data->index) { - free(file_data->data); - file_data->data = NULL; - file_data->freed = 1; - } else { - file_data->index += n; - } + int n = MIN(len, file_data->length - file_data->index); + memcpy((void *)(intptr_t)address, file_data->data + file_data->index, n); - return n; + if (n == file_data->length - file_data->index) { + free(file_data->data); + file_data->data = NULL; + file_data->freed = 1; + } else { + file_data->index += n; + } + + return n; } \ No newline at end of file diff --git a/src/fdi_hook.h b/src/fdi_hook.h index e37f3f5..5b34f07 100644 --- a/src/fdi_hook.h +++ b/src/fdi_hook.h @@ -3,17 +3,17 @@ #include -typedef jint (JNICALL *und_open0_t)(JNIEnv*, jobject, jlong, jint, jint); +typedef jint(JNICALL *und_open0_t)(JNIEnv *, jobject, jlong, jint, jint); extern und_open0_t und_real_open0; -typedef jint (JNICALL *und_close0_t)(JNIEnv*, jobject, jint); +typedef jint(JNICALL *und_close0_t)(JNIEnv *, jobject, jint); extern und_close0_t und_real_close0; -typedef jint (JNICALL *fdi_read0_t)(JNIEnv*, jobject, jobject, jlong, jint); +typedef jint(JNICALL *fdi_read0_t)(JNIEnv *, jobject, jobject, jlong, jint); extern fdi_read0_t fdi_real_read0; -jint JNICALL und_open0_hook(JNIEnv*, jobject, jlong, jint, jint); -void JNICALL und_close0_hook(JNIEnv*, jobject, jint); +jint JNICALL und_open0_hook(JNIEnv *, jobject, jlong, jint, jint); +void JNICALL und_close0_hook(JNIEnv *, jobject, jint); -jint JNICALL fdi_read0_hook(JNIEnv*, jobject, jobject, jlong, jint); +jint JNICALL fdi_read0_hook(JNIEnv *, jobject, jobject, jlong, jint); #endif \ No newline at end of file diff --git a/src/fis_hook.c b/src/fis_hook.c index 5fd42d9..810ed3e 100644 --- a/src/fis_hook.c +++ b/src/fis_hook.c @@ -15,239 +15,249 @@ fis_available0_t fis_real_available0 = NULL; fis_close_t fis_real_close = NULL; struct fis_file_data { - char* data; - size_t index; - size_t length; - int freed; + char *data; + size_t index; + size_t length; + int freed; }; -struct file{ - jint key; - struct fis_file_data value; +struct file { + jint key; + struct fis_file_data value; } *fis_files_map = NULL; -jint JNICALL fis_readBytes_hook(JNIEnv* env, jobject thiz, jbyteArray buf, jint off, jint len) { - if (!has_tag(thiz)) { - return fis_real_readBytes(env, thiz, buf, off, len); - } +jint JNICALL fis_readBytes_hook(JNIEnv *env, jobject thiz, jbyteArray buf, + jint off, jint len) { + if (!has_tag(thiz)) { + return fis_real_readBytes(env, thiz, buf, off, len); + } - jclass class = (*env)->GetObjectClass(env, thiz); - jmethodID hash_code_method = (*env)->GetMethodID(env, class, "hashCode", "()I"); + jclass class = (*env)->GetObjectClass(env, thiz); + jmethodID hash_code_method = + (*env)->GetMethodID(env, class, "hashCode", "()I"); - jint hash = (*env)->CallIntMethod(env, thiz, hash_code_method); + jint hash = (*env)->CallIntMethod(env, thiz, hash_code_method); - struct file *file = hmgetp_null(fis_files_map, hash); - if (file == NULL || file->value.freed) { - return -1; - } + struct file *file = hmgetp_null(fis_files_map, hash); + if (file == NULL || file->value.freed) { + return -1; + } - struct fis_file_data *fd = &file->value; - jsize ba_length = (*env)->GetArrayLength(env, buf); - jbyte *ba = (*env)->GetByteArrayElements(env, buf, JNI_FALSE); + struct fis_file_data *fd = &file->value; + jsize ba_length = (*env)->GetArrayLength(env, buf); + jbyte *ba = (*env)->GetByteArrayElements(env, buf, JNI_FALSE); - size_t remaining = fd->length - fd->index; - - jsize len_want_to_read = MIN((ba_length - off), len); - jsize len_to_read = MIN(len_want_to_read, (jsize)remaining); - if (len_to_read < 0) { - (*env)->ReleaseByteArrayElements(env, buf, ba, 0); - return -1; - } - memcpy(ba + off, fd->data + fd->index, len_to_read); + size_t remaining = fd->length - fd->index; + jsize len_want_to_read = MIN((ba_length - off), len); + jsize len_to_read = MIN(len_want_to_read, (jsize)remaining); + if (len_to_read < 0) { (*env)->ReleaseByteArrayElements(env, buf, ba, 0); + return -1; + } + memcpy(ba + off, fd->data + fd->index, len_to_read); - fd->index += len_to_read; - if (fd->index == fd->length) { - free(fd->data); - fd->data = NULL; - fd->freed = 1; - } + (*env)->ReleaseByteArrayElements(env, buf, ba, 0); - return len_to_read; + fd->index += len_to_read; + if (fd->index == fd->length) { + free(fd->data); + fd->data = NULL; + fd->freed = 1; + } + + return len_to_read; } -void JNICALL fis_open0_hook(JNIEnv* env, jobject thiz, jstring jpath) { - if (has_tag(thiz)) { - return; - } - - const char* path = (*env)->GetStringUTFChars(env, jpath, NULL); - if (!path || !is_config_path(path)) { - fis_real_open0(env, thiz, jpath); - return; - } - tag(thiz); - - jclass class = (*env)->GetObjectClass(env, thiz); - jmethodID hash_code_method = (*env)->GetMethodID(env, class, "hashCode", "()I"); - jint hash = (*env)->CallIntMethod(env, thiz, hash_code_method); - - FILE *file = fopen(path, "rb"); - if (!file) { - jclass fileNotFoundException = (*env)->FindClass(env, "java/io/FileNotFoundException"); - (*env)->ThrowNew(env, fileNotFoundException, path); - return; - } - - struct stat st; - if (fstat(fileno(file), &st) != 0) { - jclass fileNotFoundException = - (*env)->FindClass(env, "java/io/FileNotFoundException"); - (*env)->ThrowNew(env, fileNotFoundException, path); - return; - } - size_t fsize = st.st_size; - if (fsize == 0) { - fclose(file); - return; - } - - char *data = malloc(fsize + 1); - fread(data, fsize, 1, file); - fclose(file); - data[fsize] = '\0'; - - parse_file(&data, fsize, path); - - size_t fd_len = strlen(data); - - struct fis_file_data file_data; - file_data.data = data; - file_data.length = fd_len; - file_data.index = 0; - file_data.freed = 0; - hmput(fis_files_map, hash, file_data); - (*env)->ReleaseStringUTFChars(env, jpath, path); -} - -jint JNICALL fis_read0_hook(JNIEnv* env, jobject thiz) { - if (!has_tag(thiz)) { - return fis_real_read0(env, thiz); - } - - jclass class = (*env)->GetObjectClass(env, thiz); - jmethodID hash_code_method = (*env)->GetMethodID(env, class, "hashCode", "()I"); - - jint hash = (*env)->CallIntMethod(env, thiz, hash_code_method); - - struct file *file = hmgetp_null(fis_files_map, hash); - if (file == NULL || file->value.freed) { - return -1; - } - - struct fis_file_data *fd = &file->value; - char read_byte = fd->data[fd->index++]; - if (fd->data[fd->index] == '\0') { - free(fd->data); - fd->data = NULL; - fd->freed = 1; - } - return read_byte; -} - -jlong JNICALL fis_length0_hook(JNIEnv* env, jobject thiz) { - if (!has_tag(thiz)) { - return fis_real_length0(env, thiz); - } - - jclass class = (*env)->GetObjectClass(env, thiz); - jmethodID hash_code_method = (*env)->GetMethodID(env, class, "hashCode", "()I"); - - jint hash = (*env)->CallIntMethod(env, thiz, hash_code_method); - - struct file *file = hmgetp_null(fis_files_map, hash); - if (file == NULL) { - return -1; - } - - return file->value.length; -} - -jlong JNICALL fis_position0_hook(JNIEnv* env, jobject thiz) { - if (!has_tag(thiz)) { - return fis_real_length0(env, thiz); - } - - jclass class = (*env)->GetObjectClass(env, thiz); - jmethodID hash_code_method = (*env)->GetMethodID(env, class, "hashCode", "()I"); - - jint hash = (*env)->CallIntMethod(env, thiz, hash_code_method); - - struct file *file = hmgetp_null(fis_files_map, hash); - if (file == NULL) { - return -1; - } - - return file->value.index; -} - -jlong JNICALL fis_skip0_hook(JNIEnv* env, jobject thiz, jlong n) { - if (!has_tag(thiz)) { - return fis_real_skip0(env, thiz, n); - } - - jclass class = (*env)->GetObjectClass(env, thiz); - jmethodID hash_code_method = (*env)->GetMethodID(env, class, "hashCode", "()I"); - - jint hash = (*env)->CallIntMethod(env, thiz, hash_code_method); - - struct file *file = hmgetp_null(fis_files_map, hash); - if (file == NULL) { - return 0; - } - - struct fis_file_data *fd = &file->value; - - size_t remaining = fd->length - fd->index; - size_t skip = MIN(remaining, n); - fd->index += skip; - if (skip == remaining) { - free(fd->data); - fd->data = NULL; - fd->freed = 1; - return skip; - } - - return skip; -} - -jint JNICALL fis_available0_hook(JNIEnv* env, jobject thiz) { - if (!has_tag(thiz)) { - return fis_real_available0(env, thiz); - } - - jclass class = (*env)->GetObjectClass(env, thiz); - jmethodID hash_code_method = (*env)->GetMethodID(env, class, "hashCode", "()I"); - - jint hash = (*env)->CallIntMethod(env, thiz, hash_code_method); - - struct file *file = hmgetp_null(fis_files_map, hash); - if (file == NULL) { - return 0; - } - - struct fis_file_data *fd = &file->value; - return fd->length - fd->index; -} - -void JNICALL fis_close_hook(JNIEnv* env, jobject thiz) { - if (!has_tag(thiz)) { - return fis_real_close(env, thiz); - } - - jclass class = (*env)->GetObjectClass(env, thiz); - jmethodID hash_code_method = (*env)->GetMethodID(env, class, "hashCode", "()I"); - - jint hash = (*env)->CallIntMethod(env, thiz, hash_code_method); - - struct file *file = hmgetp_null(fis_files_map, hash); - if (file == NULL) { - return; - } - - free(file->value.data); - file->value.data = NULL; - file->value.freed = 1; +void JNICALL fis_open0_hook(JNIEnv *env, jobject thiz, jstring jpath) { + if (has_tag(thiz)) { return; + } + + const char *path = (*env)->GetStringUTFChars(env, jpath, NULL); + if (!path || !is_config_path(path)) { + fis_real_open0(env, thiz, jpath); + return; + } + tag(thiz); + + jclass class = (*env)->GetObjectClass(env, thiz); + jmethodID hash_code_method = + (*env)->GetMethodID(env, class, "hashCode", "()I"); + jint hash = (*env)->CallIntMethod(env, thiz, hash_code_method); + + FILE *file = fopen(path, "rb"); + if (!file) { + jclass fileNotFoundException = + (*env)->FindClass(env, "java/io/FileNotFoundException"); + (*env)->ThrowNew(env, fileNotFoundException, path); + return; + } + + struct stat st; + if (fstat(fileno(file), &st) != 0) { + jclass fileNotFoundException = + (*env)->FindClass(env, "java/io/FileNotFoundException"); + (*env)->ThrowNew(env, fileNotFoundException, path); + return; + } + size_t fsize = st.st_size; + if (fsize == 0) { + fclose(file); + return; + } + + char *data = malloc(fsize + 1); + fread(data, fsize, 1, file); + fclose(file); + data[fsize] = '\0'; + + parse_file(&data, fsize, path); + + size_t fd_len = strlen(data); + + struct fis_file_data file_data; + file_data.data = data; + file_data.length = fd_len; + file_data.index = 0; + file_data.freed = 0; + hmput(fis_files_map, hash, file_data); + (*env)->ReleaseStringUTFChars(env, jpath, path); +} + +jint JNICALL fis_read0_hook(JNIEnv *env, jobject thiz) { + if (!has_tag(thiz)) { + return fis_real_read0(env, thiz); + } + + jclass class = (*env)->GetObjectClass(env, thiz); + jmethodID hash_code_method = + (*env)->GetMethodID(env, class, "hashCode", "()I"); + + jint hash = (*env)->CallIntMethod(env, thiz, hash_code_method); + + struct file *file = hmgetp_null(fis_files_map, hash); + if (file == NULL || file->value.freed) { + return -1; + } + + struct fis_file_data *fd = &file->value; + char read_byte = fd->data[fd->index++]; + if (fd->data[fd->index] == '\0') { + free(fd->data); + fd->data = NULL; + fd->freed = 1; + } + return read_byte; +} + +jlong JNICALL fis_length0_hook(JNIEnv *env, jobject thiz) { + if (!has_tag(thiz)) { + return fis_real_length0(env, thiz); + } + + jclass class = (*env)->GetObjectClass(env, thiz); + jmethodID hash_code_method = + (*env)->GetMethodID(env, class, "hashCode", "()I"); + + jint hash = (*env)->CallIntMethod(env, thiz, hash_code_method); + + struct file *file = hmgetp_null(fis_files_map, hash); + if (file == NULL) { + return -1; + } + + return file->value.length; +} + +jlong JNICALL fis_position0_hook(JNIEnv *env, jobject thiz) { + if (!has_tag(thiz)) { + return fis_real_length0(env, thiz); + } + + jclass class = (*env)->GetObjectClass(env, thiz); + jmethodID hash_code_method = + (*env)->GetMethodID(env, class, "hashCode", "()I"); + + jint hash = (*env)->CallIntMethod(env, thiz, hash_code_method); + + struct file *file = hmgetp_null(fis_files_map, hash); + if (file == NULL) { + return -1; + } + + return file->value.index; +} + +jlong JNICALL fis_skip0_hook(JNIEnv *env, jobject thiz, jlong n) { + if (!has_tag(thiz)) { + return fis_real_skip0(env, thiz, n); + } + + jclass class = (*env)->GetObjectClass(env, thiz); + jmethodID hash_code_method = + (*env)->GetMethodID(env, class, "hashCode", "()I"); + + jint hash = (*env)->CallIntMethod(env, thiz, hash_code_method); + + struct file *file = hmgetp_null(fis_files_map, hash); + if (file == NULL) { + return 0; + } + + struct fis_file_data *fd = &file->value; + + size_t remaining = fd->length - fd->index; + size_t skip = MIN(remaining, n); + fd->index += skip; + if (skip == remaining) { + free(fd->data); + fd->data = NULL; + fd->freed = 1; + return skip; + } + + return skip; +} + +jint JNICALL fis_available0_hook(JNIEnv *env, jobject thiz) { + if (!has_tag(thiz)) { + return fis_real_available0(env, thiz); + } + + jclass class = (*env)->GetObjectClass(env, thiz); + jmethodID hash_code_method = + (*env)->GetMethodID(env, class, "hashCode", "()I"); + + jint hash = (*env)->CallIntMethod(env, thiz, hash_code_method); + + struct file *file = hmgetp_null(fis_files_map, hash); + if (file == NULL) { + return 0; + } + + struct fis_file_data *fd = &file->value; + return fd->length - fd->index; +} + +void JNICALL fis_close_hook(JNIEnv *env, jobject thiz) { + if (!has_tag(thiz)) { + return fis_real_close(env, thiz); + } + + jclass class = (*env)->GetObjectClass(env, thiz); + jmethodID hash_code_method = + (*env)->GetMethodID(env, class, "hashCode", "()I"); + + jint hash = (*env)->CallIntMethod(env, thiz, hash_code_method); + + struct file *file = hmgetp_null(fis_files_map, hash); + if (file == NULL) { + return; + } + + free(file->value.data); + file->value.data = NULL; + file->value.freed = 1; + return; } \ No newline at end of file diff --git a/src/fis_hook.h b/src/fis_hook.h index c303b38..7d3c4fe 100644 --- a/src/fis_hook.h +++ b/src/fis_hook.h @@ -3,14 +3,15 @@ #include -typedef void (JNICALL *fis_open0_t)(JNIEnv*, jobject, jstring); -typedef jint (JNICALL *fis_readBytes_t)(JNIEnv*, jobject, jbyteArray, jint, jint); -typedef jint (JNICALL *fis_read0_t)(JNIEnv*, jobject); -typedef jlong (JNICALL *fis_length0_t)(JNIEnv*, jobject); -typedef jlong (JNICALL *fis_position0_t)(JNIEnv*, jobject); -typedef jlong (JNICALL *fis_skip0_t)(JNIEnv*, jobject, jlong); -typedef jint (JNICALL *fis_available0_t)(JNIEnv*, jobject); -typedef void (JNICALL *fis_close_t)(JNIEnv*, jobject); +typedef void(JNICALL *fis_open0_t)(JNIEnv *, jobject, jstring); +typedef jint(JNICALL *fis_readBytes_t)(JNIEnv *, jobject, jbyteArray, jint, + jint); +typedef jint(JNICALL *fis_read0_t)(JNIEnv *, jobject); +typedef jlong(JNICALL *fis_length0_t)(JNIEnv *, jobject); +typedef jlong(JNICALL *fis_position0_t)(JNIEnv *, jobject); +typedef jlong(JNICALL *fis_skip0_t)(JNIEnv *, jobject, jlong); +typedef jint(JNICALL *fis_available0_t)(JNIEnv *, jobject); +typedef void(JNICALL *fis_close_t)(JNIEnv *, jobject); extern fis_readBytes_t fis_real_readBytes; extern fis_open0_t fis_real_open0; extern fis_read0_t fis_real_read0; @@ -20,13 +21,14 @@ extern fis_skip0_t fis_real_skip0; extern fis_available0_t fis_real_available0; extern fis_close_t fis_real_close; -jint JNICALL fis_readBytes_hook(JNIEnv* env, jobject thiz, jbyteArray buf, jint off, jint len); -void JNICALL fis_open0_hook(JNIEnv* env, jobject thiz, jstring jpath); -jint JNICALL fis_read0_hook(JNIEnv* env, jobject thiz); -jlong JNICALL fis_length0_hook(JNIEnv* env, jobject thiz); -jlong JNICALL fis_position0_hook(JNIEnv* env, jobject thiz); -jlong JNICALL fis_skip0_hook(JNIEnv* env, jobject thiz, jlong n); -jint JNICALL fis_available0_hook(JNIEnv* env, jobject thiz); -void JNICALL fis_close_hook(JNIEnv* env, jobject thiz); +jint JNICALL fis_readBytes_hook(JNIEnv *env, jobject thiz, jbyteArray buf, + jint off, jint len); +void JNICALL fis_open0_hook(JNIEnv *env, jobject thiz, jstring jpath); +jint JNICALL fis_read0_hook(JNIEnv *env, jobject thiz); +jlong JNICALL fis_length0_hook(JNIEnv *env, jobject thiz); +jlong JNICALL fis_position0_hook(JNIEnv *env, jobject thiz); +jlong JNICALL fis_skip0_hook(JNIEnv *env, jobject thiz, jlong n); +jint JNICALL fis_available0_hook(JNIEnv *env, jobject thiz); +void JNICALL fis_close_hook(JNIEnv *env, jobject thiz); #endif \ No newline at end of file diff --git a/src/substagent.c b/src/substagent.c index 4fdd844..7aa2294 100644 --- a/src/substagent.c +++ b/src/substagent.c @@ -1,144 +1,152 @@ -#include -#include -#include #include "build_info.h" #include "fdi_hook.h" #include "fis_hook.h" #include "utils.h" +#include +#include +#include -static void JNICALL onNativeMethodBind(jvmtiEnv* jvmti_env, JNIEnv* env, jthread thread, jmethodID method, void* address, void** new_address_ptr) { - char* mname = NULL; - char* msig = NULL; - char* csig = NULL; - char* gsig = NULL; +static void JNICALL onNativeMethodBind(jvmtiEnv *jvmti_env, JNIEnv *env, + jthread thread, jmethodID method, + void *address, void **new_address_ptr) { + char *mname = NULL; + char *msig = NULL; + char *csig = NULL; + char *gsig = NULL; - jclass decl; - (*jvmti_env)->GetMethodDeclaringClass(jvmti_env, method, &decl); - (*jvmti_env)->GetClassSignature(jvmti_env, decl, &csig, &gsig); - (*jvmti_env)->GetMethodName(jvmti_env, method, &mname, &msig, NULL); + jclass decl; + (*jvmti_env)->GetMethodDeclaringClass(jvmti_env, method, &decl); + (*jvmti_env)->GetClassSignature(jvmti_env, decl, &csig, &gsig); + (*jvmti_env)->GetMethodName(jvmti_env, method, &mname, &msig, NULL); - if (csig && mname && msig) { - if (strcmp(csig, "Ljava/io/FileInputStream;") == 0) { - // private native void open0(String name) - if (strcmp(mname, "open0") == 0 && strcmp(msig, "(Ljava/lang/String;)V") == 0) { - fis_real_open0 = (fis_open0_t)address; - *new_address_ptr = (void*)&fis_open0_hook; - // private native int readBytes(byte b[], int off, int len) - } else if (strcmp(mname, "readBytes") == 0 && strcmp(msig, "([BII)I") == 0) { - fis_real_readBytes = (fis_readBytes_t)address; - *new_address_ptr = (void*)&fis_readBytes_hook; - // private native int read0 - } else if (strcmp(mname, "read0") == 0 && strcmp(msig, "()I") == 0) { - fis_real_read0 = (fis_read0_t)address; - *new_address_ptr = (void*)&fis_read0_hook; - // private native long length0() - } else if (strcmp(mname, "length0") == 0 && strcmp(msig, "()J") == 0) { - fis_real_length0 = (fis_length0_t)address; - *new_address_ptr = (void*)&fis_length0_hook; - // private native long position0() - } else if (strcmp(mname, "position0") == 0 && strcmp(msig, "()J") == 0) { - fis_real_position0 = (fis_position0_t)address; - *new_address_ptr = (void*)&fis_position0_hook; - // private native long skip0(long n) - } else if (strcmp(mname, "skip0") == 0 && strcmp(msig, "(J)J") == 0) { - fis_real_skip0 = (fis_skip0_t)address; - *new_address_ptr = (void*)&fis_skip0_hook; - // private native int available0() - } else if (strcmp(mname, "available0") == 0 && strcmp(msig, "()I") == 0) { - fis_real_available0 = (fis_available0_t)address; - *new_address_ptr = (void*)&fis_available0_hook; - // public void close() - } else if (strcmp(mname, "close") == 0 && strcmp(msig, "()V") == 0) { - fis_real_close = (fis_close_t)address; - *new_address_ptr = (void*)&fis_close_hook; - } - } else if (strcmp(csig, "Lsun/nio/fs/UnixNativeDispatcher;") == 0) { - // private static native int open0(long pathAddress, int flags, int mode) - if (strcmp(mname, "open0") == 0 && strcmp(msig, "(JII)I") == 0) { - und_real_open0 = (und_open0_t)address; - *new_address_ptr = (void*)&und_open0_hook; - // private static native void close0(int fd) - } else if (strcmp(mname, "close0") == 0 && strcmp(msig, "(I)V") == 0) { - und_real_close0 = (und_close0_t)address; - *new_address_ptr = (void*)&und_close0_hook; - } - } else if (strcmp(csig, "Lsun/nio/ch/FileDispatcherImpl;") == 0) { - // static native int read0(FileDescriptor fd, long address, int len) - if (strcmp(mname, "read0") == 0 && strcmp(msig, "(Ljava/io/FileDescriptor;JI)I") == 0) { - fdi_real_read0 = (fdi_read0_t)address; - *new_address_ptr = (void*)&fdi_read0_hook; - } - } + if (csig && mname && msig) { + if (strcmp(csig, "Ljava/io/FileInputStream;") == 0) { + // private native void open0(String name) + if (strcmp(mname, "open0") == 0 && + strcmp(msig, "(Ljava/lang/String;)V") == 0) { + fis_real_open0 = (fis_open0_t)address; + *new_address_ptr = (void *)&fis_open0_hook; + // private native int readBytes(byte b[], int off, int len) + } else if (strcmp(mname, "readBytes") == 0 && + strcmp(msig, "([BII)I") == 0) { + fis_real_readBytes = (fis_readBytes_t)address; + *new_address_ptr = (void *)&fis_readBytes_hook; + // private native int read0 + } else if (strcmp(mname, "read0") == 0 && strcmp(msig, "()I") == 0) { + fis_real_read0 = (fis_read0_t)address; + *new_address_ptr = (void *)&fis_read0_hook; + // private native long length0() + } else if (strcmp(mname, "length0") == 0 && strcmp(msig, "()J") == 0) { + fis_real_length0 = (fis_length0_t)address; + *new_address_ptr = (void *)&fis_length0_hook; + // private native long position0() + } else if (strcmp(mname, "position0") == 0 && strcmp(msig, "()J") == 0) { + fis_real_position0 = (fis_position0_t)address; + *new_address_ptr = (void *)&fis_position0_hook; + // private native long skip0(long n) + } else if (strcmp(mname, "skip0") == 0 && strcmp(msig, "(J)J") == 0) { + fis_real_skip0 = (fis_skip0_t)address; + *new_address_ptr = (void *)&fis_skip0_hook; + // private native int available0() + } else if (strcmp(mname, "available0") == 0 && strcmp(msig, "()I") == 0) { + fis_real_available0 = (fis_available0_t)address; + *new_address_ptr = (void *)&fis_available0_hook; + // public void close() + } else if (strcmp(mname, "close") == 0 && strcmp(msig, "()V") == 0) { + fis_real_close = (fis_close_t)address; + *new_address_ptr = (void *)&fis_close_hook; + } + } else if (strcmp(csig, "Lsun/nio/fs/UnixNativeDispatcher;") == 0) { + // private static native int open0(long pathAddress, int flags, int mode) + if (strcmp(mname, "open0") == 0 && strcmp(msig, "(JII)I") == 0) { + und_real_open0 = (und_open0_t)address; + *new_address_ptr = (void *)&und_open0_hook; + // private static native void close0(int fd) + } else if (strcmp(mname, "close0") == 0 && strcmp(msig, "(I)V") == 0) { + und_real_close0 = (und_close0_t)address; + *new_address_ptr = (void *)&und_close0_hook; + } + } else if (strcmp(csig, "Lsun/nio/ch/FileDispatcherImpl;") == 0) { + // static native int read0(FileDescriptor fd, long address, int len) + if (strcmp(mname, "read0") == 0 && + strcmp(msig, "(Ljava/io/FileDescriptor;JI)I") == 0) { + fdi_real_read0 = (fdi_read0_t)address; + *new_address_ptr = (void *)&fdi_read0_hook; + } } + } - (*jvmti_env)->Deallocate(jvmti_env, (unsigned char*)mname); - (*jvmti_env)->Deallocate(jvmti_env, (unsigned char*)msig); - (*jvmti_env)->Deallocate(jvmti_env, (unsigned char*)csig); - (*jvmti_env)->Deallocate(jvmti_env, (unsigned char*)gsig); + (*jvmti_env)->Deallocate(jvmti_env, (unsigned char *)mname); + (*jvmti_env)->Deallocate(jvmti_env, (unsigned char *)msig); + (*jvmti_env)->Deallocate(jvmti_env, (unsigned char *)csig); + (*jvmti_env)->Deallocate(jvmti_env, (unsigned char *)gsig); } -static jint init_jvmti(JavaVM* vm) { - jint rc = (*vm)->GetEnv(vm, (void**)&jvmti, JVMTI_VERSION_1_2); - if (rc != JNI_OK || jvmti == NULL) return JNI_ERR; +static jint init_jvmti(JavaVM *vm) { + jint rc = (*vm)->GetEnv(vm, (void **)&jvmti, JVMTI_VERSION_1_2); + if (rc != JNI_OK || jvmti == NULL) + return JNI_ERR; - jvmtiCapabilities caps; - memset(&caps, 0, sizeof(caps)); - caps.can_generate_native_method_bind_events = 1; - caps.can_tag_objects = 1; - (*jvmti)->AddCapabilities(jvmti, &caps); + jvmtiCapabilities caps; + memset(&caps, 0, sizeof(caps)); + caps.can_generate_native_method_bind_events = 1; + caps.can_tag_objects = 1; + (*jvmti)->AddCapabilities(jvmti, &caps); - jvmtiEventCallbacks callbacks; - memset(&callbacks, 0, sizeof(callbacks)); - callbacks.NativeMethodBind = &onNativeMethodBind; - (*jvmti)->SetEventCallbacks(jvmti, &callbacks, (jint)sizeof(callbacks)); + jvmtiEventCallbacks callbacks; + memset(&callbacks, 0, sizeof(callbacks)); + callbacks.NativeMethodBind = &onNativeMethodBind; + (*jvmti)->SetEventCallbacks(jvmti, &callbacks, (jint)sizeof(callbacks)); - (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_NATIVE_METHOD_BIND, (jthread)NULL); + (*jvmti)->SetEventNotificationMode( + jvmti, JVMTI_ENABLE, JVMTI_EVENT_NATIVE_METHOD_BIND, (jthread)NULL); - FILE *env_file = fopen(".env", "r"); - if (env_file) { - char* line = NULL; - size_t len = 0; - ssize_t n; - while ((n = getline(&line, &len, env_file)) != -1) { - if (n > 0 && line[n - 1] == '\n') { - line[n - 1] = '\0'; - } - if (line[0] == '#') { - continue; - } - char *name = line; - char *value = NULL; - char *equal = strchr(line, '='); - if (equal == NULL) { - fprintf(stderr, "\e[0;31m[SubstAgent] Invalid line in .env: \"%s\"\e[0m\n", line); - continue; - } - *equal = '\0'; - value = equal + 1; - if (setenv(name, value, 0) != 0) { - perror("[SubstAgent] setenv failed"); - } - } - free(line); - fclose(env_file); - } else { - if (errno != ENOENT) { - perror("[SubstAgent] fopen failed"); - exit(EXIT_FAILURE); - } + FILE *env_file = fopen(".env", "r"); + if (env_file) { + char *line = NULL; + size_t len = 0; + ssize_t n; + while ((n = getline(&line, &len, env_file)) != -1) { + if (n > 0 && line[n - 1] == '\n') { + line[n - 1] = '\0'; + } + if (line[0] == '#') { + continue; + } + char *name = line; + char *value = NULL; + char *equal = strchr(line, '='); + if (equal == NULL) { + fprintf(stderr, + "\e[0;31m[SubstAgent] Invalid line in .env: \"%s\"\e[0m\n", + line); + continue; + } + *equal = '\0'; + value = equal + 1; + if (setenv(name, value, 0) != 0) { + perror("[SubstAgent] setenv failed"); + } } + free(line); + fclose(env_file); + } else if (errno != ENOENT) { + perror("[SubstAgent] fopen failed"); + exit(EXIT_FAILURE); + } - fprintf(stderr, "[SubstAgent] Loaded version %s\n", GIT_HASH); + fprintf(stderr, "[SubstAgent] Loaded version %s\n", GIT_HASH); - return JNI_OK; + return JNI_OK; } -JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) { - return init_jvmti(vm); +JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved) { + return init_jvmti(vm); } -JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* vm, char* options, void* reserved) { - return init_jvmti(vm); +JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM *vm, char *options, + void *reserved) { + return init_jvmti(vm); } -JNIEXPORT void JNICALL Agent_OnUnload(JavaVM* vm) {} +JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm) {} diff --git a/src/utils.c b/src/utils.c index d3815a7..d2724a8 100644 --- a/src/utils.c +++ b/src/utils.c @@ -3,104 +3,121 @@ #include #include -jvmtiEnv* jvmti = NULL; +jvmtiEnv *jvmti = NULL; static const jlong TAG = 1; void tag(jobject obj) { - if (obj && jvmti) { - (*jvmti)->SetTag(jvmti, obj, TAG); - } + if (obj && jvmti) { + (*jvmti)->SetTag(jvmti, obj, TAG); + } } int has_tag(jobject obj) { - jlong tag = 0; - if (obj && jvmti) { - (*jvmti)->GetTag(jvmti, obj, &tag); - } - return tag == 1; + jlong tag = 0; + if (obj && jvmti) { + (*jvmti)->GetTag(jvmti, obj, &tag); + } + return tag == 1; } -int is_config_path(const char* path) { - char* extString = strrchr(path, '.'); - if (extString) { - return strcmp(extString, ".yml") == 0 || strcmp(extString, ".yaml") == 0 || strcmp(extString, ".json") == 0 || strcmp(extString, ".txt") == 0 || strcmp(extString, ".properties") == 0; - } - return 0; +int is_config_path(const char *path) { + char *extString = strrchr(path, '.'); + if (extString) { + return strcmp(extString, ".yml") == 0 || strcmp(extString, ".yaml") == 0 || + strcmp(extString, ".json") == 0 || strcmp(extString, ".txt") == 0 || + strcmp(extString, ".properties") == 0; + } + return 0; } -char* substitute(const char* value, int prefix_char_matched_index, size_t i, size_t value_len, size_t len_diff, const char *data) { - size_t data_len = strlen(data); - size_t new_len = data_len+len_diff; - char* new_data = malloc(new_len + 1); - size_t after_len = new_len - prefix_char_matched_index - value_len; - memcpy(new_data, data, prefix_char_matched_index); - memcpy(new_data+prefix_char_matched_index, value, value_len); - memcpy(new_data+prefix_char_matched_index+value_len, data+i, after_len); - assert(prefix_char_matched_index+value_len+after_len == new_len); - new_data[new_len] = '\0'; - return new_data; +char *substitute(const char *value, int prefix_char_matched_index, size_t i, + size_t value_len, size_t len_diff, const char *data) { + size_t data_len = strlen(data); + size_t new_len = data_len + len_diff; + char *new_data = malloc(new_len + 1); + size_t after_len = new_len - prefix_char_matched_index - value_len; + memcpy(new_data, data, prefix_char_matched_index); + memcpy(new_data + prefix_char_matched_index, value, value_len); + memcpy(new_data + prefix_char_matched_index + value_len, data + i, after_len); + assert(prefix_char_matched_index + value_len + after_len == new_len); + new_data[new_len] = '\0'; + return new_data; } -void parse_file(char **data_ptr, size_t fsize, const char* filename) { - char *data = *data_ptr; - int line_count = 1;; - int begin_env_index = -1; - char env_var[4096]; - env_var[0] = '\0'; - for (size_t i = 0; i < fsize; i++) { - char c = data[i]; - if (c == '\n') ++line_count; - if (begin_env_index != -1) { - if ((c >= 48 && c <= 57) || (c >= 65 && c <= 90) || (c >= 97 && c <= 122) || c == 95) { - size_t len = strlen(env_var); - env_var[len] = c; - env_var[len + 1] = '\0'; - } else if (c == '}') { - if (strlen(env_var) == 0) { - begin_env_index = -1; - env_var[0] = '\0'; - continue; - } - char* value = getenv(env_var); - if (!value) { - fprintf(stderr, "\033[0G\e[0;31m[SubstAgent] Failed to expand environment variable \"%s\" in file %s on line %d\e[0m\n", env_var, filename, line_count); - begin_env_index = -1; - env_var[0] = '\0'; - continue; - } - - // +1 for the closing } - size_t after_closing_tag_index = i + 1; - - size_t env_len = after_closing_tag_index - begin_env_index; - - size_t value_len = strlen(value); - ssize_t len_diff = value_len - env_len; - - char* new_data = substitute(value, begin_env_index, after_closing_tag_index, value_len, len_diff, data); - free(data); - data = new_data; - *data_ptr = new_data; - - fprintf(stderr, "\033[0G[SubstAgent] Successfully expanded environment variable \"%s\" in file %s on line %d\n", env_var, filename, line_count); - - fsize += len_diff; - i += len_diff; - begin_env_index = -1; - env_var[0] = '\0'; - continue; - } else { - fprintf(stderr, "\033[0G\e[0;31m[SubstAgent] Invalid environment variable in file %s on line %d\e[0m\n", filename, line_count); - begin_env_index = -1; - env_var[0] = '\0'; - } - } else { - if (c == '^') { - if (data[i+1] == '{') { - begin_env_index = i; - i++; - } - } +void parse_file(char **data_ptr, size_t fsize, const char *filename) { + char *data = *data_ptr; + int line_count = 1; + ; + int begin_env_index = -1; + char env_var[4096]; + env_var[0] = '\0'; + for (size_t i = 0; i < fsize; i++) { + char c = data[i]; + if (c == '\n') + ++line_count; + if (begin_env_index != -1) { + if ((c >= 48 && c <= 57) || (c >= 65 && c <= 90) || + (c >= 97 && c <= 122) || c == 95) { + size_t len = strlen(env_var); + env_var[len] = c; + env_var[len + 1] = '\0'; + } else if (c == '}') { + if (strlen(env_var) == 0) { + begin_env_index = -1; + env_var[0] = '\0'; + continue; } + char *value = getenv(env_var); + if (!value) { + fprintf(stderr, + "\033[0G\e[0;31m[SubstAgent] Failed to expand environment " + "variable \"%s\" in file %s on line %d\e[0m\n", + env_var, filename, line_count); + begin_env_index = -1; + env_var[0] = '\0'; + continue; + } + + // +1 for the closing } + size_t after_closing_tag_index = i + 1; + + size_t env_len = after_closing_tag_index - begin_env_index; + + size_t value_len = strlen(value); + ssize_t len_diff = value_len - env_len; + + char *new_data = + substitute(value, begin_env_index, after_closing_tag_index, + value_len, len_diff, data); + free(data); + data = new_data; + *data_ptr = new_data; + + fprintf(stderr, + "\033[0G[SubstAgent] Successfully expanded environment " + "variable \"%s\" in file %s on line %d\n", + env_var, filename, line_count); + + fsize += len_diff; + i += len_diff; + begin_env_index = -1; + env_var[0] = '\0'; + continue; + } else { + fprintf(stderr, + "\033[0G\e[0;31m[SubstAgent] Invalid environment variable in " + "file %s on line %d\e[0m\n", + filename, line_count); + begin_env_index = -1; + env_var[0] = '\0'; + } + } else { + if (c == '^') { + if (data[i + 1] == '{') { + begin_env_index = i; + i++; + } + } } + } } \ No newline at end of file diff --git a/src/utils.h b/src/utils.h index 9a3d5ed..6775e90 100644 --- a/src/utils.h +++ b/src/utils.h @@ -3,13 +3,14 @@ #include -extern jvmtiEnv* jvmti; +extern jvmtiEnv *jvmti; void tag(jobject obj); int has_tag(jobject obj); -int is_config_path(const char* path); -char* substitute(const char* value, int dollar_sign_matched_index, size_t i, size_t value_len, size_t len_diff, const char *data); -void parse_file(char **data_ptr, size_t fsize, const char* filename); +int is_config_path(const char *path); +char *substitute(const char *value, int dollar_sign_matched_index, size_t i, + size_t value_len, size_t len_diff, const char *data); +void parse_file(char **data_ptr, size_t fsize, const char *filename); #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MAX(a, b) ((a) < (b) ? (b) : (a)) -- 2.47.3