| OLD | NEW |
| 1 // Copyright (c) 2016, 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_FUCHSIA) | 6 #if defined(TARGET_OS_FUCHSIA) |
| 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 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 241 FDUtils::SaveErrorAndClose(fd); | 241 FDUtils::SaveErrorAndClose(fd); |
| 242 return is_file; | 242 return is_file; |
| 243 } | 243 } |
| 244 | 244 |
| 245 | 245 |
| 246 bool File::CreateLink(const char* name, const char* target) { | 246 bool File::CreateLink(const char* name, const char* target) { |
| 247 return NO_RETRY_EXPECTED(symlink(target, name)) == 0; | 247 return NO_RETRY_EXPECTED(symlink(target, name)) == 0; |
| 248 } | 248 } |
| 249 | 249 |
| 250 | 250 |
| 251 bool File::Delete(const char* name) { | 251 File::Type File::GetType(const char* pathname, bool follow_links) { |
| 252 File::Type type = File::GetType(name, true); | 252 struct stat entry_info; |
| 253 if (type == kIsFile) { | 253 int stat_success; |
| 254 return NO_RETRY_EXPECTED(unlink(name)) == 0; | 254 if (follow_links) { |
| 255 } else if (type == kIsDirectory) { | 255 stat_success = NO_RETRY_EXPECTED(stat(pathname, &entry_info)); |
| 256 errno = EISDIR; | |
| 257 } else { | 256 } else { |
| 258 errno = ENOENT; | 257 stat_success = NO_RETRY_EXPECTED(lstat(pathname, &entry_info)); |
| 258 } |
| 259 if (stat_success == -1) { |
| 260 return File::kDoesNotExist; |
| 261 } |
| 262 if (S_ISDIR(entry_info.st_mode)) { |
| 263 return File::kIsDirectory; |
| 264 } |
| 265 if (S_ISREG(entry_info.st_mode)) { |
| 266 return File::kIsFile; |
| 267 } |
| 268 if (S_ISLNK(entry_info.st_mode)) { |
| 269 return File::kIsLink; |
| 270 } |
| 271 return File::kDoesNotExist; |
| 272 } |
| 273 |
| 274 |
| 275 static bool CheckTypeAndSetErrno(const char* name, |
| 276 File::Type expected, |
| 277 bool follow_links) { |
| 278 File::Type actual = File::GetType(name, follow_links); |
| 279 if (actual == expected) { |
| 280 return true; |
| 281 } |
| 282 switch (actual) { |
| 283 case File::kIsDirectory: |
| 284 errno = EISDIR; |
| 285 break; |
| 286 case File::kDoesNotExist: |
| 287 errno = ENOENT; |
| 288 break; |
| 289 default: |
| 290 errno = EINVAL; |
| 291 break; |
| 259 } | 292 } |
| 260 return false; | 293 return false; |
| 261 } | 294 } |
| 262 | 295 |
| 263 | 296 |
| 297 bool File::Delete(const char* name) { |
| 298 return CheckTypeAndSetErrno(name, kIsFile, true) && |
| 299 (NO_RETRY_EXPECTED(unlink(name)) == 0); |
| 300 } |
| 301 |
| 302 |
| 264 bool File::DeleteLink(const char* name) { | 303 bool File::DeleteLink(const char* name) { |
| 265 File::Type type = File::GetType(name, false); | 304 return CheckTypeAndSetErrno(name, kIsLink, false) && |
| 266 if (type == kIsLink) { | 305 (NO_RETRY_EXPECTED(unlink(name)) == 0); |
| 267 return NO_RETRY_EXPECTED(unlink(name)) == 0; | |
| 268 } | |
| 269 errno = EINVAL; | |
| 270 return false; | |
| 271 } | 306 } |
| 272 | 307 |
| 273 | 308 |
| 274 bool File::Rename(const char* old_path, const char* new_path) { | 309 bool File::Rename(const char* old_path, const char* new_path) { |
| 275 File::Type type = File::GetType(old_path, true); | 310 return CheckTypeAndSetErrno(old_path, kIsFile, true) && |
| 276 if (type == kIsFile) { | 311 (NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0); |
| 277 return NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0; | |
| 278 } else if (type == kIsDirectory) { | |
| 279 errno = EISDIR; | |
| 280 } else { | |
| 281 errno = ENOENT; | |
| 282 } | |
| 283 return false; | |
| 284 } | 312 } |
| 285 | 313 |
| 286 | 314 |
| 287 bool File::RenameLink(const char* old_path, const char* new_path) { | 315 bool File::RenameLink(const char* old_path, const char* new_path) { |
| 288 File::Type type = File::GetType(old_path, false); | 316 return CheckTypeAndSetErrno(old_path, kIsLink, false) && |
| 289 if (type == kIsLink) { | 317 (NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0); |
| 290 return NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0; | |
| 291 } else if (type == kIsDirectory) { | |
| 292 errno = EISDIR; | |
| 293 } else { | |
| 294 errno = EINVAL; | |
| 295 } | |
| 296 return false; | |
| 297 } | 318 } |
| 298 | 319 |
| 299 | 320 |
| 300 bool File::Copy(const char* old_path, const char* new_path) { | 321 bool File::Copy(const char* old_path, const char* new_path) { |
| 301 File::Type type = File::GetType(old_path, true); | 322 if (!CheckTypeAndSetErrno(old_path, kIsFile, true)) { |
| 302 if (type == kIsFile) { | 323 return false; |
| 303 struct stat64 st; | 324 } |
| 304 if (NO_RETRY_EXPECTED(stat64(old_path, &st)) != 0) { | 325 struct stat64 st; |
| 305 return false; | 326 if (NO_RETRY_EXPECTED(stat64(old_path, &st)) != 0) { |
| 327 return false; |
| 328 } |
| 329 int old_fd = NO_RETRY_EXPECTED(open64(old_path, O_RDONLY | O_CLOEXEC)); |
| 330 if (old_fd < 0) { |
| 331 return false; |
| 332 } |
| 333 int new_fd = NO_RETRY_EXPECTED( |
| 334 open64(new_path, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, st.st_mode)); |
| 335 if (new_fd < 0) { |
| 336 VOID_TEMP_FAILURE_RETRY(close(old_fd)); |
| 337 return false; |
| 338 } |
| 339 // TODO(MG-429): Use sendfile/copyfile or equivalent when there is one. |
| 340 intptr_t result; |
| 341 const intptr_t kBufferSize = 8 * KB; |
| 342 uint8_t buffer[kBufferSize]; |
| 343 while ((result = NO_RETRY_EXPECTED(read(old_fd, buffer, kBufferSize))) > 0) { |
| 344 int wrote = NO_RETRY_EXPECTED(write(new_fd, buffer, result)); |
| 345 if (wrote != result) { |
| 346 result = -1; |
| 347 break; |
| 306 } | 348 } |
| 307 int old_fd = NO_RETRY_EXPECTED(open64(old_path, O_RDONLY | O_CLOEXEC)); | |
| 308 if (old_fd < 0) { | |
| 309 return false; | |
| 310 } | |
| 311 int new_fd = NO_RETRY_EXPECTED( | |
| 312 open64(new_path, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, st.st_mode)); | |
| 313 if (new_fd < 0) { | |
| 314 VOID_TEMP_FAILURE_RETRY(close(old_fd)); | |
| 315 return false; | |
| 316 } | |
| 317 // TODO(MG-429): Use sendfile/copyfile or equivalent when there is one. | |
| 318 intptr_t result; | |
| 319 const intptr_t kBufferSize = 8 * KB; | |
| 320 uint8_t buffer[kBufferSize]; | |
| 321 while ((result = NO_RETRY_EXPECTED(read(old_fd, buffer, kBufferSize))) > | |
| 322 0) { | |
| 323 int wrote = NO_RETRY_EXPECTED(write(new_fd, buffer, result)); | |
| 324 if (wrote != result) { | |
| 325 result = -1; | |
| 326 break; | |
| 327 } | |
| 328 } | |
| 329 FDUtils::SaveErrorAndClose(old_fd); | |
| 330 FDUtils::SaveErrorAndClose(new_fd); | |
| 331 if (result < 0) { | |
| 332 int e = errno; | |
| 333 VOID_NO_RETRY_EXPECTED(unlink(new_path)); | |
| 334 errno = e; | |
| 335 return false; | |
| 336 } | |
| 337 return true; | |
| 338 } else if (type == kIsDirectory) { | |
| 339 errno = EISDIR; | |
| 340 } else { | |
| 341 errno = ENOENT; | |
| 342 } | 349 } |
| 343 return false; | 350 FDUtils::SaveErrorAndClose(old_fd); |
| 351 FDUtils::SaveErrorAndClose(new_fd); |
| 352 if (result < 0) { |
| 353 int e = errno; |
| 354 VOID_NO_RETRY_EXPECTED(unlink(new_path)); |
| 355 errno = e; |
| 356 return false; |
| 357 } |
| 358 return true; |
| 344 } | 359 } |
| 345 | 360 |
| 346 | 361 |
| 347 int64_t File::LengthFromPath(const char* name) { | 362 int64_t File::LengthFromPath(const char* name) { |
| 348 struct stat st; | 363 struct stat st; |
| 349 if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) { | 364 if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) { |
| 350 // Signal an error if it's a directory. | 365 // Signal an error if it's a directory. |
| 351 if (S_ISDIR(st.st_mode)) { | 366 if (S_ISDIR(st.st_mode)) { |
| 352 errno = EISDIR; | 367 errno = EISDIR; |
| 353 return -1; | 368 return -1; |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 472 if (S_ISSOCK(buf.st_mode)) { | 487 if (S_ISSOCK(buf.st_mode)) { |
| 473 return kSocket; | 488 return kSocket; |
| 474 } | 489 } |
| 475 if (S_ISREG(buf.st_mode)) { | 490 if (S_ISREG(buf.st_mode)) { |
| 476 return kFile; | 491 return kFile; |
| 477 } | 492 } |
| 478 return kOther; | 493 return kOther; |
| 479 } | 494 } |
| 480 | 495 |
| 481 | 496 |
| 482 File::Type File::GetType(const char* pathname, bool follow_links) { | |
| 483 struct stat entry_info; | |
| 484 int stat_success; | |
| 485 if (follow_links) { | |
| 486 stat_success = NO_RETRY_EXPECTED(stat(pathname, &entry_info)); | |
| 487 } else { | |
| 488 stat_success = NO_RETRY_EXPECTED(lstat(pathname, &entry_info)); | |
| 489 } | |
| 490 if (stat_success == -1) { | |
| 491 return File::kDoesNotExist; | |
| 492 } | |
| 493 if (S_ISDIR(entry_info.st_mode)) { | |
| 494 return File::kIsDirectory; | |
| 495 } | |
| 496 if (S_ISREG(entry_info.st_mode)) { | |
| 497 return File::kIsFile; | |
| 498 } | |
| 499 if (S_ISLNK(entry_info.st_mode)) { | |
| 500 return File::kIsLink; | |
| 501 } | |
| 502 return File::kDoesNotExist; | |
| 503 } | |
| 504 | |
| 505 | |
| 506 File::Identical File::AreIdentical(const char* file_1, const char* file_2) { | 497 File::Identical File::AreIdentical(const char* file_1, const char* file_2) { |
| 507 struct stat file_1_info; | 498 struct stat file_1_info; |
| 508 struct stat file_2_info; | 499 struct stat file_2_info; |
| 509 if ((NO_RETRY_EXPECTED(lstat(file_1, &file_1_info)) == -1) || | 500 if ((NO_RETRY_EXPECTED(lstat(file_1, &file_1_info)) == -1) || |
| 510 (NO_RETRY_EXPECTED(lstat(file_2, &file_2_info)) == -1)) { | 501 (NO_RETRY_EXPECTED(lstat(file_2, &file_2_info)) == -1)) { |
| 511 return File::kError; | 502 return File::kError; |
| 512 } | 503 } |
| 513 return ((file_1_info.st_ino == file_2_info.st_ino) && | 504 return ((file_1_info.st_ino == file_2_info.st_ino) && |
| 514 (file_1_info.st_dev == file_2_info.st_dev)) | 505 (file_1_info.st_dev == file_2_info.st_dev)) |
| 515 ? File::kIdentical | 506 ? File::kIdentical |
| 516 : File::kDifferent; | 507 : File::kDifferent; |
| 517 } | 508 } |
| 518 | 509 |
| 519 } // namespace bin | 510 } // namespace bin |
| 520 } // namespace dart | 511 } // namespace dart |
| 521 | 512 |
| 522 #endif // defined(TARGET_OS_FUCHSIA) | 513 #endif // defined(TARGET_OS_FUCHSIA) |
| OLD | NEW |