OLD | NEW |
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 Loading... |
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 Loading... |
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, |
| 276 const char* name, |
| 277 const char* target) { |
276 int status = NO_RETRY_EXPECTED(symlink(target, name)); | 278 int status = NO_RETRY_EXPECTED(symlink(target, name)); |
277 return (status == 0); | 279 return (status == 0); |
278 } | 280 } |
279 | 281 |
280 File::Type File::GetType(const char* pathname, bool follow_links) { | 282 File::Type File::GetType(Namespace* namespc, |
| 283 const char* pathname, |
| 284 bool follow_links) { |
281 struct stat entry_info; | 285 struct stat entry_info; |
282 int stat_success; | 286 int stat_success; |
283 if (follow_links) { | 287 if (follow_links) { |
284 stat_success = NO_RETRY_EXPECTED(stat(pathname, &entry_info)); | 288 stat_success = NO_RETRY_EXPECTED(stat(pathname, &entry_info)); |
285 } else { | 289 } else { |
286 stat_success = NO_RETRY_EXPECTED(lstat(pathname, &entry_info)); | 290 stat_success = NO_RETRY_EXPECTED(lstat(pathname, &entry_info)); |
287 } | 291 } |
288 if (stat_success == -1) { | 292 if (stat_success == -1) { |
289 return File::kDoesNotExist; | 293 return File::kDoesNotExist; |
290 } | 294 } |
291 if (S_ISDIR(entry_info.st_mode)) { | 295 if (S_ISDIR(entry_info.st_mode)) { |
292 return File::kIsDirectory; | 296 return File::kIsDirectory; |
293 } | 297 } |
294 if (S_ISREG(entry_info.st_mode)) { | 298 if (S_ISREG(entry_info.st_mode)) { |
295 return File::kIsFile; | 299 return File::kIsFile; |
296 } | 300 } |
297 if (S_ISLNK(entry_info.st_mode)) { | 301 if (S_ISLNK(entry_info.st_mode)) { |
298 return File::kIsLink; | 302 return File::kIsLink; |
299 } | 303 } |
300 return File::kDoesNotExist; | 304 return File::kDoesNotExist; |
301 } | 305 } |
302 | 306 |
303 static bool CheckTypeAndSetErrno(const char* name, | 307 static bool CheckTypeAndSetErrno(Namespace* namespc, |
| 308 const char* name, |
304 File::Type expected, | 309 File::Type expected, |
305 bool follow_links) { | 310 bool follow_links) { |
306 File::Type actual = File::GetType(name, follow_links); | 311 File::Type actual = File::GetType(namespc, name, follow_links); |
307 if (actual == expected) { | 312 if (actual == expected) { |
308 return true; | 313 return true; |
309 } | 314 } |
310 switch (actual) { | 315 switch (actual) { |
311 case File::kIsDirectory: | 316 case File::kIsDirectory: |
312 errno = EISDIR; | 317 errno = EISDIR; |
313 break; | 318 break; |
314 case File::kDoesNotExist: | 319 case File::kDoesNotExist: |
315 errno = ENOENT; | 320 errno = ENOENT; |
316 break; | 321 break; |
317 default: | 322 default: |
318 errno = EINVAL; | 323 errno = EINVAL; |
319 break; | 324 break; |
320 } | 325 } |
321 return false; | 326 return false; |
322 } | 327 } |
323 | 328 |
324 bool File::Delete(const char* name) { | 329 bool File::Delete(Namespace* namespc, const char* name) { |
325 return CheckTypeAndSetErrno(name, kIsFile, true) && | 330 return CheckTypeAndSetErrno(namespc, name, kIsFile, true) && |
326 (NO_RETRY_EXPECTED(unlink(name)) == 0); | 331 (NO_RETRY_EXPECTED(unlink(name)) == 0); |
327 } | 332 } |
328 | 333 |
329 bool File::DeleteLink(const char* name) { | 334 bool File::DeleteLink(Namespace* namespc, const char* name) { |
330 return CheckTypeAndSetErrno(name, kIsLink, false) && | 335 return CheckTypeAndSetErrno(namespc, name, kIsLink, false) && |
331 (NO_RETRY_EXPECTED(unlink(name)) == 0); | 336 (NO_RETRY_EXPECTED(unlink(name)) == 0); |
332 } | 337 } |
333 | 338 |
334 bool File::Rename(const char* old_path, const char* new_path) { | 339 bool File::Rename(Namespace* namespc, |
335 return CheckTypeAndSetErrno(old_path, kIsFile, true) && | 340 const char* old_path, |
| 341 const char* new_path) { |
| 342 return CheckTypeAndSetErrno(namespc, old_path, kIsFile, true) && |
336 (NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0); | 343 (NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0); |
337 } | 344 } |
338 | 345 |
339 bool File::RenameLink(const char* old_path, const char* new_path) { | 346 bool File::RenameLink(Namespace* namespc, |
340 return CheckTypeAndSetErrno(old_path, kIsLink, false) && | 347 const char* old_path, |
| 348 const char* new_path) { |
| 349 return CheckTypeAndSetErrno(namespc, old_path, kIsLink, false) && |
341 (NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0); | 350 (NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0); |
342 } | 351 } |
343 | 352 |
344 bool File::Copy(const char* old_path, const char* new_path) { | 353 bool File::Copy(Namespace* namespc, |
345 return CheckTypeAndSetErrno(old_path, kIsFile, true) && | 354 const char* old_path, |
| 355 const char* new_path) { |
| 356 return CheckTypeAndSetErrno(namespc, old_path, kIsFile, true) && |
346 (copyfile(old_path, new_path, NULL, COPYFILE_ALL) == 0); | 357 (copyfile(old_path, new_path, NULL, COPYFILE_ALL) == 0); |
347 } | 358 } |
348 | 359 |
349 static bool StatHelper(const char* name, struct stat* st) { | 360 static bool StatHelper(Namespace* namespc, const char* name, struct stat* st) { |
350 if (NO_RETRY_EXPECTED(stat(name, st)) != 0) { | 361 if (NO_RETRY_EXPECTED(stat(name, st)) != 0) { |
351 return false; | 362 return false; |
352 } | 363 } |
353 // Signal an error if it's a directory. | 364 // Signal an error if it's a directory. |
354 if (S_ISDIR(st->st_mode)) { | 365 if (S_ISDIR(st->st_mode)) { |
355 errno = EISDIR; | 366 errno = EISDIR; |
356 return false; | 367 return false; |
357 } | 368 } |
358 // Otherwise assume the caller knows what it's doing. | 369 // Otherwise assume the caller knows what it's doing. |
359 return true; | 370 return true; |
360 } | 371 } |
361 | 372 |
362 int64_t File::LengthFromPath(const char* name) { | 373 int64_t File::LengthFromPath(Namespace* namespc, const char* name) { |
363 struct stat st; | 374 struct stat st; |
364 if (!StatHelper(name, &st)) { | 375 if (!StatHelper(namespc, name, &st)) { |
365 return -1; | 376 return -1; |
366 } | 377 } |
367 return st.st_size; | 378 return st.st_size; |
368 } | 379 } |
369 | 380 |
370 static int64_t TimespecToMilliseconds(const struct timespec& t) { | 381 static int64_t TimespecToMilliseconds(const struct timespec& t) { |
371 return static_cast<int64_t>(t.tv_sec) * 1000L + | 382 return static_cast<int64_t>(t.tv_sec) * 1000L + |
372 static_cast<int64_t>(t.tv_nsec) / 1000000L; | 383 static_cast<int64_t>(t.tv_nsec) / 1000000L; |
373 } | 384 } |
374 | 385 |
375 void File::Stat(const char* name, int64_t* data) { | 386 void File::Stat(Namespace* namespc, const char* name, int64_t* data) { |
376 struct stat st; | 387 struct stat st; |
377 if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) { | 388 if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) { |
378 if (S_ISREG(st.st_mode)) { | 389 if (S_ISREG(st.st_mode)) { |
379 data[kType] = kIsFile; | 390 data[kType] = kIsFile; |
380 } else if (S_ISDIR(st.st_mode)) { | 391 } else if (S_ISDIR(st.st_mode)) { |
381 data[kType] = kIsDirectory; | 392 data[kType] = kIsDirectory; |
382 } else if (S_ISLNK(st.st_mode)) { | 393 } else if (S_ISLNK(st.st_mode)) { |
383 data[kType] = kIsLink; | 394 data[kType] = kIsLink; |
384 } else { | 395 } else { |
385 data[kType] = kDoesNotExist; | 396 data[kType] = kDoesNotExist; |
386 } | 397 } |
387 data[kCreatedTime] = st.st_ctime; | 398 data[kCreatedTime] = st.st_ctime; |
388 data[kModifiedTime] = st.st_mtime; | 399 data[kModifiedTime] = st.st_mtime; |
389 data[kAccessedTime] = st.st_atime; | 400 data[kAccessedTime] = st.st_atime; |
390 data[kCreatedTime] = TimespecToMilliseconds(st.st_ctimespec); | 401 data[kCreatedTime] = TimespecToMilliseconds(st.st_ctimespec); |
391 data[kModifiedTime] = TimespecToMilliseconds(st.st_mtimespec); | 402 data[kModifiedTime] = TimespecToMilliseconds(st.st_mtimespec); |
392 data[kAccessedTime] = TimespecToMilliseconds(st.st_atimespec); | 403 data[kAccessedTime] = TimespecToMilliseconds(st.st_atimespec); |
393 data[kMode] = st.st_mode; | 404 data[kMode] = st.st_mode; |
394 data[kSize] = st.st_size; | 405 data[kSize] = st.st_size; |
395 } else { | 406 } else { |
396 data[kType] = kDoesNotExist; | 407 data[kType] = kDoesNotExist; |
397 } | 408 } |
398 } | 409 } |
399 | 410 |
400 time_t File::LastModified(const char* name) { | 411 time_t File::LastModified(Namespace* namespc, const char* name) { |
401 struct stat st; | 412 struct stat st; |
402 if (!StatHelper(name, &st)) { | 413 if (!StatHelper(namespc, name, &st)) { |
403 return -1; | 414 return -1; |
404 } | 415 } |
405 return st.st_mtime; | 416 return st.st_mtime; |
406 } | 417 } |
407 | 418 |
408 time_t File::LastAccessed(const char* name) { | 419 time_t File::LastAccessed(Namespace* namespc, const char* name) { |
409 struct stat st; | 420 struct stat st; |
410 if (!StatHelper(name, &st)) { | 421 if (!StatHelper(namespc, name, &st)) { |
411 return -1; | 422 return -1; |
412 } | 423 } |
413 return st.st_atime; | 424 return st.st_atime; |
414 } | 425 } |
415 | 426 |
416 bool File::SetLastAccessed(const char* name, int64_t millis) { | 427 bool File::SetLastAccessed(Namespace* namespc, |
| 428 const char* name, |
| 429 int64_t millis) { |
417 // First get the current times. | 430 // First get the current times. |
418 struct stat st; | 431 struct stat st; |
419 if (!StatHelper(name, &st)) { | 432 if (!StatHelper(namespc, name, &st)) { |
420 return false; | 433 return false; |
421 } | 434 } |
422 | 435 |
423 // Set the new time: | 436 // Set the new time: |
424 struct utimbuf times; | 437 struct utimbuf times; |
425 times.actime = millis / kMillisecondsPerSecond; | 438 times.actime = millis / kMillisecondsPerSecond; |
426 times.modtime = st.st_mtime; | 439 times.modtime = st.st_mtime; |
427 return utime(name, ×) == 0; | 440 return utime(name, ×) == 0; |
428 } | 441 } |
429 | 442 |
430 bool File::SetLastModified(const char* name, int64_t millis) { | 443 bool File::SetLastModified(Namespace* namespc, |
| 444 const char* name, |
| 445 int64_t millis) { |
431 // First get the current times. | 446 // First get the current times. |
432 struct stat st; | 447 struct stat st; |
433 if (!StatHelper(name, &st)) { | 448 if (!StatHelper(namespc, name, &st)) { |
434 return false; | 449 return false; |
435 } | 450 } |
436 | 451 |
437 // Set the new time: | 452 // Set the new time: |
438 struct utimbuf times; | 453 struct utimbuf times; |
439 times.actime = st.st_atime; | 454 times.actime = st.st_atime; |
440 times.modtime = millis / kMillisecondsPerSecond; | 455 times.modtime = millis / kMillisecondsPerSecond; |
441 return utime(name, ×) == 0; | 456 return utime(name, ×) == 0; |
442 } | 457 } |
443 | 458 |
444 const char* File::LinkTarget(const char* pathname) { | 459 const char* File::LinkTarget(Namespace* namespc, const char* pathname) { |
445 struct stat link_stats; | 460 struct stat link_stats; |
446 if (lstat(pathname, &link_stats) != 0) { | 461 if (lstat(pathname, &link_stats) != 0) { |
447 return NULL; | 462 return NULL; |
448 } | 463 } |
449 if (!S_ISLNK(link_stats.st_mode)) { | 464 if (!S_ISLNK(link_stats.st_mode)) { |
450 errno = ENOENT; | 465 errno = ENOENT; |
451 return NULL; | 466 return NULL; |
452 } | 467 } |
453 // Don't rely on the link_stats.st_size for the size of the link | 468 // 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. | 469 // target. The link might have changed before the readlink call. |
455 const int kBufferSize = 1024; | 470 const int kBufferSize = 1024; |
456 char target[kBufferSize]; | 471 char target[kBufferSize]; |
457 size_t target_size = | 472 size_t target_size = |
458 TEMP_FAILURE_RETRY(readlink(pathname, target, kBufferSize)); | 473 TEMP_FAILURE_RETRY(readlink(pathname, target, kBufferSize)); |
459 if (target_size <= 0) { | 474 if (target_size <= 0) { |
460 return NULL; | 475 return NULL; |
461 } | 476 } |
462 char* target_name = DartUtils::ScopedCString(target_size + 1); | 477 char* target_name = DartUtils::ScopedCString(target_size + 1); |
463 ASSERT(target_name != NULL); | 478 ASSERT(target_name != NULL); |
464 memmove(target_name, target, target_size); | 479 memmove(target_name, target, target_size); |
465 target_name[target_size] = '\0'; | 480 target_name[target_size] = '\0'; |
466 return target_name; | 481 return target_name; |
467 } | 482 } |
468 | 483 |
469 bool File::IsAbsolutePath(const char* pathname) { | 484 bool File::IsAbsolutePath(const char* pathname) { |
470 return (pathname != NULL && pathname[0] == '/'); | 485 return (pathname != NULL && pathname[0] == '/'); |
471 } | 486 } |
472 | 487 |
473 const char* File::GetCanonicalPath(const char* pathname) { | 488 const char* File::GetCanonicalPath(Namespace* namespc, const char* pathname) { |
474 char* abs_path = NULL; | 489 char* abs_path = NULL; |
475 if (pathname != NULL) { | 490 if (pathname != NULL) { |
476 // On some older MacOs versions the default behaviour of realpath allocating | 491 // 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 | 492 // space for the resolved_path when a NULL is passed in does not seem to |
478 // work, so we explicitly allocate space. | 493 // work, so we explicitly allocate space. |
479 char* resolved_path = DartUtils::ScopedCString(PATH_MAX + 1); | 494 char* resolved_path = DartUtils::ScopedCString(PATH_MAX + 1); |
480 ASSERT(resolved_path != NULL); | 495 ASSERT(resolved_path != NULL); |
481 do { | 496 do { |
482 abs_path = realpath(pathname, resolved_path); | 497 abs_path = realpath(pathname, resolved_path); |
483 } while ((abs_path == NULL) && (errno == EINTR)); | 498 } while ((abs_path == NULL) && (errno == EINTR)); |
(...skipping 26 matching lines...) Expand all Loading... |
510 } | 525 } |
511 if (S_ISSOCK(buf.st_mode)) { | 526 if (S_ISSOCK(buf.st_mode)) { |
512 return kSocket; | 527 return kSocket; |
513 } | 528 } |
514 if (S_ISREG(buf.st_mode)) { | 529 if (S_ISREG(buf.st_mode)) { |
515 return kFile; | 530 return kFile; |
516 } | 531 } |
517 return kOther; | 532 return kOther; |
518 } | 533 } |
519 | 534 |
520 File::Identical File::AreIdentical(const char* file_1, const char* file_2) { | 535 File::Identical File::AreIdentical(Namespace* namespc, |
| 536 const char* file_1, |
| 537 const char* file_2) { |
521 struct stat file_1_info; | 538 struct stat file_1_info; |
522 struct stat file_2_info; | 539 struct stat file_2_info; |
523 if ((NO_RETRY_EXPECTED(lstat(file_1, &file_1_info)) == -1) || | 540 if ((NO_RETRY_EXPECTED(lstat(file_1, &file_1_info)) == -1) || |
524 (NO_RETRY_EXPECTED(lstat(file_2, &file_2_info)) == -1)) { | 541 (NO_RETRY_EXPECTED(lstat(file_2, &file_2_info)) == -1)) { |
525 return File::kError; | 542 return File::kError; |
526 } | 543 } |
527 return ((file_1_info.st_ino == file_2_info.st_ino) && | 544 return ((file_1_info.st_ino == file_2_info.st_ino) && |
528 (file_1_info.st_dev == file_2_info.st_dev)) | 545 (file_1_info.st_dev == file_2_info.st_dev)) |
529 ? File::kIdentical | 546 ? File::kIdentical |
530 : File::kDifferent; | 547 : File::kDifferent; |
531 } | 548 } |
532 | 549 |
533 } // namespace bin | 550 } // namespace bin |
534 } // namespace dart | 551 } // namespace dart |
535 | 552 |
536 #endif // defined(HOST_OS_MACOS) | 553 #endif // defined(HOST_OS_MACOS) |
OLD | NEW |