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_FUCHSIA)
7
8#include "bin/namespace.h"
9#include "bin/namespace_fuchsia.h"
10
11#include <errno.h>
12#include <fcntl.h>
13#include <lib/fdio/namespace.h>
14#include <zircon/status.h>
15
16#include "bin/file.h"
17#include "platform/signal_blocker.h"
18#include "platform/text_buffer.h"
19
20namespace dart {
21namespace bin {
22
23NamespaceImpl::NamespaceImpl(fdio_ns_t* fdio_ns)
24 : fdio_ns_(fdio_ns),
25 cwd_(strdup("/")) {
26 rootfd_ = fdio_ns_opendir(fdio_ns);
27 if (rootfd_ < 0) {
28 FATAL2("Failed to open file descriptor for namespace: errno=%d: %s", errno,
29 strerror(errno));
30 }
31 cwdfd_ = dup(rootfd_);
32 if (cwdfd_ < 0) {
33 FATAL2("Failed to dup() namespace file descriptor: errno=%d: %s", errno,
34 strerror(errno));
35 }
36}
37
38NamespaceImpl::NamespaceImpl(const char* path)
39 : fdio_ns_(NULL),
40 cwd_(strdup("/")) {
41 rootfd_ = TEMP_FAILURE_RETRY(open(path, O_DIRECTORY));
42 if (rootfd_ < 0) {
43 FATAL2("Failed to open file descriptor for namespace: errno=%d: %s", errno,
44 strerror(errno));
45 }
46 cwdfd_ = dup(rootfd_);
47 if (cwdfd_ < 0) {
48 FATAL2("Failed to dup() namespace file descriptor: errno=%d: %s", errno,
49 strerror(errno));
50 }
51}
52
53NamespaceImpl::~NamespaceImpl() {
54 NO_RETRY_EXPECTED(close(rootfd_));
55 free(cwd_);
56 NO_RETRY_EXPECTED(close(cwdfd_));
57 if (fdio_ns_ != NULL) {
58 zx_status_t status = fdio_ns_destroy(fdio_ns_);
59 if (status != ZX_OK) {
60 Syslog::PrintErr("fdio_ns_destroy: %s\n", zx_status_get_string(status));
61 }
62 }
63}
64
65bool NamespaceImpl::SetCwd(Namespace* namespc, const char* new_path) {
66 NamespaceScope ns(namespc, new_path);
67 const intptr_t new_cwdfd =
68 TEMP_FAILURE_RETRY(openat(ns.fd(), ns.path(), O_DIRECTORY));
69 if (new_cwdfd < 0) {
70 return false;
71 }
72
73 // Build the new cwd.
74 TextBuffer tbuf(PATH_MAX);
75 if (!File::IsAbsolutePath(new_path)) {
76 tbuf.AddString(cwd_);
77 }
78 tbuf.AddString(File::PathSeparator());
79 tbuf.AddString(ns.path());
80
81 // Normalize it.
82 char result[PATH_MAX];
83 const intptr_t result_len =
84 File::CleanUnixPath(tbuf.buffer(), result, PATH_MAX);
85 if (result_len < 0) {
86 errno = ENAMETOOLONG;
87 return false;
88 }
89
90 free(cwd_);
91 cwd_ = strdup(result);
92 close(cwdfd_);
93 cwdfd_ = new_cwdfd;
94 return true;
95}
96
97Namespace* Namespace::Create(intptr_t namespc) {
98 NamespaceImpl* namespc_impl = NULL;
99 if (namespc != kNone) {
100 namespc_impl = new NamespaceImpl(reinterpret_cast<fdio_ns_t*>(namespc));
101 }
102 return new Namespace(namespc_impl);
103}
104
105Namespace* Namespace::Create(const char* path) {
106 return new Namespace(new NamespaceImpl(path));
107}
108
109Namespace::~Namespace() {
110 delete namespc_;
111}
112
113intptr_t Namespace::Default() {
114 return kNone;
115}
116
117const char* Namespace::GetCurrent(Namespace* namespc) {
118 if (Namespace::IsDefault(namespc)) {
119 char buffer[PATH_MAX];
120 if (getcwd(buffer, PATH_MAX) == NULL) {
121 return NULL;
122 }
123 return DartUtils::ScopedCopyCString(buffer);
124 }
125 return namespc->namespc()->cwd();
126}
127
128bool Namespace::SetCurrent(Namespace* namespc, const char* path) {
129 if (Namespace::IsDefault(namespc)) {
130 return (NO_RETRY_EXPECTED(chdir(path)) == 0);
131 }
132 return namespc->namespc()->SetCwd(namespc, path);
133}
134
135void Namespace::ResolvePath(Namespace* namespc,
136 const char* path,
137 intptr_t* dirfd,
138 const char** resolved_path) {
139 ASSERT(dirfd != NULL);
140 ASSERT(resolved_path != NULL);
141 if (Namespace::IsDefault(namespc)) {
142 *dirfd = AT_FDCWD;
143 *resolved_path = path;
144 return;
145 }
146 if (File::IsAbsolutePath(path)) {
147 *dirfd = namespc->namespc()->rootfd();
148 if (strcmp(path, File::PathSeparator()) == 0) {
149 // Change "/" to ".".
150 *resolved_path = ".";
151 } else {
152 // Otherwise strip off the leading "/".
153 *resolved_path = &path[1];
154 }
155 } else {
156 *dirfd = namespc->namespc()->cwdfd();
157 *resolved_path = path;
158 }
159}
160
161NamespaceScope::NamespaceScope(Namespace* namespc, const char* path) {
162 Namespace::ResolvePath(namespc, path, &fd_, &path_);
163}
164
165NamespaceScope::~NamespaceScope() {}
166
167} // namespace bin
168} // namespace dart
169
170#endif // defined(HOST_OS_FUCHSIA)
171