| Index: runtime/bin/file_linux.cc
|
| diff --git a/runtime/bin/file_linux.cc b/runtime/bin/file_linux.cc
|
| index cb0d66e222998911d7f0c1622218c598a8d2d099..fd2a3c2eb69196dd29e29b1bcca4e3d074f8a903 100644
|
| --- a/runtime/bin/file_linux.cc
|
| +++ b/runtime/bin/file_linux.cc
|
| @@ -266,109 +266,124 @@ bool File::CreateLink(const char* name, const char* target) {
|
| }
|
|
|
|
|
| -bool File::Delete(const char* name) {
|
| - File::Type type = File::GetType(name, true);
|
| - if (type == kIsFile) {
|
| - return NO_RETRY_EXPECTED(unlink(name)) == 0;
|
| - } else if (type == kIsDirectory) {
|
| - errno = EISDIR;
|
| +File::Type File::GetType(const char* pathname, bool follow_links) {
|
| + struct stat64 entry_info;
|
| + int stat_success;
|
| + if (follow_links) {
|
| + stat_success = TEMP_FAILURE_RETRY(stat64(pathname, &entry_info));
|
| } else {
|
| - errno = ENOENT;
|
| + stat_success = TEMP_FAILURE_RETRY(lstat64(pathname, &entry_info));
|
| }
|
| - return false;
|
| + if (stat_success == -1) {
|
| + return File::kDoesNotExist;
|
| + }
|
| + if (S_ISDIR(entry_info.st_mode)) {
|
| + return File::kIsDirectory;
|
| + }
|
| + if (S_ISREG(entry_info.st_mode)) {
|
| + return File::kIsFile;
|
| + }
|
| + if (S_ISLNK(entry_info.st_mode)) {
|
| + return File::kIsLink;
|
| + }
|
| + return File::kDoesNotExist;
|
| }
|
|
|
|
|
| -bool File::DeleteLink(const char* name) {
|
| - File::Type type = File::GetType(name, false);
|
| - if (type == kIsLink) {
|
| - return NO_RETRY_EXPECTED(unlink(name)) == 0;
|
| +static bool CheckTypeAndSetErrno(const char* name,
|
| + File::Type expected,
|
| + bool follow_links) {
|
| + File::Type actual = File::GetType(name, follow_links);
|
| + if (actual == expected) {
|
| + return true;
|
| + }
|
| + switch (actual) {
|
| + case File::kIsDirectory:
|
| + errno = EISDIR;
|
| + break;
|
| + case File::kDoesNotExist:
|
| + errno = ENOENT;
|
| + break;
|
| + default:
|
| + errno = EINVAL;
|
| + break;
|
| }
|
| - errno = EINVAL;
|
| return false;
|
| }
|
|
|
|
|
| +bool File::Delete(const char* name) {
|
| + return CheckTypeAndSetErrno(name, kIsFile, true) &&
|
| + (NO_RETRY_EXPECTED(unlink(name)) == 0);
|
| +}
|
| +
|
| +
|
| +bool File::DeleteLink(const char* name) {
|
| + return CheckTypeAndSetErrno(name, kIsLink, false) &&
|
| + (NO_RETRY_EXPECTED(unlink(name)) == 0);
|
| +}
|
| +
|
| +
|
| bool File::Rename(const char* old_path, const char* new_path) {
|
| - File::Type type = File::GetType(old_path, true);
|
| - if (type == kIsFile) {
|
| - return NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0;
|
| - } else if (type == kIsDirectory) {
|
| - errno = EISDIR;
|
| - } else {
|
| - errno = ENOENT;
|
| - }
|
| - return false;
|
| + return CheckTypeAndSetErrno(old_path, kIsFile, true) &&
|
| + (NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0);
|
| }
|
|
|
|
|
| bool File::RenameLink(const char* old_path, const char* new_path) {
|
| - File::Type type = File::GetType(old_path, false);
|
| - if (type == kIsLink) {
|
| - return NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0;
|
| - } else if (type == kIsDirectory) {
|
| - errno = EISDIR;
|
| - } else {
|
| - errno = EINVAL;
|
| - }
|
| - return false;
|
| + return CheckTypeAndSetErrno(old_path, kIsLink, false) &&
|
| + (NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0);
|
| }
|
|
|
|
|
| bool File::Copy(const char* old_path, const char* new_path) {
|
| - File::Type type = File::GetType(old_path, true);
|
| - if (type == kIsFile) {
|
| - struct stat64 st;
|
| - if (TEMP_FAILURE_RETRY(stat64(old_path, &st)) != 0) {
|
| - return false;
|
| - }
|
| - int old_fd = TEMP_FAILURE_RETRY(open64(old_path, O_RDONLY | O_CLOEXEC));
|
| - if (old_fd < 0) {
|
| - return false;
|
| - }
|
| - int new_fd = TEMP_FAILURE_RETRY(
|
| - 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;
|
| - }
|
| - int64_t offset = 0;
|
| - intptr_t result = 1;
|
| - while (result > 0) {
|
| - // Loop to ensure we copy everything, and not only up to 2GB.
|
| - result =
|
| - NO_RETRY_EXPECTED(sendfile64(new_fd, old_fd, &offset, kMaxUint32));
|
| - }
|
| - // From sendfile man pages:
|
| - // Applications may wish to fall back to read(2)/write(2) in the case
|
| - // where sendfile() fails with EINVAL or ENOSYS.
|
| - if ((result < 0) && ((errno == EINVAL) || (errno == ENOSYS))) {
|
| - const intptr_t kBufferSize = 8 * KB;
|
| - uint8_t buffer[kBufferSize];
|
| - while ((result = TEMP_FAILURE_RETRY(read(old_fd, buffer, kBufferSize))) >
|
| - 0) {
|
| - int wrote = TEMP_FAILURE_RETRY(write(new_fd, buffer, result));
|
| - if (wrote != result) {
|
| - result = -1;
|
| - break;
|
| - }
|
| - }
|
| - }
|
| - int e = errno;
|
| + if (!CheckTypeAndSetErrno(old_path, kIsFile, true)) {
|
| + return false;
|
| + }
|
| + struct stat64 st;
|
| + if (TEMP_FAILURE_RETRY(stat64(old_path, &st)) != 0) {
|
| + return false;
|
| + }
|
| + int old_fd = TEMP_FAILURE_RETRY(open64(old_path, O_RDONLY | O_CLOEXEC));
|
| + if (old_fd < 0) {
|
| + return false;
|
| + }
|
| + int new_fd = TEMP_FAILURE_RETRY(
|
| + 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));
|
| - VOID_TEMP_FAILURE_RETRY(close(new_fd));
|
| - if (result < 0) {
|
| - VOID_NO_RETRY_EXPECTED(unlink(new_path));
|
| - errno = e;
|
| - return false;
|
| + return false;
|
| + }
|
| + int64_t offset = 0;
|
| + intptr_t result = 1;
|
| + while (result > 0) {
|
| + // Loop to ensure we copy everything, and not only up to 2GB.
|
| + result = NO_RETRY_EXPECTED(sendfile64(new_fd, old_fd, &offset, kMaxUint32));
|
| + }
|
| + // From sendfile man pages:
|
| + // Applications may wish to fall back to read(2)/write(2) in the case
|
| + // where sendfile() fails with EINVAL or ENOSYS.
|
| + if ((result < 0) && ((errno == EINVAL) || (errno == ENOSYS))) {
|
| + const intptr_t kBufferSize = 8 * KB;
|
| + uint8_t buffer[kBufferSize];
|
| + while ((result = TEMP_FAILURE_RETRY(read(old_fd, buffer, kBufferSize))) >
|
| + 0) {
|
| + int wrote = TEMP_FAILURE_RETRY(write(new_fd, buffer, result));
|
| + if (wrote != result) {
|
| + result = -1;
|
| + break;
|
| + }
|
| }
|
| - return true;
|
| - } else if (type == kIsDirectory) {
|
| - errno = EISDIR;
|
| - } else {
|
| - errno = ENOENT;
|
| }
|
| - return false;
|
| + int e = errno;
|
| + VOID_TEMP_FAILURE_RETRY(close(old_fd));
|
| + VOID_TEMP_FAILURE_RETRY(close(new_fd));
|
| + if (result < 0) {
|
| + VOID_NO_RETRY_EXPECTED(unlink(new_path));
|
| + errno = e;
|
| + return false;
|
| + }
|
| + return true;
|
| }
|
|
|
|
|
| @@ -514,30 +529,6 @@ File::StdioHandleType File::GetStdioHandleType(int fd) {
|
| }
|
|
|
|
|
| -File::Type File::GetType(const char* pathname, bool follow_links) {
|
| - struct stat64 entry_info;
|
| - int stat_success;
|
| - if (follow_links) {
|
| - stat_success = TEMP_FAILURE_RETRY(stat64(pathname, &entry_info));
|
| - } else {
|
| - stat_success = TEMP_FAILURE_RETRY(lstat64(pathname, &entry_info));
|
| - }
|
| - if (stat_success == -1) {
|
| - return File::kDoesNotExist;
|
| - }
|
| - if (S_ISDIR(entry_info.st_mode)) {
|
| - return File::kIsDirectory;
|
| - }
|
| - if (S_ISREG(entry_info.st_mode)) {
|
| - return File::kIsFile;
|
| - }
|
| - if (S_ISLNK(entry_info.st_mode)) {
|
| - return File::kIsLink;
|
| - }
|
| - return File::kDoesNotExist;
|
| -}
|
| -
|
| -
|
| File::Identical File::AreIdentical(const char* file_1, const char* file_2) {
|
| struct stat64 file_1_info;
|
| struct stat64 file_2_info;
|
|
|