Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(225)

Side by Side Diff: runtime/bin/file_macos.cc

Issue 3001963002: [dart:io] Namespaces for file IO (Closed)
Patch Set: Fuchsia fix Created 3 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/bin/file_linux.cc ('k') | runtime/bin/file_patch.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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(HOST_OS_MACOS) 6 #if defined(HOST_OS_MACOS)
7 7
8 #include "bin/file.h" 8 #include "bin/file.h"
9 9
10 #include <copyfile.h> // NOLINT 10 #include <copyfile.h> // NOLINT
11 #include <errno.h> // NOLINT 11 #include <errno.h> // NOLINT
12 #include <fcntl.h> // NOLINT 12 #include <fcntl.h> // NOLINT
13 #include <libgen.h> // NOLINT 13 #include <libgen.h> // NOLINT
14 #include <limits.h> // NOLINT 14 #include <limits.h> // NOLINT
15 #include <sys/mman.h> // NOLINT 15 #include <sys/mman.h> // NOLINT
16 #include <sys/stat.h> // NOLINT 16 #include <sys/stat.h> // NOLINT
17 #include <unistd.h> // NOLINT 17 #include <unistd.h> // NOLINT
18 #include <utime.h> // NOLINT 18 #include <utime.h> // NOLINT
19 19
20 #include "bin/builtin.h" 20 #include "bin/builtin.h"
21 #include "bin/fdutils.h" 21 #include "bin/fdutils.h"
22 #include "bin/log.h" 22 #include "bin/log.h"
23 23 #include "bin/namespace.h"
24 #include "platform/signal_blocker.h" 24 #include "platform/signal_blocker.h"
25 #include "platform/utils.h" 25 #include "platform/utils.h"
26 26
27 namespace dart { 27 namespace dart {
28 namespace bin { 28 namespace bin {
29 29
30 class FileHandle { 30 class FileHandle {
31 public: 31 public:
32 explicit FileHandle(int fd) : fd_(fd) {} 32 explicit FileHandle(int fd) : fd_(fd) {}
33 ~FileHandle() {} 33 ~FileHandle() {}
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
191 return st.st_size; 191 return st.st_size;
192 } 192 }
193 return -1; 193 return -1;
194 } 194 }
195 195
196 File* File::FileOpenW(const wchar_t* system_name, FileOpenMode mode) { 196 File* File::FileOpenW(const wchar_t* system_name, FileOpenMode mode) {
197 UNREACHABLE(); 197 UNREACHABLE();
198 return NULL; 198 return NULL;
199 } 199 }
200 200
201 File* File::Open(const char* name, FileOpenMode mode) { 201 File* File::Open(Namespace* namespc, const char* name, FileOpenMode mode) {
202 // Report errors for non-regular files. 202 // Report errors for non-regular files.
203 struct stat st; 203 struct stat st;
204 if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) { 204 if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) {
205 // Only accept regular files, character devices, and pipes. 205 // Only accept regular files, character devices, and pipes.
206 if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode) && !S_ISFIFO(st.st_mode)) { 206 if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode) && !S_ISFIFO(st.st_mode)) {
207 errno = (S_ISDIR(st.st_mode)) ? EISDIR : ENOENT; 207 errno = (S_ISDIR(st.st_mode)) ? EISDIR : ENOENT;
208 return NULL; 208 return NULL;
209 } 209 }
210 } 210 }
211 int flags = O_RDONLY; 211 int flags = O_RDONLY;
(...skipping 20 matching lines...) Expand all
232 return NULL; 232 return NULL;
233 } 233 }
234 } 234 }
235 return new File(new FileHandle(fd)); 235 return new File(new FileHandle(fd));
236 } 236 }
237 237
238 File* File::OpenStdio(int fd) { 238 File* File::OpenStdio(int fd) {
239 return ((fd < 0) || (2 < fd)) ? NULL : new File(new FileHandle(fd)); 239 return ((fd < 0) || (2 < fd)) ? NULL : new File(new FileHandle(fd));
240 } 240 }
241 241
242 bool File::Exists(const char* name) { 242 bool File::Exists(Namespace* namespc, const char* name) {
243 struct stat st; 243 struct stat st;
244 if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) { 244 if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) {
245 // Everything but a directory and a link is a file to Dart. 245 // Everything but a directory and a link is a file to Dart.
246 return !S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode); 246 return !S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode);
247 } else { 247 } else {
248 return false; 248 return false;
249 } 249 }
250 } 250 }
251 251
252 bool File::Create(const char* name) { 252 bool File::Create(Namespace* namespc, const char* name) {
253 int fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CREAT, 0666)); 253 int fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CREAT, 0666));
254 if (fd < 0) { 254 if (fd < 0) {
255 return false; 255 return false;
256 } 256 }
257 // File.create returns a File, so we shouldn't be giving the illusion that the 257 // File.create returns a File, so we shouldn't be giving the illusion that the
258 // call has created a file or that a file already exists if there is already 258 // call has created a file or that a file already exists if there is already
259 // an entity at the same path that is a directory or a link. 259 // an entity at the same path that is a directory or a link.
260 bool is_file = true; 260 bool is_file = true;
261 struct stat st; 261 struct stat st;
262 if (NO_RETRY_EXPECTED(fstat(fd, &st)) == 0) { 262 if (NO_RETRY_EXPECTED(fstat(fd, &st)) == 0) {
263 if (S_ISDIR(st.st_mode)) { 263 if (S_ISDIR(st.st_mode)) {
264 errno = EISDIR; 264 errno = EISDIR;
265 is_file = false; 265 is_file = false;
266 } else if (S_ISLNK(st.st_mode)) { 266 } else if (S_ISLNK(st.st_mode)) {
267 errno = ENOENT; 267 errno = ENOENT;
268 is_file = false; 268 is_file = false;
269 } 269 }
270 } 270 }
271 FDUtils::SaveErrorAndClose(fd); 271 FDUtils::SaveErrorAndClose(fd);
272 return is_file; 272 return is_file;
273 } 273 }
274 274
275 bool File::CreateLink(const char* name, const char* target) { 275 bool File::CreateLink(Namespace* namespc, const char* name, const char* target) {
276 int status = NO_RETRY_EXPECTED(symlink(target, name)); 276 int status = NO_RETRY_EXPECTED(symlink(target, name));
277 return (status == 0); 277 return (status == 0);
278 } 278 }
279 279
280 File::Type File::GetType(const char* pathname, bool follow_links) { 280 File::Type File::GetType(Namespace* namespc, const char* pathname, bool follow_l inks) {
281 struct stat entry_info; 281 struct stat entry_info;
282 int stat_success; 282 int stat_success;
283 if (follow_links) { 283 if (follow_links) {
284 stat_success = NO_RETRY_EXPECTED(stat(pathname, &entry_info)); 284 stat_success = NO_RETRY_EXPECTED(stat(pathname, &entry_info));
285 } else { 285 } else {
286 stat_success = NO_RETRY_EXPECTED(lstat(pathname, &entry_info)); 286 stat_success = NO_RETRY_EXPECTED(lstat(pathname, &entry_info));
287 } 287 }
288 if (stat_success == -1) { 288 if (stat_success == -1) {
289 return File::kDoesNotExist; 289 return File::kDoesNotExist;
290 } 290 }
291 if (S_ISDIR(entry_info.st_mode)) { 291 if (S_ISDIR(entry_info.st_mode)) {
292 return File::kIsDirectory; 292 return File::kIsDirectory;
293 } 293 }
294 if (S_ISREG(entry_info.st_mode)) { 294 if (S_ISREG(entry_info.st_mode)) {
295 return File::kIsFile; 295 return File::kIsFile;
296 } 296 }
297 if (S_ISLNK(entry_info.st_mode)) { 297 if (S_ISLNK(entry_info.st_mode)) {
298 return File::kIsLink; 298 return File::kIsLink;
299 } 299 }
300 return File::kDoesNotExist; 300 return File::kDoesNotExist;
301 } 301 }
302 302
303 static bool CheckTypeAndSetErrno(const char* name, 303 static bool CheckTypeAndSetErrno(Namespace* namespc,
304 const char* name,
304 File::Type expected, 305 File::Type expected,
305 bool follow_links) { 306 bool follow_links) {
306 File::Type actual = File::GetType(name, follow_links); 307 File::Type actual = File::GetType(namespc, name, follow_links);
307 if (actual == expected) { 308 if (actual == expected) {
308 return true; 309 return true;
309 } 310 }
310 switch (actual) { 311 switch (actual) {
311 case File::kIsDirectory: 312 case File::kIsDirectory:
312 errno = EISDIR; 313 errno = EISDIR;
313 break; 314 break;
314 case File::kDoesNotExist: 315 case File::kDoesNotExist:
315 errno = ENOENT; 316 errno = ENOENT;
316 break; 317 break;
317 default: 318 default:
318 errno = EINVAL; 319 errno = EINVAL;
319 break; 320 break;
320 } 321 }
321 return false; 322 return false;
322 } 323 }
323 324
324 bool File::Delete(const char* name) { 325 bool File::Delete(Namespace* namespc, const char* name) {
325 return CheckTypeAndSetErrno(name, kIsFile, true) && 326 return CheckTypeAndSetErrno(namespc, name, kIsFile, true) &&
326 (NO_RETRY_EXPECTED(unlink(name)) == 0); 327 (NO_RETRY_EXPECTED(unlink(name)) == 0);
327 } 328 }
328 329
329 bool File::DeleteLink(const char* name) { 330 bool File::DeleteLink(Namespace* namespc, const char* name) {
330 return CheckTypeAndSetErrno(name, kIsLink, false) && 331 return CheckTypeAndSetErrno(namespc, name, kIsLink, false) &&
331 (NO_RETRY_EXPECTED(unlink(name)) == 0); 332 (NO_RETRY_EXPECTED(unlink(name)) == 0);
332 } 333 }
333 334
334 bool File::Rename(const char* old_path, const char* new_path) { 335 bool File::Rename(Namespace* namespc, const char* old_path, const char* new_path ) {
335 return CheckTypeAndSetErrno(old_path, kIsFile, true) && 336 return CheckTypeAndSetErrno(namespc, old_path, kIsFile, true) &&
336 (NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0); 337 (NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0);
337 } 338 }
338 339
339 bool File::RenameLink(const char* old_path, const char* new_path) { 340 bool File::RenameLink(Namespace* namespc, const char* old_path, const char* new_ path) {
340 return CheckTypeAndSetErrno(old_path, kIsLink, false) && 341 return CheckTypeAndSetErrno(namespc, old_path, kIsLink, false) &&
341 (NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0); 342 (NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0);
342 } 343 }
343 344
344 bool File::Copy(const char* old_path, const char* new_path) { 345 bool File::Copy(Namespace* namespc, const char* old_path, const char* new_path) {
345 return CheckTypeAndSetErrno(old_path, kIsFile, true) && 346 return CheckTypeAndSetErrno(namespc, old_path, kIsFile, true) &&
346 (copyfile(old_path, new_path, NULL, COPYFILE_ALL) == 0); 347 (copyfile(old_path, new_path, NULL, COPYFILE_ALL) == 0);
347 } 348 }
348 349
349 static bool StatHelper(const char* name, struct stat* st) { 350 static bool StatHelper(Namespace* namespc, const char* name, struct stat* st) {
350 if (NO_RETRY_EXPECTED(stat(name, st)) != 0) { 351 if (NO_RETRY_EXPECTED(stat(name, st)) != 0) {
351 return false; 352 return false;
352 } 353 }
353 // Signal an error if it's a directory. 354 // Signal an error if it's a directory.
354 if (S_ISDIR(st->st_mode)) { 355 if (S_ISDIR(st->st_mode)) {
355 errno = EISDIR; 356 errno = EISDIR;
356 return false; 357 return false;
357 } 358 }
358 // Otherwise assume the caller knows what it's doing. 359 // Otherwise assume the caller knows what it's doing.
359 return true; 360 return true;
360 } 361 }
361 362
362 int64_t File::LengthFromPath(const char* name) { 363 int64_t File::LengthFromPath(Namespace* namespc, const char* name) {
363 struct stat st; 364 struct stat st;
364 if (!StatHelper(name, &st)) { 365 if (!StatHelper(namespc, name, &st)) {
365 return -1; 366 return -1;
366 } 367 }
367 return st.st_size; 368 return st.st_size;
368 } 369 }
369 370
370 static int64_t TimespecToMilliseconds(const struct timespec& t) { 371 static int64_t TimespecToMilliseconds(const struct timespec& t) {
371 return static_cast<int64_t>(t.tv_sec) * 1000L + 372 return static_cast<int64_t>(t.tv_sec) * 1000L +
372 static_cast<int64_t>(t.tv_nsec) / 1000000L; 373 static_cast<int64_t>(t.tv_nsec) / 1000000L;
373 } 374 }
374 375
375 void File::Stat(const char* name, int64_t* data) { 376 void File::Stat(Namespace* namespc, const char* name, int64_t* data) {
376 struct stat st; 377 struct stat st;
377 if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) { 378 if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) {
378 if (S_ISREG(st.st_mode)) { 379 if (S_ISREG(st.st_mode)) {
379 data[kType] = kIsFile; 380 data[kType] = kIsFile;
380 } else if (S_ISDIR(st.st_mode)) { 381 } else if (S_ISDIR(st.st_mode)) {
381 data[kType] = kIsDirectory; 382 data[kType] = kIsDirectory;
382 } else if (S_ISLNK(st.st_mode)) { 383 } else if (S_ISLNK(st.st_mode)) {
383 data[kType] = kIsLink; 384 data[kType] = kIsLink;
384 } else { 385 } else {
385 data[kType] = kDoesNotExist; 386 data[kType] = kDoesNotExist;
386 } 387 }
387 data[kCreatedTime] = st.st_ctime; 388 data[kCreatedTime] = st.st_ctime;
388 data[kModifiedTime] = st.st_mtime; 389 data[kModifiedTime] = st.st_mtime;
389 data[kAccessedTime] = st.st_atime; 390 data[kAccessedTime] = st.st_atime;
390 data[kCreatedTime] = TimespecToMilliseconds(st.st_ctimespec); 391 data[kCreatedTime] = TimespecToMilliseconds(st.st_ctimespec);
391 data[kModifiedTime] = TimespecToMilliseconds(st.st_mtimespec); 392 data[kModifiedTime] = TimespecToMilliseconds(st.st_mtimespec);
392 data[kAccessedTime] = TimespecToMilliseconds(st.st_atimespec); 393 data[kAccessedTime] = TimespecToMilliseconds(st.st_atimespec);
393 data[kMode] = st.st_mode; 394 data[kMode] = st.st_mode;
394 data[kSize] = st.st_size; 395 data[kSize] = st.st_size;
395 } else { 396 } else {
396 data[kType] = kDoesNotExist; 397 data[kType] = kDoesNotExist;
397 } 398 }
398 } 399 }
399 400
400 time_t File::LastModified(const char* name) { 401 time_t File::LastModified(Namespace* namespc, const char* name) {
401 struct stat st; 402 struct stat st;
402 if (!StatHelper(name, &st)) { 403 if (!StatHelper(namespc, name, &st)) {
403 return -1; 404 return -1;
404 } 405 }
405 return st.st_mtime; 406 return st.st_mtime;
406 } 407 }
407 408
408 time_t File::LastAccessed(const char* name) { 409 time_t File::LastAccessed(Namespace* namespc, const char* name) {
409 struct stat st; 410 struct stat st;
410 if (!StatHelper(name, &st)) { 411 if (!StatHelper(namespc, name, &st)) {
411 return -1; 412 return -1;
412 } 413 }
413 return st.st_atime; 414 return st.st_atime;
414 } 415 }
415 416
416 bool File::SetLastAccessed(const char* name, int64_t millis) { 417 bool File::SetLastAccessed(Namespace* namespc, const char* name, int64_t millis) {
417 // First get the current times. 418 // First get the current times.
418 struct stat st; 419 struct stat st;
419 if (!StatHelper(name, &st)) { 420 if (!StatHelper(namespc, name, &st)) {
420 return false; 421 return false;
421 } 422 }
422 423
423 // Set the new time: 424 // Set the new time:
424 struct utimbuf times; 425 struct utimbuf times;
425 times.actime = millis / kMillisecondsPerSecond; 426 times.actime = millis / kMillisecondsPerSecond;
426 times.modtime = st.st_mtime; 427 times.modtime = st.st_mtime;
427 return utime(name, &times) == 0; 428 return utime(name, &times) == 0;
428 } 429 }
429 430
430 bool File::SetLastModified(const char* name, int64_t millis) { 431 bool File::SetLastModified(Namespace* namespc, const char* name, int64_t millis) {
431 // First get the current times. 432 // First get the current times.
432 struct stat st; 433 struct stat st;
433 if (!StatHelper(name, &st)) { 434 if (!StatHelper(namespc, name, &st)) {
434 return false; 435 return false;
435 } 436 }
436 437
437 // Set the new time: 438 // Set the new time:
438 struct utimbuf times; 439 struct utimbuf times;
439 times.actime = st.st_atime; 440 times.actime = st.st_atime;
440 times.modtime = millis / kMillisecondsPerSecond; 441 times.modtime = millis / kMillisecondsPerSecond;
441 return utime(name, &times) == 0; 442 return utime(name, &times) == 0;
442 } 443 }
443 444
444 const char* File::LinkTarget(const char* pathname) { 445 const char* File::LinkTarget(Namespace* namespc, const char* pathname) {
445 struct stat link_stats; 446 struct stat link_stats;
446 if (lstat(pathname, &link_stats) != 0) { 447 if (lstat(pathname, &link_stats) != 0) {
447 return NULL; 448 return NULL;
448 } 449 }
449 if (!S_ISLNK(link_stats.st_mode)) { 450 if (!S_ISLNK(link_stats.st_mode)) {
450 errno = ENOENT; 451 errno = ENOENT;
451 return NULL; 452 return NULL;
452 } 453 }
453 // Don't rely on the link_stats.st_size for the size of the link 454 // Don't rely on the link_stats.st_size for the size of the link
454 // target. The link might have changed before the readlink call. 455 // target. The link might have changed before the readlink call.
455 const int kBufferSize = 1024; 456 const int kBufferSize = 1024;
456 char target[kBufferSize]; 457 char target[kBufferSize];
457 size_t target_size = 458 size_t target_size =
458 TEMP_FAILURE_RETRY(readlink(pathname, target, kBufferSize)); 459 TEMP_FAILURE_RETRY(readlink(pathname, target, kBufferSize));
459 if (target_size <= 0) { 460 if (target_size <= 0) {
460 return NULL; 461 return NULL;
461 } 462 }
462 char* target_name = DartUtils::ScopedCString(target_size + 1); 463 char* target_name = DartUtils::ScopedCString(target_size + 1);
463 ASSERT(target_name != NULL); 464 ASSERT(target_name != NULL);
464 memmove(target_name, target, target_size); 465 memmove(target_name, target, target_size);
465 target_name[target_size] = '\0'; 466 target_name[target_size] = '\0';
466 return target_name; 467 return target_name;
467 } 468 }
468 469
469 bool File::IsAbsolutePath(const char* pathname) { 470 bool File::IsAbsolutePath(const char* pathname) {
470 return (pathname != NULL && pathname[0] == '/'); 471 return (pathname != NULL && pathname[0] == '/');
471 } 472 }
472 473
473 const char* File::GetCanonicalPath(const char* pathname) { 474 const char* File::GetCanonicalPath(Namespace* namespc, const char* pathname) {
474 char* abs_path = NULL; 475 char* abs_path = NULL;
475 if (pathname != NULL) { 476 if (pathname != NULL) {
476 // On some older MacOs versions the default behaviour of realpath allocating 477 // On some older MacOs versions the default behaviour of realpath allocating
477 // space for the resolved_path when a NULL is passed in does not seem to 478 // space for the resolved_path when a NULL is passed in does not seem to
478 // work, so we explicitly allocate space. 479 // work, so we explicitly allocate space.
479 char* resolved_path = DartUtils::ScopedCString(PATH_MAX + 1); 480 char* resolved_path = DartUtils::ScopedCString(PATH_MAX + 1);
480 ASSERT(resolved_path != NULL); 481 ASSERT(resolved_path != NULL);
481 do { 482 do {
482 abs_path = realpath(pathname, resolved_path); 483 abs_path = realpath(pathname, resolved_path);
483 } while ((abs_path == NULL) && (errno == EINTR)); 484 } while ((abs_path == NULL) && (errno == EINTR));
(...skipping 26 matching lines...) Expand all
510 } 511 }
511 if (S_ISSOCK(buf.st_mode)) { 512 if (S_ISSOCK(buf.st_mode)) {
512 return kSocket; 513 return kSocket;
513 } 514 }
514 if (S_ISREG(buf.st_mode)) { 515 if (S_ISREG(buf.st_mode)) {
515 return kFile; 516 return kFile;
516 } 517 }
517 return kOther; 518 return kOther;
518 } 519 }
519 520
520 File::Identical File::AreIdentical(const char* file_1, const char* file_2) { 521 File::Identical File::AreIdentical(Namespace* namespc, const char* file_1, const char* file_2) {
521 struct stat file_1_info; 522 struct stat file_1_info;
522 struct stat file_2_info; 523 struct stat file_2_info;
523 if ((NO_RETRY_EXPECTED(lstat(file_1, &file_1_info)) == -1) || 524 if ((NO_RETRY_EXPECTED(lstat(file_1, &file_1_info)) == -1) ||
524 (NO_RETRY_EXPECTED(lstat(file_2, &file_2_info)) == -1)) { 525 (NO_RETRY_EXPECTED(lstat(file_2, &file_2_info)) == -1)) {
525 return File::kError; 526 return File::kError;
526 } 527 }
527 return ((file_1_info.st_ino == file_2_info.st_ino) && 528 return ((file_1_info.st_ino == file_2_info.st_ino) &&
528 (file_1_info.st_dev == file_2_info.st_dev)) 529 (file_1_info.st_dev == file_2_info.st_dev))
529 ? File::kIdentical 530 ? File::kIdentical
530 : File::kDifferent; 531 : File::kDifferent;
531 } 532 }
532 533
533 } // namespace bin 534 } // namespace bin
534 } // namespace dart 535 } // namespace dart
535 536
536 #endif // defined(HOST_OS_MACOS) 537 #endif // defined(HOST_OS_MACOS)
OLDNEW
« no previous file with comments | « runtime/bin/file_linux.cc ('k') | runtime/bin/file_patch.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698