| Index: runtime/bin/file_fuchsia.cc
|
| diff --git a/runtime/bin/file_fuchsia.cc b/runtime/bin/file_fuchsia.cc
|
| index 130d0310c3833f2790dc2cf1c1b73801c356bb96..ff080439d07aa5cd0e0621da58dfe12955c0c93b 100644
|
| --- a/runtime/bin/file_fuchsia.cc
|
| +++ b/runtime/bin/file_fuchsia.cc
|
| @@ -16,6 +16,7 @@
|
| #include <unistd.h> // NOLINT
|
|
|
| #include "bin/builtin.h"
|
| +#include "bin/fdutils.h"
|
| #include "bin/log.h"
|
| #include "platform/signal_blocker.h"
|
| #include "platform/utils.h"
|
| @@ -280,7 +281,48 @@ bool File::RenameLink(const char* old_path, const char* new_path) {
|
|
|
|
|
| bool File::Copy(const char* old_path, const char* new_path) {
|
| - UNIMPLEMENTED();
|
| + File::Type type = File::GetType(old_path, true);
|
| + if (type == kIsFile) {
|
| + struct stat64 st;
|
| + if (NO_RETRY_EXPECTED(stat64(old_path, &st)) != 0) {
|
| + return false;
|
| + }
|
| + int old_fd = NO_RETRY_EXPECTED(open64(old_path, O_RDONLY | O_CLOEXEC));
|
| + if (old_fd < 0) {
|
| + return false;
|
| + }
|
| + int new_fd = NO_RETRY_EXPECTED(
|
| + open64(new_path, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, st.st_mode));
|
| + if (new_fd < 0) {
|
| + VOID_TEMP_FAILURE_RETRY(close(old_fd));
|
| + return false;
|
| + }
|
| + // TODO(MG-429): Use sendfile/copyfile or equivalent when there is one.
|
| + intptr_t result;
|
| + const intptr_t kBufferSize = 8 * KB;
|
| + uint8_t buffer[kBufferSize];
|
| + while ((result = NO_RETRY_EXPECTED(read(old_fd, buffer, kBufferSize))) >
|
| + 0) {
|
| + int wrote = NO_RETRY_EXPECTED(write(new_fd, buffer, result));
|
| + if (wrote != result) {
|
| + result = -1;
|
| + break;
|
| + }
|
| + }
|
| + FDUtils::SaveErrorAndClose(old_fd);
|
| + FDUtils::SaveErrorAndClose(new_fd);
|
| + if (result < 0) {
|
| + int e = errno;
|
| + VOID_NO_RETRY_EXPECTED(unlink(new_path));
|
| + errno = e;
|
| + return false;
|
| + }
|
| + return true;
|
| + } else if (type == kIsDirectory) {
|
| + errno = EISDIR;
|
| + } else {
|
| + errno = ENOENT;
|
| + }
|
| return false;
|
| }
|
|
|
|
|