1// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "platform/globals.h"
6#if defined(HOST_OS_ANDROID)
7
8#include "bin/namespace.h"
9
10#include <errno.h>
11#include <fcntl.h>
12
13#include "bin/file.h"
14#include "platform/signal_blocker.h"
15#include "platform/text_buffer.h"
16
17namespace dart {
18namespace bin {
19
20class NamespaceImpl {
21 public:
22 explicit NamespaceImpl(intptr_t rootfd) : rootfd_(rootfd), cwd_(strdup("/")) {
23 ASSERT(rootfd_ > 0);
24 cwdfd_ = dup(rootfd_);
25 ASSERT(cwdfd_ > 0);
26 }
27
28 explicit NamespaceImpl(const char* path)
29 : rootfd_(TEMP_FAILURE_RETRY(open(path, O_DIRECTORY))),
30 cwd_(strdup("/")) {
31 ASSERT(rootfd_ > 0);
32 cwdfd_ = dup(rootfd_);
33 ASSERT(cwdfd_ > 0);
34 }
35
36 ~NamespaceImpl() {
37 NO_RETRY_EXPECTED(close(rootfd_));
38 free(cwd_);
39 NO_RETRY_EXPECTED(close(cwdfd_));
40 }
41
42 intptr_t rootfd() const { return rootfd_; }
43 char* cwd() const { return cwd_; }
44 intptr_t cwdfd() const { return cwdfd_; }
45
46 bool SetCwd(Namespace* namespc, const char* new_path) {
47 NamespaceScope ns(namespc, new_path);
48 const intptr_t new_cwdfd =
49 TEMP_FAILURE_RETRY(openat(ns.fd(), ns.path(), O_DIRECTORY));
50 if (new_cwdfd < 0) {
51 return false;
52 }
53
54 TextBuffer tbuf(PATH_MAX);
55 if (!File::IsAbsolutePath(new_path)) {
56 tbuf.AddString(cwd_);
57 }
58 tbuf.AddString(File::PathSeparator());
59 tbuf.AddString(ns.path());
60
61 // Normalize it.
62 char result[PATH_MAX];
63 const intptr_t result_len =
64 File::CleanUnixPath(tbuf.buffer(), result, PATH_MAX);
65 if (result_len < 0) {
66 errno = ENAMETOOLONG;
67 return false;
68 }
69
70 free(cwd_);
71 cwd_ = strdup(result);
72 close(cwdfd_);
73 cwdfd_ = new_cwdfd;
74 return true;
75 }
76
77 private:
78 intptr_t rootfd_; // dirfd for the namespace root.
79 char* cwd_; // cwd relative to the namespace.
80 intptr_t cwdfd_; // dirfd for the cwd.
81
82 DISALLOW_COPY_AND_ASSIGN(NamespaceImpl);
83};
84
85Namespace* Namespace::Create(intptr_t namespc) {
86 NamespaceImpl* namespc_impl = NULL;
87 if (namespc != kNone) {
88 namespc_impl = new NamespaceImpl(namespc);
89 }
90 return new Namespace(namespc_impl);
91}
92
93Namespace* Namespace::Create(const char* path) {
94 return new Namespace(new NamespaceImpl(path));
95}
96
97Namespace::~Namespace() {
98 delete namespc_;
99}
100
101intptr_t Namespace::Default() {
102 return kNone;
103}
104
105const char* Namespace::GetCurrent(Namespace* namespc) {
106 if (Namespace::IsDefault(namespc)) {
107 char buffer[PATH_MAX];
108 if (getcwd(buffer, PATH_MAX) == NULL) {
109 return NULL;
110 }
111 return DartUtils::ScopedCopyCString(buffer);
112 }
113 const char* cwd = namespc->namespc()->cwd();
114 return cwd;
115}
116
117bool Namespace::SetCurrent(Namespace* namespc, const char* path) {
118 if (Namespace::IsDefault(namespc)) {
119 return (NO_RETRY_EXPECTED(chdir(path)) == 0);
120 }
121 return namespc->namespc()->SetCwd(namespc, path);
122}
123
124void Namespace::ResolvePath(Namespace* namespc,
125 const char* path,
126 intptr_t* dirfd,
127 const char** resolved_path) {
128 ASSERT(dirfd != NULL);
129 ASSERT(resolved_path != NULL);
130 if (Namespace::IsDefault(namespc)) {
131 *dirfd = AT_FDCWD;
132 *resolved_path = path;
133 return;
134 }
135 if (File::IsAbsolutePath(path)) {
136 *dirfd = namespc->namespc()->rootfd();
137 if (strcmp(path, File::PathSeparator()) == 0) {
138 // Change "/" to ".".
139 *resolved_path = ".";
140 } else {
141 // Otherwise strip off the leading "/".
142 *resolved_path = &path[1];
143 }
144 } else {
145 *dirfd = namespc->namespc()->cwdfd();
146 *resolved_path = path;
147 }
148}
149
150NamespaceScope::NamespaceScope(Namespace* namespc, const char* path) {
151 Namespace::ResolvePath(namespc, path, &fd_, &path_);
152}
153
154NamespaceScope::~NamespaceScope() {}
155
156} // namespace bin
157} // namespace dart
158
159#endif // defined(HOST_OS_ANDROID)
160