| 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, 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, ×) == 0; | 428 return utime(name, ×) == 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, ×) == 0; | 442 return utime(name, ×) == 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 Loading... |
| 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) |
| OLD | NEW |