1cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/* Copyright 2013 The Chromium Authors. All rights reserved.
2cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Use of this source code is governed by a BSD-style license that can be
3cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * found in the LICENSE file. */
4cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
5cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <assert.h>
6cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <stdlib.h>
7cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <errno.h>
8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <limits.h>
9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <stdlib.h>
10cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <string.h>
11cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <sys/stat.h>
12cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <unistd.h>
13cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
14cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "sdk_util/macros.h"
15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
16cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)EXTERN_C_BEGIN
17cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#if defined(__native_client__)
19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// TODO(binji): glibc has realpath, but it fails for all tests. Investigate.
21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)char* realpath(const char* path, char* resolved_path) {
23cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (path == NULL) {
24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    errno = EINVAL;
25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return NULL;
26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int needs_free = 0;
29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (resolved_path == NULL) {
30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    resolved_path = (char*)malloc(PATH_MAX);
31cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    needs_free = 1;
32cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
33cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
34cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  struct stat statbuf;
35cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const char* in = path;
36cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  char* out = resolved_path;
37cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  char* out_end = resolved_path + PATH_MAX - 1;
38cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int done = 0;
39cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
40cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  *out = 0;
41cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
42cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (*in == '/') {
43cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // Absolute path.
44cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    strcat(out, "/");
45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    in++;
46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    out++;
47cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  } else {
48cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // Relative path.
49cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (getcwd(out, out_end - out) == NULL)
50cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      goto fail;
51cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    out += strlen(out);
53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
54cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (stat(resolved_path, &statbuf) != 0)
56cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    goto fail;
57cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
58cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  while (!done) {
59cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const char* next_slash = strchr(in, '/');
60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    size_t namelen;
61cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const char* next_in;
62cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (next_slash) {
63cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      namelen = next_slash - in;
64cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      next_in = next_slash + 1;
65cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    } else {
66cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      namelen = strlen(in);
67cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      next_in = in + namelen;  // Move to the '\0'
68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      done = 1;
69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
71cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (namelen == 0) {
72cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      // Empty name, do nothing.
73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    } else if (namelen == 1 && strncmp(in, ".", 1) == 0) {
74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      // Current directory, do nothing.
75cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    } else if (namelen == 2 && strncmp(in, "..", 2) == 0) {
76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      // Parent directory, find previous slash in resolved_path.
77cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      char* prev_slash = strrchr(resolved_path, '/');
78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      assert(prev_slash != NULL);
79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
80cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      out = prev_slash;
81cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if (prev_slash == resolved_path) {
82cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        // Moved to the root. Keep the slash.
83cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        ++out;
84cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      }
85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      *out = 0;
87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    } else {
88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      // Append a slash if not at root.
89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if (out != resolved_path + 1) {
90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        if (out + 1 > out_end) {
91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          errno = ENAMETOOLONG;
92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          goto fail;
93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        }
94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
95cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        strncat(out, "/", namelen);
96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        out++;
97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      }
98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
99cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if (out + namelen > out_end) {
100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        errno = ENAMETOOLONG;
101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        goto fail;
102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      }
103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      strncat(out, in, namelen);
105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      out += namelen;
106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    in = next_in;
109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (stat(resolved_path, &statbuf) != 0)
111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      goto fail;
112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // If there is more to the path, then the current path must be a directory.
114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (!done && !S_ISDIR(statbuf.st_mode)) {
115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      errno = ENOTDIR;
116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      goto fail;
117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return resolved_path;
121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)fail:
123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (needs_free) {
124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    free(resolved_path);
125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return NULL;
127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)EXTERN_C_END
130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#endif  // defined(__native_client__)
132