11cb0ef41Sopenharmony_ci#include <string.h> 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ci#include "uv.h" 41cb0ef41Sopenharmony_ci#include "uvwasi.h" 51cb0ef41Sopenharmony_ci#include "uvwasi_alloc.h" 61cb0ef41Sopenharmony_ci#include "uv_mapping.h" 71cb0ef41Sopenharmony_ci#include "path_resolver.h" 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ci#define UVWASI__MAX_SYMLINK_FOLLOWS 32 101cb0ef41Sopenharmony_ci 111cb0ef41Sopenharmony_ci#ifndef _WIN32 121cb0ef41Sopenharmony_ci# define IS_SLASH(c) ((c) == '/') 131cb0ef41Sopenharmony_ci#else 141cb0ef41Sopenharmony_ci# define IS_SLASH(c) ((c) == '/' || (c) == '\\') 151cb0ef41Sopenharmony_ci#endif /* _WIN32 */ 161cb0ef41Sopenharmony_ci 171cb0ef41Sopenharmony_ci 181cb0ef41Sopenharmony_cistatic int uvwasi__is_absolute_path(const char* path, uvwasi_size_t path_len) { 191cb0ef41Sopenharmony_ci /* It's expected that only Unix style paths will be generated by WASI. */ 201cb0ef41Sopenharmony_ci return path != NULL && path_len > 0 && path[0] == '/'; 211cb0ef41Sopenharmony_ci} 221cb0ef41Sopenharmony_ci 231cb0ef41Sopenharmony_ci 241cb0ef41Sopenharmony_cistatic char* uvwasi__strchr_slash(const char* s) { 251cb0ef41Sopenharmony_ci /* strchr() that identifies /, as well as \ on Windows. */ 261cb0ef41Sopenharmony_ci do { 271cb0ef41Sopenharmony_ci if (IS_SLASH(*s)) 281cb0ef41Sopenharmony_ci return (char*) s; 291cb0ef41Sopenharmony_ci } while (*s++); 301cb0ef41Sopenharmony_ci 311cb0ef41Sopenharmony_ci return NULL; 321cb0ef41Sopenharmony_ci} 331cb0ef41Sopenharmony_ci 341cb0ef41Sopenharmony_ci 351cb0ef41Sopenharmony_ciuvwasi_errno_t uvwasi__normalize_path(const char* path, 361cb0ef41Sopenharmony_ci uvwasi_size_t path_len, 371cb0ef41Sopenharmony_ci char* normalized_path, 381cb0ef41Sopenharmony_ci uvwasi_size_t normalized_len) { 391cb0ef41Sopenharmony_ci const char* cur; 401cb0ef41Sopenharmony_ci char* ptr; 411cb0ef41Sopenharmony_ci char* next; 421cb0ef41Sopenharmony_ci char* last; 431cb0ef41Sopenharmony_ci size_t cur_len; 441cb0ef41Sopenharmony_ci int is_absolute; 451cb0ef41Sopenharmony_ci 461cb0ef41Sopenharmony_ci if (path_len > normalized_len) 471cb0ef41Sopenharmony_ci return UVWASI_ENOBUFS; 481cb0ef41Sopenharmony_ci 491cb0ef41Sopenharmony_ci is_absolute = uvwasi__is_absolute_path(path, path_len); 501cb0ef41Sopenharmony_ci normalized_path[0] = '\0'; 511cb0ef41Sopenharmony_ci ptr = normalized_path; 521cb0ef41Sopenharmony_ci for (cur = path; cur != NULL; cur = next + 1) { 531cb0ef41Sopenharmony_ci next = uvwasi__strchr_slash(cur); 541cb0ef41Sopenharmony_ci cur_len = (next == NULL) ? strlen(cur) : (size_t) (next - cur); 551cb0ef41Sopenharmony_ci 561cb0ef41Sopenharmony_ci if (cur_len == 0) { 571cb0ef41Sopenharmony_ci if (ptr == normalized_path && next != NULL && is_absolute) { 581cb0ef41Sopenharmony_ci *ptr = '/'; 591cb0ef41Sopenharmony_ci ptr++; 601cb0ef41Sopenharmony_ci } 611cb0ef41Sopenharmony_ci 621cb0ef41Sopenharmony_ci *ptr = '\0'; 631cb0ef41Sopenharmony_ci } else if (cur_len == 1 && cur[0] == '.') { 641cb0ef41Sopenharmony_ci /* No-op. Just consume the '.' */ 651cb0ef41Sopenharmony_ci } else if (cur_len == 2 && cur[0] == '.' && cur[1] == '.') { 661cb0ef41Sopenharmony_ci /* Identify the path segment that preceded the current one. */ 671cb0ef41Sopenharmony_ci last = ptr; 681cb0ef41Sopenharmony_ci while (!IS_SLASH(*last) && last != normalized_path) { 691cb0ef41Sopenharmony_ci last--; 701cb0ef41Sopenharmony_ci } 711cb0ef41Sopenharmony_ci 721cb0ef41Sopenharmony_ci /* If the result is currently empty, or the last prior path is also '..' 731cb0ef41Sopenharmony_ci then output '..'. Otherwise, remove the last path segment. */ 741cb0ef41Sopenharmony_ci if (ptr == normalized_path || 751cb0ef41Sopenharmony_ci (last == ptr - 2 && last[0] == '.' && last[1] == '.') || 761cb0ef41Sopenharmony_ci (last == ptr - 3 && last[0] == '/' && 771cb0ef41Sopenharmony_ci last[1] == '.' && last[2] == '.')) { 781cb0ef41Sopenharmony_ci if (ptr != normalized_path && *(ptr - 1) != '/') { 791cb0ef41Sopenharmony_ci *ptr = '/'; 801cb0ef41Sopenharmony_ci ptr++; 811cb0ef41Sopenharmony_ci } 821cb0ef41Sopenharmony_ci 831cb0ef41Sopenharmony_ci *ptr = '.'; 841cb0ef41Sopenharmony_ci ptr++; 851cb0ef41Sopenharmony_ci *ptr = '.'; 861cb0ef41Sopenharmony_ci ptr++; 871cb0ef41Sopenharmony_ci } else { 881cb0ef41Sopenharmony_ci /* Strip the last segment, but make sure not to strip the '/' if that 891cb0ef41Sopenharmony_ci is the entire path. */ 901cb0ef41Sopenharmony_ci if (last == normalized_path && *last == '/') 911cb0ef41Sopenharmony_ci ptr = last + 1; 921cb0ef41Sopenharmony_ci else 931cb0ef41Sopenharmony_ci ptr = last; 941cb0ef41Sopenharmony_ci } 951cb0ef41Sopenharmony_ci 961cb0ef41Sopenharmony_ci *ptr = '\0'; 971cb0ef41Sopenharmony_ci } else { 981cb0ef41Sopenharmony_ci if (ptr != normalized_path && *(ptr - 1) != '/') { 991cb0ef41Sopenharmony_ci *ptr = '/'; 1001cb0ef41Sopenharmony_ci ptr++; 1011cb0ef41Sopenharmony_ci } 1021cb0ef41Sopenharmony_ci 1031cb0ef41Sopenharmony_ci memcpy(ptr, cur, cur_len); 1041cb0ef41Sopenharmony_ci ptr += cur_len; 1051cb0ef41Sopenharmony_ci *ptr = '\0'; 1061cb0ef41Sopenharmony_ci } 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_ci if (next == NULL) 1091cb0ef41Sopenharmony_ci break; 1101cb0ef41Sopenharmony_ci } 1111cb0ef41Sopenharmony_ci 1121cb0ef41Sopenharmony_ci /* Normalized the path to the empty string. Return either '/' or '.'. */ 1131cb0ef41Sopenharmony_ci if (ptr == normalized_path) { 1141cb0ef41Sopenharmony_ci if (1 == is_absolute) 1151cb0ef41Sopenharmony_ci *ptr = '/'; 1161cb0ef41Sopenharmony_ci else 1171cb0ef41Sopenharmony_ci *ptr = '.'; 1181cb0ef41Sopenharmony_ci 1191cb0ef41Sopenharmony_ci ptr++; 1201cb0ef41Sopenharmony_ci *ptr = '\0'; 1211cb0ef41Sopenharmony_ci } 1221cb0ef41Sopenharmony_ci 1231cb0ef41Sopenharmony_ci return UVWASI_ESUCCESS; 1241cb0ef41Sopenharmony_ci} 1251cb0ef41Sopenharmony_ci 1261cb0ef41Sopenharmony_ci 1271cb0ef41Sopenharmony_cistatic int uvwasi__is_path_sandboxed(const char* path, 1281cb0ef41Sopenharmony_ci uvwasi_size_t path_len, 1291cb0ef41Sopenharmony_ci const char* fd_path, 1301cb0ef41Sopenharmony_ci uvwasi_size_t fd_path_len) { 1311cb0ef41Sopenharmony_ci char* ptr; 1321cb0ef41Sopenharmony_ci int remaining_len; 1331cb0ef41Sopenharmony_ci 1341cb0ef41Sopenharmony_ci if (1 == uvwasi__is_absolute_path(fd_path, fd_path_len)) 1351cb0ef41Sopenharmony_ci return path == strstr(path, fd_path) ? 1 : 0; 1361cb0ef41Sopenharmony_ci 1371cb0ef41Sopenharmony_ci /* Handle relative fds that normalized to '.' */ 1381cb0ef41Sopenharmony_ci if (fd_path_len == 1 && fd_path[0] == '.') { 1391cb0ef41Sopenharmony_ci /* If the fd's path is '.', then any path does not begin with '..' is OK. */ 1401cb0ef41Sopenharmony_ci if ((path_len == 2 && path[0] == '.' && path[1] == '.') || 1411cb0ef41Sopenharmony_ci (path_len > 2 && path[0] == '.' && path[1] == '.' && path[2] == '/')) { 1421cb0ef41Sopenharmony_ci return 0; 1431cb0ef41Sopenharmony_ci } 1441cb0ef41Sopenharmony_ci 1451cb0ef41Sopenharmony_ci return 1; 1461cb0ef41Sopenharmony_ci } 1471cb0ef41Sopenharmony_ci 1481cb0ef41Sopenharmony_ci if (path != strstr(path, fd_path)) 1491cb0ef41Sopenharmony_ci return 0; 1501cb0ef41Sopenharmony_ci 1511cb0ef41Sopenharmony_ci /* Fail if the remaining path starts with '..', '../', '/..', or '/../'. */ 1521cb0ef41Sopenharmony_ci ptr = (char*) path + fd_path_len; 1531cb0ef41Sopenharmony_ci remaining_len = path_len - fd_path_len; 1541cb0ef41Sopenharmony_ci if (remaining_len < 2) 1551cb0ef41Sopenharmony_ci return 1; 1561cb0ef41Sopenharmony_ci 1571cb0ef41Sopenharmony_ci /* Strip a leading slash so the check is only for '..' and '../'. */ 1581cb0ef41Sopenharmony_ci if (*ptr == '/') { 1591cb0ef41Sopenharmony_ci ptr++; 1601cb0ef41Sopenharmony_ci remaining_len--; 1611cb0ef41Sopenharmony_ci } 1621cb0ef41Sopenharmony_ci 1631cb0ef41Sopenharmony_ci if ((remaining_len == 2 && ptr[0] == '.' && ptr[1] == '.') || 1641cb0ef41Sopenharmony_ci (remaining_len > 2 && ptr[0] == '.' && ptr[1] == '.' && ptr[2] == '/')) { 1651cb0ef41Sopenharmony_ci return 0; 1661cb0ef41Sopenharmony_ci } 1671cb0ef41Sopenharmony_ci 1681cb0ef41Sopenharmony_ci return 1; 1691cb0ef41Sopenharmony_ci} 1701cb0ef41Sopenharmony_ci 1711cb0ef41Sopenharmony_ci 1721cb0ef41Sopenharmony_cistatic uvwasi_errno_t uvwasi__normalize_absolute_path( 1731cb0ef41Sopenharmony_ci const uvwasi_t* uvwasi, 1741cb0ef41Sopenharmony_ci const struct uvwasi_fd_wrap_t* fd, 1751cb0ef41Sopenharmony_ci const char* path, 1761cb0ef41Sopenharmony_ci uvwasi_size_t path_len, 1771cb0ef41Sopenharmony_ci char** normalized_path, 1781cb0ef41Sopenharmony_ci uvwasi_size_t* normalized_len 1791cb0ef41Sopenharmony_ci ) { 1801cb0ef41Sopenharmony_ci /* This function resolves an absolute path to the provided file descriptor. 1811cb0ef41Sopenharmony_ci If the file descriptor's path is relative, then this operation will fail 1821cb0ef41Sopenharmony_ci with UVWASI_ENOTCAPABLE since it doesn't make sense to resolve an absolute 1831cb0ef41Sopenharmony_ci path to a relative prefix. If the file desciptor's path is also absolute, 1841cb0ef41Sopenharmony_ci then we just need to verify that the normalized path still starts with 1851cb0ef41Sopenharmony_ci the file descriptor's path. */ 1861cb0ef41Sopenharmony_ci uvwasi_errno_t err; 1871cb0ef41Sopenharmony_ci char* abs_path; 1881cb0ef41Sopenharmony_ci int abs_size; 1891cb0ef41Sopenharmony_ci 1901cb0ef41Sopenharmony_ci *normalized_path = NULL; 1911cb0ef41Sopenharmony_ci *normalized_len = 0; 1921cb0ef41Sopenharmony_ci abs_size = path_len + 1; 1931cb0ef41Sopenharmony_ci abs_path = uvwasi__malloc(uvwasi, abs_size); 1941cb0ef41Sopenharmony_ci if (abs_path == NULL) { 1951cb0ef41Sopenharmony_ci err = UVWASI_ENOMEM; 1961cb0ef41Sopenharmony_ci goto exit; 1971cb0ef41Sopenharmony_ci } 1981cb0ef41Sopenharmony_ci 1991cb0ef41Sopenharmony_ci /* Normalize the input path first. */ 2001cb0ef41Sopenharmony_ci err = uvwasi__normalize_path(path, path_len, abs_path, path_len); 2011cb0ef41Sopenharmony_ci if (err != UVWASI_ESUCCESS) 2021cb0ef41Sopenharmony_ci goto exit; 2031cb0ef41Sopenharmony_ci 2041cb0ef41Sopenharmony_ci /* Once the input is normalized, ensure that it is still sandboxed. */ 2051cb0ef41Sopenharmony_ci if (0 == uvwasi__is_path_sandboxed(abs_path, 2061cb0ef41Sopenharmony_ci path_len, 2071cb0ef41Sopenharmony_ci fd->normalized_path, 2081cb0ef41Sopenharmony_ci strlen(fd->normalized_path))) { 2091cb0ef41Sopenharmony_ci err = UVWASI_ENOTCAPABLE; 2101cb0ef41Sopenharmony_ci goto exit; 2111cb0ef41Sopenharmony_ci } 2121cb0ef41Sopenharmony_ci 2131cb0ef41Sopenharmony_ci *normalized_path = abs_path; 2141cb0ef41Sopenharmony_ci *normalized_len = abs_size - 1; 2151cb0ef41Sopenharmony_ci return UVWASI_ESUCCESS; 2161cb0ef41Sopenharmony_ci 2171cb0ef41Sopenharmony_ciexit: 2181cb0ef41Sopenharmony_ci uvwasi__free(uvwasi, abs_path); 2191cb0ef41Sopenharmony_ci return err; 2201cb0ef41Sopenharmony_ci} 2211cb0ef41Sopenharmony_ci 2221cb0ef41Sopenharmony_ci 2231cb0ef41Sopenharmony_cistatic uvwasi_errno_t uvwasi__normalize_relative_path( 2241cb0ef41Sopenharmony_ci const uvwasi_t* uvwasi, 2251cb0ef41Sopenharmony_ci const struct uvwasi_fd_wrap_t* fd, 2261cb0ef41Sopenharmony_ci const char* path, 2271cb0ef41Sopenharmony_ci uvwasi_size_t path_len, 2281cb0ef41Sopenharmony_ci char** normalized_path, 2291cb0ef41Sopenharmony_ci uvwasi_size_t* normalized_len 2301cb0ef41Sopenharmony_ci ) { 2311cb0ef41Sopenharmony_ci /* This function resolves a relative path to the provided file descriptor. 2321cb0ef41Sopenharmony_ci The relative path is concatenated to the file descriptor's path, and then 2331cb0ef41Sopenharmony_ci normalized. */ 2341cb0ef41Sopenharmony_ci uvwasi_errno_t err; 2351cb0ef41Sopenharmony_ci char* combined; 2361cb0ef41Sopenharmony_ci char* normalized; 2371cb0ef41Sopenharmony_ci int combined_size; 2381cb0ef41Sopenharmony_ci int fd_path_len; 2391cb0ef41Sopenharmony_ci int norm_len; 2401cb0ef41Sopenharmony_ci int r; 2411cb0ef41Sopenharmony_ci 2421cb0ef41Sopenharmony_ci *normalized_path = NULL; 2431cb0ef41Sopenharmony_ci *normalized_len = 0; 2441cb0ef41Sopenharmony_ci 2451cb0ef41Sopenharmony_ci /* The max combined size is the path length + the file descriptor's path 2461cb0ef41Sopenharmony_ci length + 2 for a terminating NULL and a possible path separator. */ 2471cb0ef41Sopenharmony_ci fd_path_len = strlen(fd->normalized_path); 2481cb0ef41Sopenharmony_ci combined_size = path_len + fd_path_len + 2; 2491cb0ef41Sopenharmony_ci combined = uvwasi__malloc(uvwasi, combined_size); 2501cb0ef41Sopenharmony_ci if (combined == NULL) 2511cb0ef41Sopenharmony_ci return UVWASI_ENOMEM; 2521cb0ef41Sopenharmony_ci 2531cb0ef41Sopenharmony_ci normalized = uvwasi__malloc(uvwasi, combined_size); 2541cb0ef41Sopenharmony_ci if (normalized == NULL) { 2551cb0ef41Sopenharmony_ci err = UVWASI_ENOMEM; 2561cb0ef41Sopenharmony_ci goto exit; 2571cb0ef41Sopenharmony_ci } 2581cb0ef41Sopenharmony_ci 2591cb0ef41Sopenharmony_ci r = snprintf(combined, combined_size, "%s/%s", fd->normalized_path, path); 2601cb0ef41Sopenharmony_ci if (r <= 0) { 2611cb0ef41Sopenharmony_ci err = uvwasi__translate_uv_error(uv_translate_sys_error(errno)); 2621cb0ef41Sopenharmony_ci goto exit; 2631cb0ef41Sopenharmony_ci } 2641cb0ef41Sopenharmony_ci 2651cb0ef41Sopenharmony_ci /* Normalize the input path. */ 2661cb0ef41Sopenharmony_ci err = uvwasi__normalize_path(combined, 2671cb0ef41Sopenharmony_ci combined_size - 1, 2681cb0ef41Sopenharmony_ci normalized, 2691cb0ef41Sopenharmony_ci combined_size - 1); 2701cb0ef41Sopenharmony_ci if (err != UVWASI_ESUCCESS) 2711cb0ef41Sopenharmony_ci goto exit; 2721cb0ef41Sopenharmony_ci 2731cb0ef41Sopenharmony_ci norm_len = strlen(normalized); 2741cb0ef41Sopenharmony_ci 2751cb0ef41Sopenharmony_ci /* Once the path is normalized, ensure that it is still sandboxed. */ 2761cb0ef41Sopenharmony_ci if (0 == uvwasi__is_path_sandboxed(normalized, 2771cb0ef41Sopenharmony_ci norm_len, 2781cb0ef41Sopenharmony_ci fd->normalized_path, 2791cb0ef41Sopenharmony_ci fd_path_len)) { 2801cb0ef41Sopenharmony_ci err = UVWASI_ENOTCAPABLE; 2811cb0ef41Sopenharmony_ci goto exit; 2821cb0ef41Sopenharmony_ci } 2831cb0ef41Sopenharmony_ci 2841cb0ef41Sopenharmony_ci err = UVWASI_ESUCCESS; 2851cb0ef41Sopenharmony_ci *normalized_path = normalized; 2861cb0ef41Sopenharmony_ci *normalized_len = norm_len; 2871cb0ef41Sopenharmony_ci 2881cb0ef41Sopenharmony_ciexit: 2891cb0ef41Sopenharmony_ci if (err != UVWASI_ESUCCESS) 2901cb0ef41Sopenharmony_ci uvwasi__free(uvwasi, normalized); 2911cb0ef41Sopenharmony_ci 2921cb0ef41Sopenharmony_ci uvwasi__free(uvwasi, combined); 2931cb0ef41Sopenharmony_ci return err; 2941cb0ef41Sopenharmony_ci} 2951cb0ef41Sopenharmony_ci 2961cb0ef41Sopenharmony_ci 2971cb0ef41Sopenharmony_cistatic uvwasi_errno_t uvwasi__resolve_path_to_host( 2981cb0ef41Sopenharmony_ci const uvwasi_t* uvwasi, 2991cb0ef41Sopenharmony_ci const struct uvwasi_fd_wrap_t* fd, 3001cb0ef41Sopenharmony_ci const char* path, 3011cb0ef41Sopenharmony_ci uvwasi_size_t path_len, 3021cb0ef41Sopenharmony_ci char** resolved_path, 3031cb0ef41Sopenharmony_ci uvwasi_size_t* resolved_len 3041cb0ef41Sopenharmony_ci ) { 3051cb0ef41Sopenharmony_ci /* Return the normalized path, but resolved to the host's real path. */ 3061cb0ef41Sopenharmony_ci char* res_path; 3071cb0ef41Sopenharmony_ci char* stripped_path; 3081cb0ef41Sopenharmony_ci int real_path_len; 3091cb0ef41Sopenharmony_ci int fake_path_len; 3101cb0ef41Sopenharmony_ci int stripped_len; 3111cb0ef41Sopenharmony_ci#ifdef _WIN32 3121cb0ef41Sopenharmony_ci uvwasi_size_t i; 3131cb0ef41Sopenharmony_ci#endif /* _WIN32 */ 3141cb0ef41Sopenharmony_ci 3151cb0ef41Sopenharmony_ci real_path_len = strlen(fd->real_path); 3161cb0ef41Sopenharmony_ci fake_path_len = strlen(fd->normalized_path); 3171cb0ef41Sopenharmony_ci 3181cb0ef41Sopenharmony_ci /* If the fake path is '.' just ignore it. */ 3191cb0ef41Sopenharmony_ci if (fake_path_len == 1 && fd->normalized_path[0] == '.') { 3201cb0ef41Sopenharmony_ci fake_path_len = 0; 3211cb0ef41Sopenharmony_ci } 3221cb0ef41Sopenharmony_ci 3231cb0ef41Sopenharmony_ci stripped_len = path_len - fake_path_len; 3241cb0ef41Sopenharmony_ci 3251cb0ef41Sopenharmony_ci /* The resolved path's length is calculated as: the length of the fd's real 3261cb0ef41Sopenharmony_ci path, + 1 for a path separator, and the length of the input path (with the 3271cb0ef41Sopenharmony_ci fake path stripped off). */ 3281cb0ef41Sopenharmony_ci *resolved_len = stripped_len + real_path_len + 1; 3291cb0ef41Sopenharmony_ci *resolved_path = uvwasi__malloc(uvwasi, *resolved_len + 1); 3301cb0ef41Sopenharmony_ci 3311cb0ef41Sopenharmony_ci if (*resolved_path == NULL) 3321cb0ef41Sopenharmony_ci return UVWASI_ENOMEM; 3331cb0ef41Sopenharmony_ci 3341cb0ef41Sopenharmony_ci res_path = *resolved_path; 3351cb0ef41Sopenharmony_ci stripped_path = (char*) path + fake_path_len; 3361cb0ef41Sopenharmony_ci memcpy(res_path, fd->real_path, real_path_len); 3371cb0ef41Sopenharmony_ci res_path += real_path_len; 3381cb0ef41Sopenharmony_ci 3391cb0ef41Sopenharmony_ci if (stripped_len > 1 || 3401cb0ef41Sopenharmony_ci (stripped_len == 1 && stripped_path[0] != '/')) { 3411cb0ef41Sopenharmony_ci if (stripped_path[0] != '/') { 3421cb0ef41Sopenharmony_ci *res_path = '/'; 3431cb0ef41Sopenharmony_ci res_path++; 3441cb0ef41Sopenharmony_ci } 3451cb0ef41Sopenharmony_ci 3461cb0ef41Sopenharmony_ci memcpy(res_path, stripped_path, stripped_len); 3471cb0ef41Sopenharmony_ci res_path += stripped_len; 3481cb0ef41Sopenharmony_ci } 3491cb0ef41Sopenharmony_ci 3501cb0ef41Sopenharmony_ci *res_path = '\0'; 3511cb0ef41Sopenharmony_ci 3521cb0ef41Sopenharmony_ci#ifdef _WIN32 3531cb0ef41Sopenharmony_ci /* Replace / with \ on Windows. */ 3541cb0ef41Sopenharmony_ci res_path = *resolved_path; 3551cb0ef41Sopenharmony_ci for (i = real_path_len; i < *resolved_len; i++) { 3561cb0ef41Sopenharmony_ci if (res_path[i] == '/') 3571cb0ef41Sopenharmony_ci res_path[i] = '\\'; 3581cb0ef41Sopenharmony_ci } 3591cb0ef41Sopenharmony_ci#endif /* _WIN32 */ 3601cb0ef41Sopenharmony_ci 3611cb0ef41Sopenharmony_ci return UVWASI_ESUCCESS; 3621cb0ef41Sopenharmony_ci} 3631cb0ef41Sopenharmony_ci 3641cb0ef41Sopenharmony_ci 3651cb0ef41Sopenharmony_ciuvwasi_errno_t uvwasi__resolve_path(const uvwasi_t* uvwasi, 3661cb0ef41Sopenharmony_ci const struct uvwasi_fd_wrap_t* fd, 3671cb0ef41Sopenharmony_ci const char* path, 3681cb0ef41Sopenharmony_ci uvwasi_size_t path_len, 3691cb0ef41Sopenharmony_ci char** resolved_path, 3701cb0ef41Sopenharmony_ci uvwasi_lookupflags_t flags) { 3711cb0ef41Sopenharmony_ci uv_fs_t req; 3721cb0ef41Sopenharmony_ci uvwasi_errno_t err; 3731cb0ef41Sopenharmony_ci const char* input; 3741cb0ef41Sopenharmony_ci char* host_path; 3751cb0ef41Sopenharmony_ci char* normalized_path; 3761cb0ef41Sopenharmony_ci char* link_target; 3771cb0ef41Sopenharmony_ci uvwasi_size_t input_len; 3781cb0ef41Sopenharmony_ci uvwasi_size_t host_path_len; 3791cb0ef41Sopenharmony_ci uvwasi_size_t normalized_len; 3801cb0ef41Sopenharmony_ci int follow_count; 3811cb0ef41Sopenharmony_ci int r; 3821cb0ef41Sopenharmony_ci 3831cb0ef41Sopenharmony_ci input = path; 3841cb0ef41Sopenharmony_ci input_len = path_len; 3851cb0ef41Sopenharmony_ci link_target = NULL; 3861cb0ef41Sopenharmony_ci follow_count = 0; 3871cb0ef41Sopenharmony_ci host_path = NULL; 3881cb0ef41Sopenharmony_ci 3891cb0ef41Sopenharmony_cistart: 3901cb0ef41Sopenharmony_ci normalized_path = NULL; 3911cb0ef41Sopenharmony_ci err = UVWASI_ESUCCESS; 3921cb0ef41Sopenharmony_ci 3931cb0ef41Sopenharmony_ci if (1 == uvwasi__is_absolute_path(input, input_len)) { 3941cb0ef41Sopenharmony_ci err = uvwasi__normalize_absolute_path(uvwasi, 3951cb0ef41Sopenharmony_ci fd, 3961cb0ef41Sopenharmony_ci input, 3971cb0ef41Sopenharmony_ci input_len, 3981cb0ef41Sopenharmony_ci &normalized_path, 3991cb0ef41Sopenharmony_ci &normalized_len); 4001cb0ef41Sopenharmony_ci } else { 4011cb0ef41Sopenharmony_ci err = uvwasi__normalize_relative_path(uvwasi, 4021cb0ef41Sopenharmony_ci fd, 4031cb0ef41Sopenharmony_ci input, 4041cb0ef41Sopenharmony_ci input_len, 4051cb0ef41Sopenharmony_ci &normalized_path, 4061cb0ef41Sopenharmony_ci &normalized_len); 4071cb0ef41Sopenharmony_ci } 4081cb0ef41Sopenharmony_ci 4091cb0ef41Sopenharmony_ci if (err != UVWASI_ESUCCESS) 4101cb0ef41Sopenharmony_ci goto exit; 4111cb0ef41Sopenharmony_ci 4121cb0ef41Sopenharmony_ci uvwasi__free(uvwasi, host_path); 4131cb0ef41Sopenharmony_ci err = uvwasi__resolve_path_to_host(uvwasi, 4141cb0ef41Sopenharmony_ci fd, 4151cb0ef41Sopenharmony_ci normalized_path, 4161cb0ef41Sopenharmony_ci normalized_len, 4171cb0ef41Sopenharmony_ci &host_path, 4181cb0ef41Sopenharmony_ci &host_path_len); 4191cb0ef41Sopenharmony_ci if (err != UVWASI_ESUCCESS) 4201cb0ef41Sopenharmony_ci goto exit; 4211cb0ef41Sopenharmony_ci 4221cb0ef41Sopenharmony_ci if ((flags & UVWASI_LOOKUP_SYMLINK_FOLLOW) == UVWASI_LOOKUP_SYMLINK_FOLLOW) { 4231cb0ef41Sopenharmony_ci r = uv_fs_readlink(NULL, &req, host_path, NULL); 4241cb0ef41Sopenharmony_ci 4251cb0ef41Sopenharmony_ci if (r != 0) { 4261cb0ef41Sopenharmony_ci#ifdef _WIN32 4271cb0ef41Sopenharmony_ci /* uv_fs_readlink() returns UV__UNKNOWN on Windows. Try to get a better 4281cb0ef41Sopenharmony_ci error using uv_fs_stat(). */ 4291cb0ef41Sopenharmony_ci if (r == UV__UNKNOWN) { 4301cb0ef41Sopenharmony_ci uv_fs_req_cleanup(&req); 4311cb0ef41Sopenharmony_ci r = uv_fs_stat(NULL, &req, host_path, NULL); 4321cb0ef41Sopenharmony_ci 4331cb0ef41Sopenharmony_ci if (r == 0) { 4341cb0ef41Sopenharmony_ci if (uvwasi__stat_to_filetype(&req.statbuf) != 4351cb0ef41Sopenharmony_ci UVWASI_FILETYPE_SYMBOLIC_LINK) { 4361cb0ef41Sopenharmony_ci r = UV_EINVAL; 4371cb0ef41Sopenharmony_ci } 4381cb0ef41Sopenharmony_ci } 4391cb0ef41Sopenharmony_ci 4401cb0ef41Sopenharmony_ci /* Fall through. */ 4411cb0ef41Sopenharmony_ci } 4421cb0ef41Sopenharmony_ci#endif /* _WIN32 */ 4431cb0ef41Sopenharmony_ci 4441cb0ef41Sopenharmony_ci /* Don't report UV_EINVAL or UV_ENOENT. They mean that either the file 4451cb0ef41Sopenharmony_ci does not exist, or it is not a symlink. Both are OK. */ 4461cb0ef41Sopenharmony_ci if (r != UV_EINVAL && r != UV_ENOENT) 4471cb0ef41Sopenharmony_ci err = uvwasi__translate_uv_error(r); 4481cb0ef41Sopenharmony_ci 4491cb0ef41Sopenharmony_ci uv_fs_req_cleanup(&req); 4501cb0ef41Sopenharmony_ci goto exit; 4511cb0ef41Sopenharmony_ci } 4521cb0ef41Sopenharmony_ci 4531cb0ef41Sopenharmony_ci /* Clean up memory and follow the link, unless it's time to return ELOOP. */ 4541cb0ef41Sopenharmony_ci follow_count++; 4551cb0ef41Sopenharmony_ci if (follow_count >= UVWASI__MAX_SYMLINK_FOLLOWS) { 4561cb0ef41Sopenharmony_ci uv_fs_req_cleanup(&req); 4571cb0ef41Sopenharmony_ci err = UVWASI_ELOOP; 4581cb0ef41Sopenharmony_ci goto exit; 4591cb0ef41Sopenharmony_ci } 4601cb0ef41Sopenharmony_ci 4611cb0ef41Sopenharmony_ci input_len = strlen(req.ptr); 4621cb0ef41Sopenharmony_ci uvwasi__free(uvwasi, link_target); 4631cb0ef41Sopenharmony_ci link_target = uvwasi__malloc(uvwasi, input_len + 1); 4641cb0ef41Sopenharmony_ci if (link_target == NULL) { 4651cb0ef41Sopenharmony_ci uv_fs_req_cleanup(&req); 4661cb0ef41Sopenharmony_ci err = UVWASI_ENOMEM; 4671cb0ef41Sopenharmony_ci goto exit; 4681cb0ef41Sopenharmony_ci } 4691cb0ef41Sopenharmony_ci 4701cb0ef41Sopenharmony_ci memcpy(link_target, req.ptr, input_len + 1); 4711cb0ef41Sopenharmony_ci input = link_target; 4721cb0ef41Sopenharmony_ci uvwasi__free(uvwasi, normalized_path); 4731cb0ef41Sopenharmony_ci uv_fs_req_cleanup(&req); 4741cb0ef41Sopenharmony_ci goto start; 4751cb0ef41Sopenharmony_ci } 4761cb0ef41Sopenharmony_ci 4771cb0ef41Sopenharmony_ciexit: 4781cb0ef41Sopenharmony_ci if (err == UVWASI_ESUCCESS) { 4791cb0ef41Sopenharmony_ci *resolved_path = host_path; 4801cb0ef41Sopenharmony_ci } else { 4811cb0ef41Sopenharmony_ci *resolved_path = NULL; 4821cb0ef41Sopenharmony_ci uvwasi__free(uvwasi, host_path); 4831cb0ef41Sopenharmony_ci } 4841cb0ef41Sopenharmony_ci 4851cb0ef41Sopenharmony_ci uvwasi__free(uvwasi, link_target); 4861cb0ef41Sopenharmony_ci uvwasi__free(uvwasi, normalized_path); 4871cb0ef41Sopenharmony_ci return err; 4881cb0ef41Sopenharmony_ci} 489