Normalize an untrusted repository-relative path without touching the * filesystem. Absolute paths, drive/UNC paths, control bytes, and any `..` * component are rejected. A root scope (`.`) normalizes to the empty prefix. */
| 4052 | * filesystem. Absolute paths, drive/UNC paths, control bytes, and any `..` |
| 4053 | * component are rejected. A root scope (`.`) normalizes to the empty prefix. */ |
| 4054 | static coverage_path_result_t coverage_normalize_rel(const char *input, bool allow_root, char *out, |
| 4055 | size_t out_size) { |
| 4056 | if (!input || !out || out_size == 0U) { |
| 4057 | return COVERAGE_PATH_INVALID; |
| 4058 | } |
| 4059 | out[0] = '\0'; |
| 4060 | size_t len = strlen(input); |
| 4061 | if (len == 0U || len >= out_size || input[0] == '/' || input[0] == '\\' || |
| 4062 | (len >= 2U && isalpha((unsigned char)input[0]) && input[1] == ':')) { |
| 4063 | return COVERAGE_PATH_OUTSIDE; |
| 4064 | } |
| 4065 | |
| 4066 | size_t in = 0U; |
| 4067 | size_t written = 0U; |
| 4068 | while (in < len) { |
| 4069 | while (in < len && (input[in] == '/' || input[in] == '\\')) { |
| 4070 | in++; |
| 4071 | } |
| 4072 | if (in >= len) { |
| 4073 | break; |
| 4074 | } |
| 4075 | size_t start = in; |
| 4076 | while (in < len && input[in] != '/' && input[in] != '\\') { |
| 4077 | unsigned char c = (unsigned char)input[in]; |
| 4078 | if (c < 0x20U) { |
| 4079 | return COVERAGE_PATH_INVALID; |
| 4080 | } |
| 4081 | in++; |
| 4082 | } |
| 4083 | size_t part_len = in - start; |
| 4084 | if (part_len == 1U && input[start] == '.') { |
| 4085 | continue; |
| 4086 | } |
| 4087 | if (part_len == 2U && input[start] == '.' && input[start + 1U] == '.') { |
| 4088 | return COVERAGE_PATH_OUTSIDE; |
| 4089 | } |
| 4090 | if (written > 0U) { |
| 4091 | if (written + 1U >= out_size) { |
| 4092 | return COVERAGE_PATH_INVALID; |
| 4093 | } |
| 4094 | out[written++] = '/'; |
| 4095 | } |
| 4096 | if (written + part_len >= out_size) { |
| 4097 | return COVERAGE_PATH_INVALID; |
| 4098 | } |
| 4099 | memcpy(out + written, input + start, part_len); |
| 4100 | written += part_len; |
| 4101 | } |
| 4102 | out[written] = '\0'; |
| 4103 | return written > 0U || allow_root ? COVERAGE_PATH_OK : COVERAGE_PATH_INVALID; |
| 4104 | } |
| 4105 | |
| 4106 | static int64_t coverage_stat_mtime_ns(const struct stat *st) { |
| 4107 | #ifdef __APPLE__ |
no outgoing calls
no test coverage detected