| 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(TARGET_OS_ANDROID) | 6 #if defined(TARGET_OS_ANDROID) |
| 7 | 7 |
| 8 #include "bin/file.h" | 8 #include "bin/file.h" |
| 9 | 9 |
| 10 #include <errno.h> // NOLINT | 10 #include <errno.h> // NOLINT |
| (...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 258 return is_file; | 258 return is_file; |
| 259 } | 259 } |
| 260 | 260 |
| 261 | 261 |
| 262 bool File::CreateLink(const char* name, const char* target) { | 262 bool File::CreateLink(const char* name, const char* target) { |
| 263 int status = NO_RETRY_EXPECTED(symlink(target, name)); | 263 int status = NO_RETRY_EXPECTED(symlink(target, name)); |
| 264 return (status == 0); | 264 return (status == 0); |
| 265 } | 265 } |
| 266 | 266 |
| 267 | 267 |
| 268 bool File::Delete(const char* name) { | 268 File::Type File::GetType(const char* pathname, bool follow_links) { |
| 269 File::Type type = File::GetType(name, true); | 269 struct stat entry_info; |
| 270 if (type == kIsFile) { | 270 int stat_success; |
| 271 return NO_RETRY_EXPECTED(unlink(name)) == 0; | 271 if (follow_links) { |
| 272 } else if (type == kIsDirectory) { | 272 stat_success = NO_RETRY_EXPECTED(stat(pathname, &entry_info)); |
| 273 errno = EISDIR; | |
| 274 } else { | 273 } else { |
| 275 errno = ENOENT; | 274 stat_success = NO_RETRY_EXPECTED(lstat(pathname, &entry_info)); |
| 275 } |
| 276 if (stat_success == -1) { |
| 277 return File::kDoesNotExist; |
| 278 } |
| 279 if (S_ISDIR(entry_info.st_mode)) { |
| 280 return File::kIsDirectory; |
| 281 } |
| 282 if (S_ISREG(entry_info.st_mode)) { |
| 283 return File::kIsFile; |
| 284 } |
| 285 if (S_ISLNK(entry_info.st_mode)) { |
| 286 return File::kIsLink; |
| 287 } |
| 288 return File::kDoesNotExist; |
| 289 } |
| 290 |
| 291 |
| 292 static bool CheckTypeAndSetErrno(const char* name, |
| 293 File::Type expected, |
| 294 bool follow_links) { |
| 295 File::Type actual = File::GetType(name, follow_links); |
| 296 if (actual == expected) { |
| 297 return true; |
| 298 } |
| 299 switch (actual) { |
| 300 case File::kIsDirectory: |
| 301 errno = EISDIR; |
| 302 break; |
| 303 case File::kDoesNotExist: |
| 304 errno = ENOENT; |
| 305 break; |
| 306 default: |
| 307 errno = EINVAL; |
| 308 break; |
| 276 } | 309 } |
| 277 return false; | 310 return false; |
| 278 } | 311 } |
| 279 | 312 |
| 280 | 313 |
| 314 bool File::Delete(const char* name) { |
| 315 return CheckTypeAndSetErrno(name, kIsFile, true) && |
| 316 (NO_RETRY_EXPECTED(unlink(name)) == 0); |
| 317 } |
| 318 |
| 319 |
| 281 bool File::DeleteLink(const char* name) { | 320 bool File::DeleteLink(const char* name) { |
| 282 File::Type type = File::GetType(name, false); | 321 return CheckTypeAndSetErrno(name, kIsLink, false) && |
| 283 if (type == kIsLink) { | 322 (NO_RETRY_EXPECTED(unlink(name)) == 0); |
| 284 return NO_RETRY_EXPECTED(unlink(name)) == 0; | |
| 285 } | |
| 286 errno = EINVAL; | |
| 287 return false; | |
| 288 } | 323 } |
| 289 | 324 |
| 290 | 325 |
| 291 bool File::Rename(const char* old_path, const char* new_path) { | 326 bool File::Rename(const char* old_path, const char* new_path) { |
| 292 File::Type type = File::GetType(old_path, true); | 327 return CheckTypeAndSetErrno(old_path, kIsFile, true) && |
| 293 if (type == kIsFile) { | 328 (NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0); |
| 294 return NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0; | |
| 295 } else if (type == kIsDirectory) { | |
| 296 errno = EISDIR; | |
| 297 } else { | |
| 298 errno = ENOENT; | |
| 299 } | |
| 300 return false; | |
| 301 } | 329 } |
| 302 | 330 |
| 303 | 331 |
| 304 bool File::RenameLink(const char* old_path, const char* new_path) { | 332 bool File::RenameLink(const char* old_path, const char* new_path) { |
| 305 File::Type type = File::GetType(old_path, false); | 333 return CheckTypeAndSetErrno(old_path, kIsLink, false) && |
| 306 if (type == kIsLink) { | 334 (NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0); |
| 307 return NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0; | |
| 308 } else if (type == kIsDirectory) { | |
| 309 errno = EISDIR; | |
| 310 } else { | |
| 311 errno = EINVAL; | |
| 312 } | |
| 313 return false; | |
| 314 } | 335 } |
| 315 | 336 |
| 316 | 337 |
| 317 bool File::Copy(const char* old_path, const char* new_path) { | 338 bool File::Copy(const char* old_path, const char* new_path) { |
| 318 File::Type type = File::GetType(old_path, true); | 339 if (!CheckTypeAndSetErrno(old_path, kIsFile, true)) { |
| 319 if (type == kIsFile) { | 340 return false; |
| 320 struct stat st; | 341 } |
| 321 if (NO_RETRY_EXPECTED(stat(old_path, &st)) != 0) { | 342 struct stat st; |
| 322 return false; | 343 if (NO_RETRY_EXPECTED(stat(old_path, &st)) != 0) { |
| 323 } | 344 return false; |
| 324 int old_fd = TEMP_FAILURE_RETRY(open(old_path, O_RDONLY | O_CLOEXEC)); | 345 } |
| 325 if (old_fd < 0) { | 346 int old_fd = TEMP_FAILURE_RETRY(open(old_path, O_RDONLY | O_CLOEXEC)); |
| 326 return false; | 347 if (old_fd < 0) { |
| 327 } | 348 return false; |
| 328 int new_fd = TEMP_FAILURE_RETRY( | 349 } |
| 329 open(new_path, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, st.st_mode)); | 350 int new_fd = TEMP_FAILURE_RETRY( |
| 330 if (new_fd < 0) { | 351 open(new_path, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, st.st_mode)); |
| 331 VOID_TEMP_FAILURE_RETRY(close(old_fd)); | 352 if (new_fd < 0) { |
| 332 return false; | 353 VOID_TEMP_FAILURE_RETRY(close(old_fd)); |
| 333 } | 354 return false; |
| 334 off_t offset = 0; | 355 } |
| 335 int result = 1; | 356 off_t offset = 0; |
| 336 while (result > 0) { | 357 int result = 1; |
| 337 // Loop to ensure we copy everything, and not only up to 2GB. | 358 while (result > 0) { |
| 338 result = NO_RETRY_EXPECTED(sendfile(new_fd, old_fd, &offset, kMaxUint32)); | 359 // Loop to ensure we copy everything, and not only up to 2GB. |
| 339 } | 360 result = NO_RETRY_EXPECTED(sendfile(new_fd, old_fd, &offset, kMaxUint32)); |
| 340 // From sendfile man pages: | 361 } |
| 341 // Applications may wish to fall back to read(2)/write(2) in the case | 362 // From sendfile man pages: |
| 342 // where sendfile() fails with EINVAL or ENOSYS. | 363 // Applications may wish to fall back to read(2)/write(2) in the case |
| 343 if ((result < 0) && ((errno == EINVAL) || (errno == ENOSYS))) { | 364 // where sendfile() fails with EINVAL or ENOSYS. |
| 344 const intptr_t kBufferSize = 8 * KB; | 365 if ((result < 0) && ((errno == EINVAL) || (errno == ENOSYS))) { |
| 345 uint8_t buffer[kBufferSize]; | 366 const intptr_t kBufferSize = 8 * KB; |
| 346 while ((result = TEMP_FAILURE_RETRY(read(old_fd, buffer, kBufferSize))) > | 367 uint8_t buffer[kBufferSize]; |
| 347 0) { | 368 while ((result = TEMP_FAILURE_RETRY(read(old_fd, buffer, kBufferSize))) > |
| 348 int wrote = TEMP_FAILURE_RETRY(write(new_fd, buffer, result)); | 369 0) { |
| 349 if (wrote != result) { | 370 int wrote = TEMP_FAILURE_RETRY(write(new_fd, buffer, result)); |
| 350 result = -1; | 371 if (wrote != result) { |
| 351 break; | 372 result = -1; |
| 352 } | 373 break; |
| 353 } | 374 } |
| 354 } | 375 } |
| 355 int e = errno; | |
| 356 VOID_TEMP_FAILURE_RETRY(close(old_fd)); | |
| 357 VOID_TEMP_FAILURE_RETRY(close(new_fd)); | |
| 358 if (result < 0) { | |
| 359 VOID_NO_RETRY_EXPECTED(unlink(new_path)); | |
| 360 errno = e; | |
| 361 return false; | |
| 362 } | |
| 363 return true; | |
| 364 } else if (type == kIsDirectory) { | |
| 365 errno = EISDIR; | |
| 366 } else { | |
| 367 errno = ENOENT; | |
| 368 } | 376 } |
| 369 return false; | 377 int e = errno; |
| 378 VOID_TEMP_FAILURE_RETRY(close(old_fd)); |
| 379 VOID_TEMP_FAILURE_RETRY(close(new_fd)); |
| 380 if (result < 0) { |
| 381 VOID_NO_RETRY_EXPECTED(unlink(new_path)); |
| 382 errno = e; |
| 383 return false; |
| 384 } |
| 385 return true; |
| 370 } | 386 } |
| 371 | 387 |
| 372 | 388 |
| 373 int64_t File::LengthFromPath(const char* name) { | 389 int64_t File::LengthFromPath(const char* name) { |
| 374 struct stat st; | 390 struct stat st; |
| 375 if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) { | 391 if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) { |
| 376 // Signal an error if it's a directory. | 392 // Signal an error if it's a directory. |
| 377 if (S_ISDIR(st.st_mode)) { | 393 if (S_ISDIR(st.st_mode)) { |
| 378 errno = EISDIR; | 394 errno = EISDIR; |
| 379 return -1; | 395 return -1; |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 493 if (S_ISSOCK(buf.st_mode)) { | 509 if (S_ISSOCK(buf.st_mode)) { |
| 494 return kSocket; | 510 return kSocket; |
| 495 } | 511 } |
| 496 if (S_ISREG(buf.st_mode)) { | 512 if (S_ISREG(buf.st_mode)) { |
| 497 return kFile; | 513 return kFile; |
| 498 } | 514 } |
| 499 return kOther; | 515 return kOther; |
| 500 } | 516 } |
| 501 | 517 |
| 502 | 518 |
| 503 File::Type File::GetType(const char* pathname, bool follow_links) { | |
| 504 struct stat entry_info; | |
| 505 int stat_success; | |
| 506 if (follow_links) { | |
| 507 stat_success = NO_RETRY_EXPECTED(stat(pathname, &entry_info)); | |
| 508 } else { | |
| 509 stat_success = NO_RETRY_EXPECTED(lstat(pathname, &entry_info)); | |
| 510 } | |
| 511 if (stat_success == -1) { | |
| 512 return File::kDoesNotExist; | |
| 513 } | |
| 514 if (S_ISDIR(entry_info.st_mode)) { | |
| 515 return File::kIsDirectory; | |
| 516 } | |
| 517 if (S_ISREG(entry_info.st_mode)) { | |
| 518 return File::kIsFile; | |
| 519 } | |
| 520 if (S_ISLNK(entry_info.st_mode)) { | |
| 521 return File::kIsLink; | |
| 522 } | |
| 523 return File::kDoesNotExist; | |
| 524 } | |
| 525 | |
| 526 | |
| 527 File::Identical File::AreIdentical(const char* file_1, const char* file_2) { | 519 File::Identical File::AreIdentical(const char* file_1, const char* file_2) { |
| 528 struct stat file_1_info; | 520 struct stat file_1_info; |
| 529 struct stat file_2_info; | 521 struct stat file_2_info; |
| 530 if ((NO_RETRY_EXPECTED(lstat(file_1, &file_1_info)) == -1) || | 522 if ((NO_RETRY_EXPECTED(lstat(file_1, &file_1_info)) == -1) || |
| 531 (NO_RETRY_EXPECTED(lstat(file_2, &file_2_info)) == -1)) { | 523 (NO_RETRY_EXPECTED(lstat(file_2, &file_2_info)) == -1)) { |
| 532 return File::kError; | 524 return File::kError; |
| 533 } | 525 } |
| 534 return ((file_1_info.st_ino == file_2_info.st_ino) && | 526 return ((file_1_info.st_ino == file_2_info.st_ino) && |
| 535 (file_1_info.st_dev == file_2_info.st_dev)) | 527 (file_1_info.st_dev == file_2_info.st_dev)) |
| 536 ? File::kIdentical | 528 ? File::kIdentical |
| 537 : File::kDifferent; | 529 : File::kDifferent; |
| 538 } | 530 } |
| 539 | 531 |
| 540 } // namespace bin | 532 } // namespace bin |
| 541 } // namespace dart | 533 } // namespace dart |
| 542 | 534 |
| 543 #endif // defined(TARGET_OS_ANDROID) | 535 #endif // defined(TARGET_OS_ANDROID) |
| OLD | NEW |