From 268c89cac7855447c62918bd52131f779ef29e05 Mon Sep 17 00:00:00 2001 From: Yonggang Luo Date: Tue, 10 Dec 2024 09:00:05 +0000 Subject: [PATCH] Implement jerry_port_path_normalize in a more reliable way Replace jerry_port_path_normalize,jerry_port_path_free,jerry_port_path_base with jerry_port_path_style,jerry_port_get_cwd Partially fixes https://github.com/jerryscript-project/jerryscript/issues/4979 Closes: https://github.com/jerryscript-project/jerryscript/issues/4983 JerryScript-DCO-1.0-Signed-off-by: Yonggang Luo luoyonggang@gmail.com --- docs/05.PORT-API.md | 49 +- jerry-core/api/jerry-module.c | 578 +++++++++++++++++++- jerry-core/include/jerryscript-port.h | 56 +- jerry-ext/include/jerryscript-ext/sources.h | 8 +- jerry-ext/util/sources.c | 22 +- jerry-main/main-desktop.c | 9 +- jerry-port/common/jerry-port-fs.c | 67 +-- jerry-port/unix/jerry-port-unix-fs.c | 75 ++- jerry-port/win/jerry-port-win-fs.c | 71 ++- 9 files changed, 721 insertions(+), 214 deletions(-) diff --git a/docs/05.PORT-API.md b/docs/05.PORT-API.md index 015bbb6f0c..59963693a5 100644 --- a/docs/05.PORT-API.md +++ b/docs/05.PORT-API.md @@ -173,52 +173,33 @@ void jerry_port_line_free (jerry_char_t *buffer_p); ## Filesystem -``` -/** - * Canonicalize a file path. - * - * If possible, the implementation should resolve symbolic links and other directory references found in the input path, - * and create a fully canonicalized file path as the result. - * - * The function may return with NULL in case an error is encountered, in which case the calling operation will not - * proceed. - * - * The implementation should allocate storage for the result path as necessary. Non-NULL return values will be passed - * to `jerry_port_path_free` when the result is no longer needed by the caller, which can be used to finalize - * dynamically allocated buffers. - * - * NOTE: The implementation must not return directly with the input, as the input buffer is released after the call. - * - * @param path_p: zero-terminated string containing the input path - * @param path_size: size of the input path string in bytes, excluding terminating zero - * - * @return buffer with the normalized path if the operation is successful, - * NULL otherwise - */ -jerry_char_t *jerry_port_path_normalize (const jerry_char_t *path_p, jerry_size_t path_size); -``` - ```c /** - * Free a path buffer returned by jerry_port_path_normalize. + * Get the path style of the current OS * - * @param path_p: the path buffer to free + * @return path style */ -void jerry_port_path_free (jerry_char_t *path_p); +jerry_path_style_t jerry_port_path_style (void); ``` ```c /** - * Get the offset of the basename component in the input path. + * Get the cwd, the output string will be zero-terminated * - * The implementation should return the offset of the first character after the last path separator found in the path. - * This is used by the caller to split the path into a directory name and a file name. + * @param buffer_p: the buffer to storage the cwd + * @param buffer_size: the `buffer_p` buffer size, including '\0` terminator * - * @param path_p: input zero-terminated path string + * @note + * - cwd: current working directory * - * @return offset of the basename component in the input path + * @return The length of cwd, excluding '\0' terminator + * - When buffer_p is `NULL` and get cwd succeed return length of cwd + * - When buffer_p is `NULL` and get cwd failed return 0 + * - When buffer_p is not `NULL` and the `buffer_size - 1` just equal to + * length of cwd; and get cwd succeed return `buffer_size - 1`. + * - Otherwise means get cwd failed and return 0 */ -jerry_size_t jerry_port_path_base (const jerry_char_t *path_p); +jerry_size_t jerry_port_get_cwd (jerry_char_t *buffer_p, jerry_size_t buffer_size); ``` ```c diff --git a/jerry-core/api/jerry-module.c b/jerry-core/api/jerry-module.c index 964686990f..cd0abc02df 100644 --- a/jerry-core/api/jerry-module.c +++ b/jerry-core/api/jerry-module.c @@ -30,6 +30,7 @@ typedef struct jerry_module_t { struct jerry_module_t *next_p; /**< next_module */ jerry_char_t *path_p; /**< path to the module */ + jerry_size_t path_size; /**< size of path to the module, excluding '\0' terminator */ jerry_size_t basename_offset; /**< offset of the basename in the module path*/ jerry_value_t realm; /**< the realm of the module */ jerry_value_t module; /**< the module itself */ @@ -50,6 +51,555 @@ typedef struct jerry_module_t *module_head_p; /**< first module */ } jerry_module_manager_t; +typedef enum +{ + JERRY_PATH_JOIN_ITERATOR_STATE_ONE_DOT, + JERRY_PATH_JOIN_ITERATOR_STATE_TWO_DOT, + JERRY_PATH_JOIN_ITERATOR_STATE_SEPARATOR, + JERRY_PATH_JOIN_ITERATOR_STATE_SEGMENT, + JERRY_PATH_JOIN_ITERATOR_STATE_ROOT, +} jerry_path_iterator_state_t; + +typedef struct +{ + jerry_path_style_t style; + jerry_char_t *buffer_p; + jerry_size_t buffer_size; + jerry_size_t buffer_size_expected; + jerry_size_t buffer_index; + jerry_size_t buffer_index_init; + jerry_size_t segment_length; + + const jerry_string_t *path_list_p; + jerry_size_t path_list_count; + jerry_size_t path_total_size; + + jerry_size_t segment_eat_count; + jerry_path_iterator_state_t iterator_state; + bool only_first_path_is_root; +} jerry_path_join_state_t; + +typedef struct +{ + int32_t list_pos; + jerry_size_t item_pos; + jerry_size_t root_length; +} jerry_path_iterator_t; + +static bool +jerry_module_path_is_separator (jerry_path_style_t style, const jerry_char_t ch) +{ + if (style == JERRY_PATH_STYLE_WINDOWS) + { + return ch == '/' || ch == '\\'; + } + else + { + return ch == '/'; + } +} /* jerry_module_path_is_separator */ + +static const jerry_char_t * +jerry_module_path_find_next_stop (jerry_path_style_t path_style, const jerry_char_t *c) +{ + // We just move forward until we find a '\0' or a separator, which will be our + // next "stop". + while (*c != '\0' && !jerry_module_path_is_separator (path_style, *c)) + { + ++c; + } + + // Return the pointer of the next stop. + return c; +} /* jerry_module_path_find_next_stop */ + +static void +jerry_module_path_get_root_windows (const jerry_char_t *path, jerry_size_t *length) +{ + const jerry_char_t *c; + + // We can not determine the root if this is an empty string. So we set the + // root to NULL and the length to zero and cancel the whole thing. + c = path; + *length = 0; + if (!*c) + { + return; + } + + // Now we have to verify whether this is a windows network path (UNC), which + // we will consider our root. + if (jerry_module_path_is_separator (JERRY_PATH_STYLE_WINDOWS, *c)) + { + bool is_device_path; + ++c; + + // Check whether the path starts with a single backslash, which means this + // is not a network path - just a normal path starting with a backslash. + if (!jerry_module_path_is_separator (JERRY_PATH_STYLE_WINDOWS, *c)) + { + // Okay, this is not a network path but we still use the backslash as a + // root. + ++(*length); + return; + } + + // A device path is a path which starts with "\\." or "\\?". A device path + // can be a UNC path as well, in which case it will take up one more + // segment. So, this is a network or device path. Skip the previous + // separator. Now we need to determine whether this is a device path. We + // might advance one character here if the server name starts with a '?' or + // a '.', but that's fine since we will search for a separator afterwards + // anyway. + ++c; + is_device_path = (*c == '?' || *c == '.') && jerry_module_path_is_separator (JERRY_PATH_STYLE_WINDOWS, *(++c)); + if (is_device_path) + { + // That's a device path, and the root must be either "\\.\" or "\\?\" + // which is 4 characters long. (at least that's how Windows + // GetFullPathName behaves.) + *length = 4; + return; + } + + // We will grab anything up to the next stop. The next stop might be a '\0' + // or another separator. That will be the server name. + c = jerry_module_path_find_next_stop (JERRY_PATH_STYLE_WINDOWS, c); + + // If this is a separator and not the end of a string we wil have to include + // it. However, if this is a '\0' we must not skip it. + while (jerry_module_path_is_separator (JERRY_PATH_STYLE_WINDOWS, *c)) + { + ++c; + } + + // We are now skipping the shared folder name, which will end after the + // next stop. + c = jerry_module_path_find_next_stop (JERRY_PATH_STYLE_WINDOWS, c); + + // Then there might be a separator at the end. We will include that as well, + // it will mark the path as absolute. + if (jerry_module_path_is_separator (JERRY_PATH_STYLE_WINDOWS, *c)) + { + ++c; + } + + // Finally, calculate the size of the root. + *length = (jerry_size_t) (c - path); + return; + } + + // Move to the next and check whether this is a colon. + if (*++c == ':') + { + *length = 2; + + // Now check whether this is a backslash (or slash). If it is not, we could + // assume that the next character is a '\0' if it is a valid path. However, + // we will not assume that - since ':' is not valid in a path it must be a + // mistake by the caller than. We will try to understand it anyway. + if (jerry_module_path_is_separator (JERRY_PATH_STYLE_WINDOWS, *(++c))) + { + *length = 3; + } + } +} /* jerry_module_path_get_root_windows */ + +static void +jerry_module_path_get_root_unix (const jerry_char_t *path, jerry_size_t *length) +{ + // The slash of the unix path represents the root. There is no root if there + // is no slash. + if (jerry_module_path_is_separator (JERRY_PATH_STYLE_POSIX, *path)) + { + *length = 1; + } + else + { + *length = 0; + } +} /* jerry_module_path_get_root_unix */ + +static void +jerry_module_path_get_root (jerry_path_style_t path_style, const jerry_char_t *path, jerry_size_t *length) +{ + // We use a different implementation here based on the configuration of the + // library. + if (path_style == JERRY_PATH_STYLE_WINDOWS) + { + jerry_module_path_get_root_windows (path, length); + } + else + { + jerry_module_path_get_root_unix (path, length); + } +} /* jerry_module_path_get_root */ + +static jerry_char_t +jerry_module_path_get_char (jerry_path_join_state_t *state, jerry_path_iterator_t *it) +{ + if (it->list_pos < 0) + { + return 0; + } + if (it->item_pos == state->path_list_p[it->list_pos].size) + { + return '/'; + } + return state->path_list_p[it->list_pos].ptr[it->item_pos]; +} /* jerry_module_path_get_char */ + +static void +jerry_module_path_update_root_length (jerry_path_join_state_t *state, jerry_path_iterator_t *it) +{ + state->path_total_size += state->path_list_p[it->list_pos].size; + if (!state->only_first_path_is_root || it->list_pos == 0) + { + jerry_module_path_get_root (state->style, state->path_list_p[it->list_pos].ptr, &it->root_length); + } +} /* jerry_module_path_update_root_length */ + +static void +jerry_module_path_interator_prev (jerry_path_join_state_t *state, jerry_path_iterator_t *it) +{ + if (it->list_pos < 0) + { + return; + } + if (it->item_pos > 0) + { + --it->item_pos; + return; + } + if (it->root_length > 0) + { + it->list_pos = -1; + return; + } + it->list_pos -= 1; + if (it->list_pos >= 0) + { + jerry_module_path_update_root_length (state, it); + /** + * The tail '\0' treat as '/' that is a path separator for both + * POSIX/WINDOWS + */ + it->item_pos = state->path_list_p[it->list_pos].size; + } +} /* jerry_module_path_interator_prev */ + +static void +jerry_module_path_push_front_direct (jerry_path_join_state_t *state, jerry_char_t ch) +{ + --state->buffer_index; + if (state->buffer_p) + { + if (state->buffer_index < state->buffer_size) + { + state->buffer_p[state->buffer_index] = ch; + } + } +} /* jerry_module_path_push_front_direct */ + +static void +jerry_module_path_push_front (jerry_path_join_state_t *state, jerry_char_t ch) +{ + jerry_module_path_push_front_direct (state, ch); + if (jerry_module_path_is_separator (state->style, ch)) + { + state->segment_length = 0; + } + else + { + state->segment_length += 1; + } +} /* jerry_module_path_push_front */ + +static jerry_char_t +jerry_module_path_get_separator (jerry_path_style_t path_style) +{ + return path_style == JERRY_PATH_STYLE_POSIX ? '/' : '\\'; +} /* jerry_module_path_get_separator */ + +static jerry_size_t +jerry_module_path_join_and_normalize (jerry_path_style_t style, + bool only_first_path_is_root, + const jerry_string_t *path_list_p, + jerry_size_t path_list_count, + jerry_char_t *buffer_p, + jerry_size_t buffer_size, + jerry_size_t buffer_size_expected) +{ + jerry_path_join_state_t state = { 0 }; + state.style = style; + state.only_first_path_is_root = only_first_path_is_root; + state.buffer_p = buffer_p; + state.buffer_size = buffer_size; + state.buffer_size_expected = buffer_size_expected; + if (buffer_p) + { + if (buffer_size_expected > buffer_size) + { + /** + * When `buffer_p` exist and `buffer_size_expected` > `buffer_size` that + * means there is not enough buffer to storage the final generated path + * so set buffer_index_init to buffer_size_expected to ensure only the + * heading part of the generated part are stroaged into `buffer_p` + */ + state.buffer_index_init = buffer_size_expected; + } + else + { + /** + * Always storage at the tail of `buffer_p`. So that when normalize the + * path inplace, the path own't be corrupted. + */ + state.buffer_index_init = buffer_size; + } + } + else + { + /* For calculating the path size */ + state.buffer_index_init = UINT32_MAX; + } + state.buffer_index = state.buffer_index_init; + state.path_list_p = path_list_p; + state.path_list_count = path_list_count; + state.iterator_state = JERRY_PATH_JOIN_ITERATOR_STATE_SEPARATOR; + + jerry_size_t path_list_tail_pos = path_list_count - 1; + jerry_path_iterator_t it = { (int32_t) path_list_tail_pos, path_list_p[path_list_tail_pos].size, 0 }; + jerry_module_path_update_root_length (&state, &it); + jerry_module_path_push_front_direct (&state, '\0'); + for (;;) + { + jerry_char_t ch = jerry_module_path_get_char (&state, &it); + if (ch == 0) + { + break; + } + switch (state.iterator_state) + { + case JERRY_PATH_JOIN_ITERATOR_STATE_ROOT: + { + jerry_module_path_push_front_direct (&state, ch); + state.segment_length += 1; + break; + } + case JERRY_PATH_JOIN_ITERATOR_STATE_SEPARATOR: + { + if (ch == '.') + { + state.iterator_state = JERRY_PATH_JOIN_ITERATOR_STATE_ONE_DOT; + } + else if (!jerry_module_path_is_separator (style, ch)) + { + state.iterator_state = JERRY_PATH_JOIN_ITERATOR_STATE_SEGMENT; + jerry_module_path_push_front (&state, ch); + } + break; + } + case JERRY_PATH_JOIN_ITERATOR_STATE_ONE_DOT: + { + if (ch == '.') + { + state.iterator_state = JERRY_PATH_JOIN_ITERATOR_STATE_TWO_DOT; + } + else if (jerry_module_path_is_separator (style, ch)) + { + state.iterator_state = JERRY_PATH_JOIN_ITERATOR_STATE_SEPARATOR; + } + else + { + jerry_module_path_push_front (&state, '.'); + jerry_module_path_push_front (&state, ch); + state.iterator_state = JERRY_PATH_JOIN_ITERATOR_STATE_SEGMENT; + } + break; + } + case JERRY_PATH_JOIN_ITERATOR_STATE_TWO_DOT: + { + if (jerry_module_path_is_separator (style, ch)) + { + state.segment_eat_count += 1; + state.iterator_state = JERRY_PATH_JOIN_ITERATOR_STATE_SEPARATOR; + } + else + { + jerry_module_path_push_front (&state, ch); + state.iterator_state = JERRY_PATH_JOIN_ITERATOR_STATE_SEGMENT; + } + break; + } + case JERRY_PATH_JOIN_ITERATOR_STATE_SEGMENT: + { + if (jerry_module_path_is_separator (style, ch)) + { + if (state.segment_eat_count > 0) + { + state.segment_eat_count -= 1; + state.buffer_index += state.segment_length; + state.segment_length = 0; + } + else + { + jerry_module_path_push_front (&state, jerry_module_path_get_separator (style)); + } + state.iterator_state = JERRY_PATH_JOIN_ITERATOR_STATE_SEPARATOR; + } + else + { + jerry_module_path_push_front (&state, ch); + } + break; + } + } + + if (it.item_pos < it.root_length) + { + state.iterator_state = JERRY_PATH_JOIN_ITERATOR_STATE_ROOT; + if (it.root_length == 1 && (state.buffer_index_init - state.buffer_index) == 1) + { + jerry_module_path_push_front (&state, jerry_module_path_get_separator (style)); + } + } + jerry_module_path_interator_prev (&state, &it); + } + if (state.iterator_state != JERRY_PATH_JOIN_ITERATOR_STATE_ROOT) + { + if (state.segment_eat_count > 0 && state.segment_length > 0) + { + state.segment_eat_count -= 1; + state.buffer_index += state.segment_length; + state.segment_length = 0; + if (state.buffer_index_init - state.buffer_index > 1) + { + /* Strip the starting path separator `/` or `\` */ + state.buffer_index += 1; + } + } + + if (state.buffer_index_init - state.buffer_index == 1) + { + if (state.segment_eat_count == 0) + { + if (state.path_total_size > 0) + { + jerry_module_path_push_front (&state, '.'); + } + } + else + { + for (jerry_size_t i = 0; i < state.segment_eat_count; i += 1) + { + jerry_module_path_push_front (&state, '.'); + jerry_module_path_push_front (&state, '.'); + if (i < state.segment_eat_count - 1) + { + jerry_module_path_push_front (&state, '/'); + } + } + } + } + } + jerry_size_t path_size = state.buffer_index_init - state.buffer_index; + if (state.buffer_p) + { + if (state.buffer_index > 0) + { + memmove (buffer_p, buffer_p + state.buffer_index, path_size); + } + else + { + if (buffer_size > 0 && buffer_size < path_size) + { + buffer_p[buffer_size - 1] = '\0'; + } + } + } + return path_size - 1; +} /* jerry_module_path_join_and_normalize */ + +/** + * Get the end of the directory part of the input path. + * + * @param path_p: input zero-terminated path string + * + * @return offset of the directory end in the input path string + */ +static jerry_size_t +jerry_module_path_base (jerry_path_style_t style, const jerry_char_t *path_p, jerry_size_t path_size) +{ + const jerry_char_t *end_p = path_p + path_size; + + while (end_p > path_p) + { + if (jerry_module_path_is_separator (style, *(end_p - 1))) + { + return (jerry_size_t) (end_p - path_p); + } + + end_p--; + } + + return 0; +} /* jerry_module_path_base */ + +static jerry_size_t +jerry_module_get_cwd (jerry_char_t **path_p) +{ + jerry_char_t *buffer_p = NULL; + jerry_size_t path_size = jerry_port_get_cwd (NULL, 0); + if (path_size > 0) + { + jerry_size_t buffer_size = path_size + 1; + buffer_p = jerry_heap_alloc (buffer_size); + if (buffer_p) + { + if (jerry_port_get_cwd (buffer_p, buffer_size) != path_size) + { + jerry_heap_free (buffer_p, buffer_size); + buffer_p = NULL; + } + } + } + *path_p = buffer_p; + return path_size; +} /* jerry_module_get_cwd */ + +static jerry_size_t +jerry_module_path_join_allocated (jerry_path_style_t style, + const jerry_string_t *path_list_p, + jerry_size_t path_list_count, + jerry_char_t **path_out_p) +{ + jerry_char_t *buffer_p = NULL; + jerry_size_t path_size = + jerry_module_path_join_and_normalize (style, false, path_list_p, path_list_count, NULL, 0, 0); + if (path_size > 0) + { + jerry_size_t buffer_size = path_size + 1; + buffer_p = jerry_heap_alloc (buffer_size); + if (buffer_p) + { + if (jerry_module_path_join_and_normalize (style, + false, + path_list_p, + path_list_count, + buffer_p, + buffer_size, + buffer_size) + != path_size) + { + jerry_heap_free (buffer_p, buffer_size); + buffer_p = NULL; + } + } + } + *path_out_p = buffer_p; + return path_size; +} /* jerry_module_path_join_allocated */ + /** * Release known modules. */ @@ -70,7 +620,7 @@ jerry_module_free (jerry_module_manager_t *manager_p, /**< module manager */ if (release_all || module_p->realm == realm) { - jerry_port_path_free (module_p->path_p); + jerry_heap_free (module_p->path_p, module_p->path_size + 1); jerry_value_free (module_p->realm); jerry_value_free (module_p->module); @@ -157,7 +707,19 @@ jerry_module_resolve (const jerry_value_t specifier, /**< module specifier strin jerry_string_to_buffer (specifier, JERRY_ENCODING_UTF8, reference_path_p + directory_size, specifier_size); reference_path_p[reference_size] = '\0'; - jerry_char_t *path_p = jerry_port_path_normalize (reference_path_p, reference_size); + jerry_char_t *path_p = NULL; + jerry_size_t path_size = 0; + jerry_path_style_t path_style = jerry_port_path_style (); + jerry_char_t *cwd_path_p = NULL; + jerry_size_t cwd_path_size = jerry_module_get_cwd (&cwd_path_p); + if (cwd_path_p) + { + jerry_string_t path_list[] = { { cwd_path_p, cwd_path_size }, { reference_path_p, reference_size } }; + path_size = + jerry_module_path_join_allocated (path_style, path_list, sizeof (path_list) / sizeof (path_list[0]), &path_p); + jerry_heap_free (cwd_path_p, cwd_path_size + 1); + } + jerry_heap_free (reference_path_p, reference_size + 1); if (path_p == NULL) @@ -174,10 +736,11 @@ jerry_module_resolve (const jerry_value_t specifier, /**< module specifier strin while (module_p != NULL) { - if (module_p->realm == realm && strcmp ((const char *) module_p->path_p, (const char *) path_p) == 0) + if (module_p->realm == realm && module_p->path_size == path_size + && memcmp (module_p->path_p, path_p, path_size) == 0) { jerry_value_free (realm); - jerry_port_path_free (path_p); + jerry_heap_free (path_p, path_size + 1); return jerry_value_copy (module_p->module); } @@ -190,7 +753,7 @@ jerry_module_resolve (const jerry_value_t specifier, /**< module specifier strin if (source_p == NULL) { jerry_value_free (realm); - jerry_port_path_free (path_p); + jerry_heap_free (path_p, path_size + 1); return jerry_throw_sz (JERRY_ERROR_SYNTAX, jerry_string_sz ("Module file not found")); } @@ -206,7 +769,7 @@ jerry_module_resolve (const jerry_value_t specifier, /**< module specifier strin if (jerry_value_is_exception (ret_value)) { - jerry_port_path_free (path_p); + jerry_heap_free (path_p, path_size + 1); jerry_value_free (realm); return ret_value; } @@ -215,7 +778,8 @@ jerry_module_resolve (const jerry_value_t specifier, /**< module specifier strin module_p->next_p = manager_p->module_head_p; module_p->path_p = path_p; - module_p->basename_offset = jerry_port_path_base (module_p->path_p); + module_p->path_size = path_size; + module_p->basename_offset = jerry_module_path_base (path_style, module_p->path_p, module_p->path_size); module_p->realm = realm; module_p->module = jerry_value_copy (ret_value); diff --git a/jerry-core/include/jerryscript-port.h b/jerry-core/include/jerryscript-port.h index bbff4cf774..d2d31b2c32 100644 --- a/jerry-core/include/jerryscript-port.h +++ b/jerry-core/include/jerryscript-port.h @@ -37,6 +37,15 @@ JERRY_C_API_BEGIN * @{ */ +/** + * The path style of the OS + */ +typedef enum +{ + JERRY_PATH_STYLE_WINDOWS, + JERRY_PATH_STYLE_POSIX, +} jerry_path_style_t; + /** * Error codes that can be passed by the engine when calling jerry_port_fatal */ @@ -198,46 +207,29 @@ void jerry_port_line_free (jerry_char_t *buffer_p); */ /** - * Canonicalize a file path. - * - * If possible, the implementation should resolve symbolic links and other directory references found in the input path, - * and create a fully canonicalized file path as the result. - * - * The function may return with NULL in case an error is encountered, in which case the calling operation will not - * proceed. - * - * The implementation should allocate storage for the result path as necessary. Non-NULL return values will be passed - * to `jerry_port_path_free` when the result is no longer needed by the caller, which can be used to finalize - * dynamically allocated buffers. - * - * NOTE: The implementation must not return directly with the input, as the input buffer is released after the call. - * - * @param path_p: zero-terminated string containing the input path - * @param path_size: size of the input path string in bytes, excluding terminating zero - * - * @return buffer with the normalized path if the operation is successful, - * NULL otherwise - */ -jerry_char_t *jerry_port_path_normalize (const jerry_char_t *path_p, jerry_size_t path_size); - -/** - * Free a path buffer returned by jerry_port_path_normalize. + * Get the path style of the current OS * - * @param path_p: the path buffer to free + * @return path style */ -void jerry_port_path_free (jerry_char_t *path_p); +jerry_path_style_t jerry_port_path_style (void); /** - * Get the offset of the basename component in the input path. + * Get the cwd, the output string will be zero-terminated * - * The implementation should return the offset of the first character after the last path separator found in the path. - * This is used by the caller to split the path into a directory name and a file name. + * @param buffer_p: the buffer to storage the cwd + * @param buffer_size: the `buffer_p` buffer size, including '\0` terminator * - * @param path_p: input zero-terminated path string + * @note + * - cwd: current working directory * - * @return offset of the basename component in the input path + * @return The length of cwd, excluding '\0' terminator + * - When buffer_p is `NULL` and get cwd succeed return length of cwd + * - When buffer_p is `NULL` and get cwd failed return 0 + * - When buffer_p is not `NULL` and the `buffer_size - 1` just equal to + * length of cwd; and get cwd succeed return `buffer_size - 1`. + * - Otherwise means get cwd failed and return 0 */ -jerry_size_t jerry_port_path_base (const jerry_char_t *path_p); +jerry_size_t jerry_port_get_cwd (jerry_char_t *buffer_p, jerry_size_t buffer_size); /** * Open a source file and read the content into a buffer. diff --git a/jerry-ext/include/jerryscript-ext/sources.h b/jerry-ext/include/jerryscript-ext/sources.h index e33aa6b9a6..add84b5523 100644 --- a/jerry-ext/include/jerryscript-ext/sources.h +++ b/jerry-ext/include/jerryscript-ext/sources.h @@ -20,10 +20,10 @@ JERRY_C_API_BEGIN -jerry_value_t jerryx_source_parse_script (const char* path); -jerry_value_t jerryx_source_exec_script (const char* path); -jerry_value_t jerryx_source_exec_module (const char* path); -jerry_value_t jerryx_source_exec_snapshot (const char* path, size_t function_index); +jerry_value_t jerryx_source_parse_script (const jerry_string_t *path); +jerry_value_t jerryx_source_exec_script (const jerry_string_t *path); +jerry_value_t jerryx_source_exec_module (const jerry_string_t *path); +jerry_value_t jerryx_source_exec_snapshot (const jerry_string_t *path, size_t function_index); jerry_value_t jerryx_source_exec_stdin (void); JERRY_C_API_END diff --git a/jerry-ext/util/sources.c b/jerry-ext/util/sources.c index 99a3e71068..4f3d768d64 100644 --- a/jerry-ext/util/sources.c +++ b/jerry-ext/util/sources.c @@ -27,14 +27,14 @@ #include "jerryscript-ext/print.h" jerry_value_t -jerryx_source_parse_script (const char *path_p) +jerryx_source_parse_script (const jerry_string_t *path_p) { jerry_size_t source_size; - jerry_char_t *source_p = jerry_port_source_read (path_p, &source_size); + jerry_char_t *source_p = jerry_port_source_read ((const char *) path_p->ptr, &source_size); if (source_p == NULL) { - jerry_log (JERRY_LOG_LEVEL_ERROR, "Failed to open file: %s\n", path_p); + jerry_log (JERRY_LOG_LEVEL_ERROR, "Failed to open file: %.*s\n", (int) path_p->size, path_p->ptr); return jerry_throw_sz (JERRY_ERROR_SYNTAX, jerry_string_sz ("Source file not found")); } @@ -46,8 +46,7 @@ jerryx_source_parse_script (const char *path_p) jerry_parse_options_t parse_options; parse_options.options = JERRY_PARSE_HAS_SOURCE_NAME; - parse_options.source_name = - jerry_string ((const jerry_char_t *) path_p, (jerry_size_t) strlen (path_p), JERRY_ENCODING_UTF8); + parse_options.source_name = jerry_string (path_p->ptr, path_p->size, JERRY_ENCODING_UTF8); jerry_value_t result = jerry_parse (source_p, source_size, &parse_options); @@ -58,7 +57,7 @@ jerryx_source_parse_script (const char *path_p) } /* jerryx_source_parse_script */ jerry_value_t -jerryx_source_exec_script (const char *path_p) +jerryx_source_exec_script (const jerry_string_t *path_p) { jerry_value_t result = jerryx_source_parse_script (path_p); @@ -73,10 +72,9 @@ jerryx_source_exec_script (const char *path_p) } /* jerryx_source_exec_script */ jerry_value_t -jerryx_source_exec_module (const char *path_p) +jerryx_source_exec_module (const jerry_string_t *path_p) { - jerry_value_t specifier = - jerry_string ((const jerry_char_t *) path_p, (jerry_size_t) strlen (path_p), JERRY_ENCODING_UTF8); + jerry_value_t specifier = jerry_string (path_p->ptr, path_p->size, JERRY_ENCODING_UTF8); jerry_value_t referrer = jerry_undefined (); jerry_value_t module = jerry_module_resolve (specifier, referrer, NULL); @@ -110,14 +108,14 @@ jerryx_source_exec_module (const char *path_p) } /* jerryx_source_exec_module */ jerry_value_t -jerryx_source_exec_snapshot (const char *path_p, size_t function_index) +jerryx_source_exec_snapshot (const jerry_string_t *path_p, size_t function_index) { jerry_size_t source_size; - jerry_char_t *source_p = jerry_port_source_read (path_p, &source_size); + jerry_char_t *source_p = jerry_port_source_read ((const char *) path_p->ptr, &source_size); if (source_p == NULL) { - jerry_log (JERRY_LOG_LEVEL_ERROR, "Failed to open file: %s\n", path_p); + jerry_log (JERRY_LOG_LEVEL_ERROR, "Failed to open file: %.*s\n", (int) path_p->size, path_p->ptr); return jerry_throw_sz (JERRY_ERROR_SYNTAX, jerry_string_sz ("Snapshot file not found")); } diff --git a/jerry-main/main-desktop.c b/jerry-main/main-desktop.c index cfe771b98b..d07214a999 100644 --- a/jerry-main/main-desktop.c +++ b/jerry-main/main-desktop.c @@ -130,17 +130,18 @@ main (int argc, char **argv) { main_source_t *source_file_p = sources_p + source_index; const char *file_path_p = argv[source_file_p->path_index]; + jerry_string_t file_path = { (const jerry_char_t *) file_path_p, (jerry_size_t) strlen (file_path_p) }; switch (source_file_p->type) { case SOURCE_MODULE: { - result = jerryx_source_exec_module (file_path_p); + result = jerryx_source_exec_module (&file_path); break; } case SOURCE_SNAPSHOT: { - result = jerryx_source_exec_snapshot (file_path_p, source_file_p->snapshot_index); + result = jerryx_source_exec_snapshot (&file_path, source_file_p->snapshot_index); break; } default: @@ -149,11 +150,11 @@ main (int argc, char **argv) if ((arguments.option_flags & OPT_FLAG_PARSE_ONLY) != 0) { - result = jerryx_source_parse_script (file_path_p); + result = jerryx_source_parse_script (&file_path); } else { - result = jerryx_source_exec_script (file_path_p); + result = jerryx_source_exec_script (&file_path); } break; diff --git a/jerry-port/common/jerry-port-fs.c b/jerry-port/common/jerry-port-fs.c index 549121b7c7..b5138da646 100644 --- a/jerry-port/common/jerry-port-fs.c +++ b/jerry-port/common/jerry-port-fs.c @@ -25,7 +25,7 @@ #ifndef S_ISDIR #define S_ISDIR(mode) (((mode) &S_IFMT) == S_IFDIR) #endif /* !defined(S_ISDIR) */ -#endif /* __GLIBC__ */ +#endif /* defined(__GLIBC__) || defined(_WIN32) */ /** * Determines the size of the given file. @@ -59,7 +59,7 @@ jerry_port_source_read (const char *file_name_p, /**< file name */ { return NULL; } -#endif /* __GLIBC__ */ +#endif /* defined(__GLIBC__) || defined(_WIN32) */ FILE *file_p = fopen (file_name_p, "rb"); @@ -101,6 +101,16 @@ jerry_port_source_free (uint8_t *buffer_p) /**< buffer to free */ free (buffer_p); } /* jerry_port_source_free */ +#if !defined(_WIN32) + +jerry_path_style_t +jerry_port_path_style (void) +{ + return JERRY_PATH_STYLE_POSIX; +} /* jerry_port_path_style */ + +#endif /* !defined(_WIN32) */ + /** * These functions provide generic implementation for paths and are only enabled when the compiler support weak symbols, * and we are not building for a platform that has platform specific versions. @@ -108,55 +118,22 @@ jerry_port_source_free (uint8_t *buffer_p) /**< buffer to free */ #if !(defined(__unix__) || defined(__APPLE__) || defined(_WIN32)) /** - * Normalize a file path. - * - * @return a newly allocated buffer with the normalized path if the operation is successful, - * NULL otherwise + * Default to `/` */ -jerry_char_t *JERRY_ATTR_WEAK -jerry_port_path_normalize (const jerry_char_t *path_p, /**< input path */ - jerry_size_t path_size) /**< size of the path */ +jerry_size_t JERRY_ATTR_WEAK +jerry_port_get_cwd (jerry_char_t *buffer_p, jerry_size_t buffer_size) { - jerry_char_t *buffer_p = (jerry_char_t *) malloc (path_size + 1); - if (buffer_p == NULL) { - return NULL; + return 1; } - - /* Also copy terminating zero byte. */ - memcpy (buffer_p, path_p, path_size + 1); - - return buffer_p; -} /* jerry_port_path_normalize */ - -/** - * Free a path buffer returned by jerry_port_path_normalize. - * - * @param path_p: the path to free - */ -void JERRY_ATTR_WEAK -jerry_port_path_free (jerry_char_t *path_p) -{ - free (path_p); -} /* jerry_port_path_free */ - -/** - * Computes the end of the directory part of a path. - * - * @return end of the directory part of a path. - */ -jerry_size_t JERRY_ATTR_WEAK -jerry_port_path_base (const jerry_char_t *path_p) /**< path */ -{ - const jerry_char_t *basename_p = (jerry_char_t *) strrchr ((char *) path_p, '/') + 1; - - if (basename_p == NULL) + if (buffer_size == 2) { - return 0; + buffer_p[0] = '/'; + buffer_p[1] = '\0'; + return 1; } - - return (jerry_size_t) (basename_p - path_p); -} /* jerry_port_get_directory_end */ + return 0; +} /* jerry_port_get_cwd */ #endif /* !(defined(__unix__) || defined(__APPLE__) || defined(_WIN32)) */ diff --git a/jerry-port/unix/jerry-port-unix-fs.c b/jerry-port/unix/jerry-port-unix-fs.c index d610a7e290..354dd22ab9 100644 --- a/jerry-port/unix/jerry-port-unix-fs.c +++ b/jerry-port/unix/jerry-port-unix-fs.c @@ -17,47 +17,46 @@ #if defined(__unix__) || defined(__APPLE__) +#include #include #include +#include -/** - * Normalize a file path using realpath. - * - * @param path_p: input path - * @param path_size: input path size - * - * @return a newly allocated buffer with the normalized path if the operation is successful, - * NULL otherwise - */ -jerry_char_t * -jerry_port_path_normalize (const jerry_char_t *path_p, /**< input path */ - jerry_size_t path_size) /**< size of the path */ -{ - (void) path_size; - - return (jerry_char_t *) realpath ((char *) path_p, NULL); -} /* jerry_port_path_normalize */ - -/** - * Free a path buffer returned by jerry_port_path_normalize. - */ -void -jerry_port_path_free (jerry_char_t *path_p) -{ - free (path_p); -} /* jerry_port_path_free */ - -/** - * Computes the end of the directory part of a path. - * - * @return end of the directory part of a path. - */ -jerry_size_t JERRY_ATTR_WEAK -jerry_port_path_base (const jerry_char_t *path_p) /**< path */ +jerry_size_t +jerry_port_get_cwd (jerry_char_t *buffer_p, jerry_size_t buffer_size) { - const jerry_char_t *basename_p = (jerry_char_t *) strrchr ((char *) path_p, '/') + 1; - - return (jerry_size_t) (basename_p - path_p); -} /* jerry_port_get_directory_end */ + if (buffer_p == NULL) + { + jerry_size_t size = 260; + char *buf = NULL; + char *ptr = NULL; + for (; ptr == NULL; size *= 2) + { + if ((ptr = realloc (buf, size)) == NULL) + { + break; + } + buf = ptr; + ptr = getcwd (buf, size); + if (ptr == NULL && errno != ERANGE) + { + break; + } + } + size = ptr ? (jerry_size_t) strlen (ptr) : 0; + if (buf) + free (buf); + return size; + } + + if (getcwd ((char *) buffer_p, buffer_size) != NULL) + { + if ((strlen ((char *) buffer_p) + 1) == buffer_size) + { + return buffer_size - 1; + } + } + return 0; +} /* jerry_port_get_cwd */ #endif /* defined(__unix__) || defined(__APPLE__) */ diff --git a/jerry-port/win/jerry-port-win-fs.c b/jerry-port/win/jerry-port-win-fs.c index dbfe0467f5..82f6c56f2d 100644 --- a/jerry-port/win/jerry-port-win-fs.c +++ b/jerry-port/win/jerry-port-win-fs.c @@ -17,56 +17,51 @@ #if defined(_WIN32) +#include #include #include -/** - * Normalize a file path. - * - * @return a newly allocated buffer with the normalized path if the operation is successful, - * NULL otherwise - */ -jerry_char_t * -jerry_port_path_normalize (const jerry_char_t *path_p, /**< input path */ - jerry_size_t path_size) /**< size of the path */ -{ - (void) path_size; - - return (jerry_char_t *) _fullpath (NULL, (const char *) path_p, _MAX_PATH); -} /* jerry_port_path_normalize */ - -/** - * Free a path buffer returned by jerry_port_path_normalize. - */ -void -jerry_port_path_free (jerry_char_t *path_p) +jerry_path_style_t +jerry_port_path_style (void) { - free (path_p); -} /* jerry_port_path_free */ + return JERRY_PATH_STYLE_WINDOWS; +} /* jerry_port_path_style */ -/** - * Get the end of the directory part of the input path. - * - * @param path_p: input zero-terminated path string - * - * @return offset of the directory end in the input path string - */ jerry_size_t -jerry_port_path_base (const jerry_char_t *path_p) +jerry_port_get_cwd (jerry_char_t *buffer_p, jerry_size_t buffer_size) { - const jerry_char_t *end_p = path_p + strlen ((const char *) path_p); - - while (end_p > path_p) + if (buffer_p == NULL) { - if (end_p[-1] == '/' || end_p[-1] == '\\') + jerry_size_t size = _MAX_PATH; + char *buf = NULL; + char *ptr = NULL; + for (; ptr == NULL; size *= 2) { - return (jerry_size_t) (end_p - path_p); + if ((ptr = realloc (buf, size)) == NULL) + { + break; + } + buf = ptr; + ptr = getcwd (buf, size); + if (ptr == NULL && errno != ERANGE) + { + break; + } } - - end_p--; + size = ptr ? (jerry_size_t) strlen (ptr) : 0; + if (buf) + free (buf); + return size; } + if (getcwd ((char *) buffer_p, buffer_size) != NULL) + { + if ((strlen ((char *) buffer_p) + 1) == buffer_size) + { + return buffer_size - 1; + } + } return 0; -} /* jerry_port_path_base */ +} /* jerry_port_get_cwd */ #endif /* defined(_WIN32) */