OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "platform/globals.h" | 5 #include "platform/globals.h" |
6 #if defined(TARGET_OS_MACOS) | 6 #if defined(TARGET_OS_FUCHSIA) |
7 | 7 |
8 #include "bin/file.h" | 8 #include "bin/file.h" |
9 | 9 |
10 #include <copyfile.h> // NOLINT | |
11 #include <errno.h> // NOLINT | 10 #include <errno.h> // NOLINT |
12 #include <fcntl.h> // NOLINT | 11 #include <fcntl.h> // NOLINT |
13 #include <libgen.h> // NOLINT | 12 #include <libgen.h> // NOLINT |
14 #include <limits.h> // NOLINT | |
15 #include <sys/mman.h> // NOLINT | 13 #include <sys/mman.h> // NOLINT |
16 #include <sys/stat.h> // NOLINT | 14 #include <sys/stat.h> // NOLINT |
| 15 #include <sys/types.h> // NOLINT |
17 #include <unistd.h> // NOLINT | 16 #include <unistd.h> // NOLINT |
18 | 17 |
19 #include "bin/builtin.h" | 18 #include "bin/builtin.h" |
20 #include "bin/fdutils.h" | |
21 #include "bin/log.h" | 19 #include "bin/log.h" |
22 | |
23 #include "platform/signal_blocker.h" | 20 #include "platform/signal_blocker.h" |
24 #include "platform/utils.h" | 21 #include "platform/utils.h" |
25 | 22 |
26 namespace dart { | 23 namespace dart { |
27 namespace bin { | 24 namespace bin { |
28 | 25 |
29 class FileHandle { | 26 class FileHandle { |
30 public: | 27 public: |
31 explicit FileHandle(int fd) : fd_(fd) { } | 28 explicit FileHandle(int fd) : fd_(fd) { } |
32 ~FileHandle() { } | 29 ~FileHandle() { } |
(...skipping 12 matching lines...) Expand all Loading... |
45 Close(); | 42 Close(); |
46 } | 43 } |
47 delete handle_; | 44 delete handle_; |
48 } | 45 } |
49 | 46 |
50 | 47 |
51 void File::Close() { | 48 void File::Close() { |
52 ASSERT(handle_->fd() >= 0); | 49 ASSERT(handle_->fd() >= 0); |
53 if (handle_->fd() == STDOUT_FILENO) { | 50 if (handle_->fd() == STDOUT_FILENO) { |
54 // If stdout, redirect fd to /dev/null. | 51 // If stdout, redirect fd to /dev/null. |
55 intptr_t null_fd = TEMP_FAILURE_RETRY(open("/dev/null", O_WRONLY)); | 52 int null_fd = NO_RETRY_EXPECTED(open("/dev/null", O_WRONLY)); |
56 ASSERT(null_fd >= 0); | 53 ASSERT(null_fd >= 0); |
57 VOID_TEMP_FAILURE_RETRY(dup2(null_fd, handle_->fd())); | 54 VOID_NO_RETRY_EXPECTED(dup2(null_fd, handle_->fd())); |
58 VOID_TEMP_FAILURE_RETRY(close(null_fd)); | 55 VOID_NO_RETRY_EXPECTED(close(null_fd)); |
59 } else { | 56 } else { |
60 intptr_t err = TEMP_FAILURE_RETRY(close(handle_->fd())); | 57 int err = NO_RETRY_EXPECTED(close(handle_->fd())); |
61 if (err != 0) { | 58 if (err != 0) { |
62 const int kBufferSize = 1024; | 59 const int kBufferSize = 1024; |
63 char error_message[kBufferSize]; | 60 char error_buf[kBufferSize]; |
64 Utils::StrError(errno, error_message, kBufferSize); | 61 Log::PrintErr("%s\n", Utils::StrError(errno, error_buf, kBufferSize)); |
65 Log::PrintErr("%s\n", error_message); | |
66 } | 62 } |
67 } | 63 } |
68 handle_->set_fd(kClosedFd); | 64 handle_->set_fd(kClosedFd); |
69 } | 65 } |
70 | 66 |
71 | 67 |
72 intptr_t File::GetFD() { | 68 intptr_t File::GetFD() { |
73 return handle_->fd(); | 69 return handle_->fd(); |
74 } | 70 } |
75 | 71 |
76 | 72 |
77 bool File::IsClosed() { | 73 bool File::IsClosed() { |
78 return handle_->fd() == kClosedFd; | 74 return handle_->fd() == kClosedFd; |
79 } | 75 } |
80 | 76 |
81 | 77 |
82 void* File::MapExecutable(intptr_t* len) { | 78 void* File::MapExecutable(intptr_t* len) { |
83 ASSERT(handle_->fd() >= 0); | 79 UNIMPLEMENTED(); |
84 intptr_t length = Length(); | 80 return NULL; |
85 void* addr = mmap(0, length, | |
86 PROT_READ | PROT_EXEC, MAP_PRIVATE, | |
87 handle_->fd(), 0); | |
88 if (addr == MAP_FAILED) { | |
89 *len = -1; | |
90 } else { | |
91 *len = length; | |
92 } | |
93 return addr; | |
94 } | 81 } |
95 | 82 |
96 | 83 |
97 int64_t File::Read(void* buffer, int64_t num_bytes) { | 84 int64_t File::Read(void* buffer, int64_t num_bytes) { |
98 ASSERT(handle_->fd() >= 0); | 85 ASSERT(handle_->fd() >= 0); |
99 return TEMP_FAILURE_RETRY(read(handle_->fd(), buffer, num_bytes)); | 86 return NO_RETRY_EXPECTED(read(handle_->fd(), buffer, num_bytes)); |
100 } | 87 } |
101 | 88 |
102 | 89 |
103 int64_t File::Write(const void* buffer, int64_t num_bytes) { | 90 int64_t File::Write(const void* buffer, int64_t num_bytes) { |
104 ASSERT(handle_->fd() >= 0); | 91 ASSERT(handle_->fd() >= 0); |
105 return TEMP_FAILURE_RETRY(write(handle_->fd(), buffer, num_bytes)); | 92 return NO_RETRY_EXPECTED(write(handle_->fd(), buffer, num_bytes)); |
106 } | 93 } |
107 | 94 |
108 | 95 |
109 int64_t File::Position() { | 96 int64_t File::Position() { |
110 ASSERT(handle_->fd() >= 0); | 97 ASSERT(handle_->fd() >= 0); |
111 return lseek(handle_->fd(), 0, SEEK_CUR); | 98 return NO_RETRY_EXPECTED(lseek(handle_->fd(), 0, SEEK_CUR)); |
112 } | 99 } |
113 | 100 |
114 | 101 |
115 bool File::SetPosition(int64_t position) { | 102 bool File::SetPosition(int64_t position) { |
116 ASSERT(handle_->fd() >= 0); | 103 ASSERT(handle_->fd() >= 0); |
117 return lseek(handle_->fd(), position, SEEK_SET) >= 0; | 104 return NO_RETRY_EXPECTED(lseek(handle_->fd(), position, SEEK_SET)) >= 0; |
118 } | 105 } |
119 | 106 |
120 | 107 |
121 bool File::Truncate(int64_t length) { | 108 bool File::Truncate(int64_t length) { |
122 ASSERT(handle_->fd() >= 0); | 109 ASSERT(handle_->fd() >= 0); |
123 return TEMP_FAILURE_RETRY(ftruncate(handle_->fd(), length)) != -1; | 110 return NO_RETRY_EXPECTED(ftruncate(handle_->fd(), length) != -1); |
124 } | 111 } |
125 | 112 |
126 | 113 |
127 bool File::Flush() { | 114 bool File::Flush() { |
128 ASSERT(handle_->fd() >= 0); | 115 ASSERT(handle_->fd() >= 0); |
129 return NO_RETRY_EXPECTED(fsync(handle_->fd())) != -1; | 116 return NO_RETRY_EXPECTED(fsync(handle_->fd())) != -1; |
130 } | 117 } |
131 | 118 |
132 | 119 |
133 bool File::Lock(File::LockType lock, int64_t start, int64_t end) { | 120 bool File::Lock(File::LockType lock, int64_t start, int64_t end) { |
(...skipping 16 matching lines...) Expand all Loading... |
150 return false; | 137 return false; |
151 } | 138 } |
152 fl.l_whence = SEEK_SET; | 139 fl.l_whence = SEEK_SET; |
153 fl.l_start = start; | 140 fl.l_start = start; |
154 fl.l_len = end == -1 ? 0 : end - start; | 141 fl.l_len = end == -1 ? 0 : end - start; |
155 int cmd = F_SETLK; | 142 int cmd = F_SETLK; |
156 if ((lock == File::kLockBlockingShared) || | 143 if ((lock == File::kLockBlockingShared) || |
157 (lock == File::kLockBlockingExclusive)) { | 144 (lock == File::kLockBlockingExclusive)) { |
158 cmd = F_SETLKW; | 145 cmd = F_SETLKW; |
159 } | 146 } |
160 return TEMP_FAILURE_RETRY(fcntl(handle_->fd(), cmd, &fl)) != -1; | 147 return NO_RETRY_EXPECTED(fcntl(handle_->fd(), cmd, &fl)) != -1; |
161 } | 148 } |
162 | 149 |
163 | 150 |
164 int64_t File::Length() { | 151 int64_t File::Length() { |
165 ASSERT(handle_->fd() >= 0); | 152 ASSERT(handle_->fd() >= 0); |
166 struct stat st; | 153 struct stat st; |
167 if (NO_RETRY_EXPECTED(fstat(handle_->fd(), &st)) == 0) { | 154 if (NO_RETRY_EXPECTED(fstat(handle_->fd(), &st)) == 0) { |
168 return st.st_size; | 155 return st.st_size; |
169 } | 156 } |
170 return -1; | 157 return -1; |
171 } | 158 } |
172 | 159 |
173 | 160 |
174 File* File::FileOpenW(const wchar_t* system_name, FileOpenMode mode) { | 161 File* File::FileOpenW(const wchar_t* system_name, FileOpenMode mode) { |
175 UNREACHABLE(); | 162 UNREACHABLE(); |
176 return NULL; | 163 return NULL; |
177 } | 164 } |
178 | 165 |
179 | 166 |
180 File* File::ScopedOpen(const char* name, FileOpenMode mode) { | 167 File* File::ScopedOpen(const char* name, FileOpenMode mode) { |
181 // Report errors for non-regular files. | 168 // Report errors for non-regular files. |
182 struct stat st; | 169 struct stat st; |
183 if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) { | 170 if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) { |
184 // Only accept regular files, character devices, and pipes. | 171 if (!S_ISREG(st.st_mode)) { |
185 if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode) && !S_ISFIFO(st.st_mode)) { | |
186 errno = (S_ISDIR(st.st_mode)) ? EISDIR : ENOENT; | 172 errno = (S_ISDIR(st.st_mode)) ? EISDIR : ENOENT; |
187 return NULL; | 173 return NULL; |
188 } | 174 } |
189 } | 175 } |
190 int flags = O_RDONLY; | 176 int flags = O_RDONLY; |
191 if ((mode & kWrite) != 0) { | 177 if ((mode & kWrite) != 0) { |
192 ASSERT((mode & kWriteOnly) == 0); | 178 ASSERT((mode & kWriteOnly) == 0); |
193 flags = (O_RDWR | O_CREAT); | 179 flags = (O_RDWR | O_CREAT); |
194 } | 180 } |
195 if ((mode & kWriteOnly) != 0) { | 181 if ((mode & kWriteOnly) != 0) { |
196 ASSERT((mode & kWrite) == 0); | 182 ASSERT((mode & kWrite) == 0); |
197 flags = (O_WRONLY | O_CREAT); | 183 flags = (O_WRONLY | O_CREAT); |
198 } | 184 } |
199 if ((mode & kTruncate) != 0) { | 185 if ((mode & kTruncate) != 0) { |
200 flags = flags | O_TRUNC; | 186 flags = flags | O_TRUNC; |
201 } | 187 } |
202 int fd = TEMP_FAILURE_RETRY(open(name, flags, 0666)); | 188 flags |= O_CLOEXEC; |
| 189 int fd = NO_RETRY_EXPECTED(open(name, flags, 0666)); |
203 if (fd < 0) { | 190 if (fd < 0) { |
204 return NULL; | 191 return NULL; |
205 } | 192 } |
206 FDUtils::SetCloseOnExec(fd); | |
207 if ((((mode & kWrite) != 0) && ((mode & kTruncate) == 0)) || | 193 if ((((mode & kWrite) != 0) && ((mode & kTruncate) == 0)) || |
208 (((mode & kWriteOnly) != 0) && ((mode & kTruncate) == 0))) { | 194 (((mode & kWriteOnly) != 0) && ((mode & kTruncate) == 0))) { |
209 int64_t position = lseek(fd, 0, SEEK_END); | 195 int64_t position = lseek(fd, 0, SEEK_END); |
210 if (position < 0) { | 196 if (position < 0) { |
211 return NULL; | 197 return NULL; |
212 } | 198 } |
213 } | 199 } |
214 return new File(new FileHandle(fd)); | 200 return new File(new FileHandle(fd)); |
215 } | 201 } |
216 | 202 |
(...skipping 13 matching lines...) Expand all Loading... |
230 struct stat st; | 216 struct stat st; |
231 if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) { | 217 if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) { |
232 return S_ISREG(st.st_mode); | 218 return S_ISREG(st.st_mode); |
233 } else { | 219 } else { |
234 return false; | 220 return false; |
235 } | 221 } |
236 } | 222 } |
237 | 223 |
238 | 224 |
239 bool File::Create(const char* name) { | 225 bool File::Create(const char* name) { |
240 int fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CREAT, 0666)); | 226 int fd = NO_RETRY_EXPECTED(open(name, O_RDONLY | O_CREAT | O_CLOEXEC, 0666)); |
241 if (fd < 0) { | 227 if (fd < 0) { |
242 return false; | 228 return false; |
243 } | 229 } |
244 return (close(fd) == 0); | 230 return (close(fd) == 0); |
245 } | 231 } |
246 | 232 |
247 | 233 |
248 bool File::CreateLink(const char* name, const char* target) { | 234 bool File::CreateLink(const char* name, const char* target) { |
249 int status = NO_RETRY_EXPECTED(symlink(target, name)); | 235 return NO_RETRY_EXPECTED(symlink(target, name)) == 0; |
250 return (status == 0); | |
251 } | 236 } |
252 | 237 |
253 | 238 |
254 bool File::Delete(const char* name) { | 239 bool File::Delete(const char* name) { |
255 File::Type type = File::GetType(name, true); | 240 File::Type type = File::GetType(name, true); |
256 if (type == kIsFile) { | 241 if (type == kIsFile) { |
257 return NO_RETRY_EXPECTED(unlink(name)) == 0; | 242 return NO_RETRY_EXPECTED(unlink(name)) == 0; |
258 } else if (type == kIsDirectory) { | 243 } else if (type == kIsDirectory) { |
259 errno = EISDIR; | 244 errno = EISDIR; |
260 } else { | 245 } else { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
294 } else if (type == kIsDirectory) { | 279 } else if (type == kIsDirectory) { |
295 errno = EISDIR; | 280 errno = EISDIR; |
296 } else { | 281 } else { |
297 errno = EINVAL; | 282 errno = EINVAL; |
298 } | 283 } |
299 return false; | 284 return false; |
300 } | 285 } |
301 | 286 |
302 | 287 |
303 bool File::Copy(const char* old_path, const char* new_path) { | 288 bool File::Copy(const char* old_path, const char* new_path) { |
304 File::Type type = File::GetType(old_path, true); | 289 UNIMPLEMENTED(); |
305 if (type == kIsFile) { | |
306 return copyfile(old_path, new_path, NULL, COPYFILE_ALL) == 0; | |
307 } else if (type == kIsDirectory) { | |
308 errno = EISDIR; | |
309 } else { | |
310 errno = ENOENT; | |
311 } | |
312 return false; | 290 return false; |
313 } | 291 } |
314 | 292 |
315 | 293 |
316 int64_t File::LengthFromPath(const char* name) { | 294 int64_t File::LengthFromPath(const char* name) { |
317 struct stat st; | 295 struct stat st; |
318 if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) { | 296 if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) { |
319 return st.st_size; | 297 return st.st_size; |
320 } | 298 } |
321 return -1; | 299 return -1; |
322 } | 300 } |
323 | 301 |
324 | 302 |
325 static int64_t TimespecToMilliseconds(const struct timespec& t) { | |
326 return static_cast<int64_t>(t.tv_sec) * 1000L + | |
327 static_cast<int64_t>(t.tv_nsec) / 1000000L; | |
328 } | |
329 | |
330 | |
331 void File::Stat(const char* name, int64_t* data) { | 303 void File::Stat(const char* name, int64_t* data) { |
332 struct stat st; | 304 struct stat st; |
333 if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) { | 305 if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) { |
334 if (S_ISREG(st.st_mode)) { | 306 if (S_ISREG(st.st_mode)) { |
335 data[kType] = kIsFile; | 307 data[kType] = kIsFile; |
336 } else if (S_ISDIR(st.st_mode)) { | 308 } else if (S_ISDIR(st.st_mode)) { |
337 data[kType] = kIsDirectory; | 309 data[kType] = kIsDirectory; |
338 } else if (S_ISLNK(st.st_mode)) { | 310 } else if (S_ISLNK(st.st_mode)) { |
339 data[kType] = kIsLink; | 311 data[kType] = kIsLink; |
340 } else { | 312 } else { |
341 data[kType] = kDoesNotExist; | 313 data[kType] = kDoesNotExist; |
342 } | 314 } |
343 data[kCreatedTime] = st.st_ctime; | 315 data[kCreatedTime] = static_cast<int64_t>(st.st_ctime) * 1000; |
344 data[kModifiedTime] = st.st_mtime; | 316 data[kModifiedTime] = static_cast<int64_t>(st.st_mtime) * 1000; |
345 data[kAccessedTime] = st.st_atime; | 317 data[kAccessedTime] = static_cast<int64_t>(st.st_atime) * 1000; |
346 data[kCreatedTime] = TimespecToMilliseconds(st.st_ctimespec); | |
347 data[kModifiedTime] = TimespecToMilliseconds(st.st_mtimespec); | |
348 data[kAccessedTime] = TimespecToMilliseconds(st.st_atimespec); | |
349 data[kMode] = st.st_mode; | 318 data[kMode] = st.st_mode; |
350 data[kSize] = st.st_size; | 319 data[kSize] = st.st_size; |
351 } else { | 320 } else { |
352 data[kType] = kDoesNotExist; | 321 data[kType] = kDoesNotExist; |
353 } | 322 } |
354 } | 323 } |
355 | 324 |
356 | 325 |
357 time_t File::LastModified(const char* name) { | 326 time_t File::LastModified(const char* name) { |
358 struct stat st; | 327 struct stat st; |
359 if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) { | 328 if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) { |
360 return st.st_mtime; | 329 return st.st_mtime; |
361 } | 330 } |
362 return -1; | 331 return -1; |
363 } | 332 } |
364 | 333 |
365 | 334 |
366 const char* File::LinkTarget(const char* pathname) { | 335 const char* File::LinkTarget(const char* pathname) { |
367 struct stat link_stats; | 336 struct stat link_stats; |
368 if (lstat(pathname, &link_stats) != 0) { | 337 if (lstat(pathname, &link_stats) != 0) { |
369 return NULL; | 338 return NULL; |
370 } | 339 } |
371 if (!S_ISLNK(link_stats.st_mode)) { | 340 if (!S_ISLNK(link_stats.st_mode)) { |
372 errno = ENOENT; | 341 errno = ENOENT; |
373 return NULL; | 342 return NULL; |
374 } | 343 } |
375 // Don't rely on the link_stats.st_size for the size of the link | 344 size_t target_size = link_stats.st_size; |
376 // target. The link might have changed before the readlink call. | 345 char* target_name = DartUtils::ScopedCString(target_size + 1); |
377 const int kBufferSize = 1024; | 346 ASSERT(target_name != NULL); |
378 char target[kBufferSize]; | 347 size_t read_size = readlink(pathname, target_name, target_size + 1); |
379 size_t target_size = TEMP_FAILURE_RETRY( | 348 if (read_size != target_size) { |
380 readlink(pathname, target, kBufferSize)); | |
381 if (target_size <= 0) { | |
382 return NULL; | 349 return NULL; |
383 } | 350 } |
384 char* target_name = DartUtils::ScopedCString(target_size + 1); | |
385 ASSERT(target_name != NULL); | |
386 memmove(target_name, target, target_size); | |
387 target_name[target_size] = '\0'; | 351 target_name[target_size] = '\0'; |
388 return target_name; | 352 return target_name; |
389 } | 353 } |
390 | 354 |
391 | 355 |
392 bool File::IsAbsolutePath(const char* pathname) { | 356 bool File::IsAbsolutePath(const char* pathname) { |
393 return (pathname != NULL && pathname[0] == '/'); | 357 return ((pathname != NULL) && (pathname[0] == '/')); |
394 } | 358 } |
395 | 359 |
396 | 360 |
397 const char* File::GetCanonicalPath(const char* pathname) { | 361 const char* File::GetCanonicalPath(const char* pathname) { |
398 char* abs_path = NULL; | 362 char* abs_path = NULL; |
399 if (pathname != NULL) { | 363 if (pathname != NULL) { |
400 // On some older MacOs versions the default behaviour of realpath allocating | |
401 // space for the resolved_path when a NULL is passed in does not seem to | |
402 // work, so we explicitly allocate space. | |
403 char* resolved_path = DartUtils::ScopedCString(PATH_MAX + 1); | 364 char* resolved_path = DartUtils::ScopedCString(PATH_MAX + 1); |
404 ASSERT(resolved_path != NULL); | 365 ASSERT(resolved_path != NULL); |
405 do { | 366 do { |
406 abs_path = realpath(pathname, resolved_path); | 367 abs_path = realpath(pathname, resolved_path); |
407 } while ((abs_path == NULL) && (errno == EINTR)); | 368 } while ((abs_path == NULL) && (errno == EINTR)); |
408 ASSERT((abs_path == NULL) || IsAbsolutePath(abs_path)); | 369 ASSERT((abs_path == NULL) || IsAbsolutePath(abs_path)); |
409 ASSERT((abs_path == NULL) || (abs_path == resolved_path)); | 370 ASSERT((abs_path == NULL) || (abs_path == resolved_path)); |
410 } | 371 } |
411 return abs_path; | 372 return abs_path; |
412 } | 373 } |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
481 } | 442 } |
482 return ((file_1_info.st_ino == file_2_info.st_ino) && | 443 return ((file_1_info.st_ino == file_2_info.st_ino) && |
483 (file_1_info.st_dev == file_2_info.st_dev)) ? | 444 (file_1_info.st_dev == file_2_info.st_dev)) ? |
484 File::kIdentical : | 445 File::kIdentical : |
485 File::kDifferent; | 446 File::kDifferent; |
486 } | 447 } |
487 | 448 |
488 } // namespace bin | 449 } // namespace bin |
489 } // namespace dart | 450 } // namespace dart |
490 | 451 |
491 #endif // defined(TARGET_OS_MACOS) | 452 #endif // defined(TARGET_OS_FUCHSIA) |
OLD | NEW |