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