ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / native_client_sdk / src / libraries / nacl_io / syscalls / realpath.c
blob9451243c70feee7603032590e2341b25d0fd1cea
1 /* Copyright 2013 The Chromium Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file. */
5 #include <assert.h>
6 #include <stdlib.h>
7 #include <errno.h>
8 #include <limits.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <sys/stat.h>
12 #include <unistd.h>
14 #include "sdk_util/macros.h"
16 EXTERN_C_BEGIN
18 #if defined(__native_client__)
20 // TODO(binji): glibc has realpath, but it fails for all tests. Investigate.
22 char* realpath(const char* path, char* resolved_path) {
23 if (path == NULL) {
24 errno = EINVAL;
25 return NULL;
28 int needs_free = 0;
29 if (resolved_path == NULL) {
30 resolved_path = (char*)malloc(PATH_MAX);
31 needs_free = 1;
34 struct stat statbuf;
35 const char* in = path;
36 char* out = resolved_path;
37 char* out_end = resolved_path + PATH_MAX - 1;
38 int done = 0;
40 *out = 0;
42 if (*in == '/') {
43 // Absolute path.
44 strcat(out, "/");
45 in++;
46 out++;
47 } else {
48 // Relative path.
49 if (getcwd(out, out_end - out) == NULL)
50 goto fail;
52 out += strlen(out);
55 if (stat(resolved_path, &statbuf) != 0)
56 goto fail;
58 while (!done) {
59 const char* next_slash = strchr(in, '/');
60 size_t namelen;
61 const char* next_in;
62 if (next_slash) {
63 namelen = next_slash - in;
64 next_in = next_slash + 1;
65 } else {
66 namelen = strlen(in);
67 next_in = in + namelen; // Move to the '\0'
68 done = 1;
71 if (namelen == 0) {
72 // Empty name, do nothing.
73 } else if (namelen == 1 && strncmp(in, ".", 1) == 0) {
74 // Current directory, do nothing.
75 } else if (namelen == 2 && strncmp(in, "..", 2) == 0) {
76 // Parent directory, find previous slash in resolved_path.
77 char* prev_slash = strrchr(resolved_path, '/');
78 assert(prev_slash != NULL);
80 out = prev_slash;
81 if (prev_slash == resolved_path) {
82 // Moved to the root. Keep the slash.
83 ++out;
86 *out = 0;
87 } else {
88 // Append a slash if not at root.
89 if (out != resolved_path + 1) {
90 if (out + 1 > out_end) {
91 errno = ENAMETOOLONG;
92 goto fail;
95 strncat(out, "/", namelen);
96 out++;
99 if (out + namelen > out_end) {
100 errno = ENAMETOOLONG;
101 goto fail;
104 strncat(out, in, namelen);
105 out += namelen;
108 in = next_in;
110 if (stat(resolved_path, &statbuf) != 0)
111 goto fail;
113 // If there is more to the path, then the current path must be a directory.
114 if (!done && !S_ISDIR(statbuf.st_mode)) {
115 errno = ENOTDIR;
116 goto fail;
120 return resolved_path;
122 fail:
123 if (needs_free) {
124 free(resolved_path);
126 return NULL;
129 EXTERN_C_END
131 #endif // defined(__native_client__)