diff --git a/base/file.cpp b/base/file.cpp index a51c5ffa8..6b19818e0 100644 --- a/base/file.cpp +++ b/base/file.cpp @@ -120,5 +120,29 @@ bool WriteStringToFile(const std::string& content, const std::string& path) { return result || CleanUpAfterFailedWrite(path); } +bool ReadFully(int fd, void* data, size_t byte_count) { + uint8_t* p = reinterpret_cast(data); + size_t remaining = byte_count; + while (remaining > 0) { + ssize_t n = TEMP_FAILURE_RETRY(read(fd, p, remaining)); + if (n <= 0) return false; + p += n; + remaining -= n; + } + return true; +} + +bool WriteFully(int fd, const void* data, size_t byte_count) { + const uint8_t* p = reinterpret_cast(data); + size_t remaining = byte_count; + while (remaining > 0) { + ssize_t n = TEMP_FAILURE_RETRY(write(fd, p, remaining)); + if (n == -1) return false; + p += n; + remaining -= n; + } + return true; +} + } // namespace base } // namespace android diff --git a/base/file_test.cpp b/base/file_test.cpp index fc48b32a7..e5cf696fe 100644 --- a/base/file_test.cpp +++ b/base/file_test.cpp @@ -79,3 +79,28 @@ TEST(file, WriteStringToFd) { ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)) << errno; EXPECT_EQ("abc", s); } + +TEST(file, ReadFully) { + int fd = open("/proc/version", O_RDONLY); + ASSERT_NE(-1, fd) << strerror(errno); + + char buf[1024]; + memset(buf, 0, sizeof(buf)); + ASSERT_TRUE(android::base::ReadFully(fd, buf, 5)); + ASSERT_STREQ("Linux", buf); + + ASSERT_EQ(0, lseek(fd, 0, SEEK_SET)) << strerror(errno); + + ASSERT_FALSE(android::base::ReadFully(fd, buf, sizeof(buf))); + + close(fd); +} + +TEST(file, WriteFully) { + TemporaryFile tf; + ASSERT_TRUE(tf.fd != -1); + ASSERT_TRUE(android::base::WriteFully(tf.fd, "abc", 3)); + std::string s; + ASSERT_TRUE(android::base::ReadFileToString(tf.filename, &s)) << errno; + EXPECT_EQ("abc", s); +} diff --git a/base/include/base/file.h b/base/include/base/file.h index ef977421b..acd29b30e 100644 --- a/base/include/base/file.h +++ b/base/include/base/file.h @@ -34,6 +34,9 @@ bool WriteStringToFile(const std::string& content, const std::string& path, mode_t mode, uid_t owner, gid_t group); #endif +bool ReadFully(int fd, void* data, size_t byte_count); +bool WriteFully(int fd, const void* data, size_t byte_count); + } // namespace base } // namespace android