diff options
author | 2017-02-27 12:25:11 +0000 | |
---|---|---|
committer | 2017-02-27 15:10:04 +0000 | |
commit | 5f27712d09a501c8d5da20b43484490076b749f2 (patch) | |
tree | 6d1e263f5e3ace226ed3f8cc1d9548c1162e9476 /src | |
parent | abc933266ebdebe0bd8fc8cc78a8aed3f4fc87fb (diff) |
Bazel client: add new ReadFile/WriteFile variants
Instead of writing from / reading to a string,
these variants take a buffer and a size.
These methods will be used from ijar.
See https://github.com/bazelbuild/bazel/issues/2157
--
PiperOrigin-RevId: 148635487
MOS_MIGRATED_REVID=148635487
Diffstat (limited to 'src')
-rw-r--r-- | src/main/cpp/util/file.cc | 38 | ||||
-rw-r--r-- | src/main/cpp/util/file.h | 16 | ||||
-rw-r--r-- | src/main/cpp/util/file_platform.h | 10 | ||||
-rw-r--r-- | src/main/cpp/util/file_posix.cc | 15 | ||||
-rw-r--r-- | src/main/cpp/util/file_windows.cc | 51 | ||||
-rw-r--r-- | src/test/cpp/util/file_test.cc | 27 |
6 files changed, 128 insertions, 29 deletions
diff --git a/src/main/cpp/util/file.cc b/src/main/cpp/util/file.cc index 392af372af..97f7d3da15 100644 --- a/src/main/cpp/util/file.cc +++ b/src/main/cpp/util/file.cc @@ -31,16 +31,17 @@ using std::pair; using std::string; using std::vector; -bool ReadFrom(const std::function<int(void *, int)> &read_func, string *content, - int max_size) { +bool ReadFrom(const std::function<int(void *, size_t)> &read_func, + string *content, int max_size) { + static const size_t kReadSize = 4096; // read 4K chunks content->clear(); - char buf[4096]; + char buf[kReadSize]; // OPT: This loop generates one spurious read on regular files. while (int r = read_func( buf, max_size > 0 - ? std::min(max_size, static_cast<int>(sizeof buf)) - : sizeof buf)) { - if (r == -1) { + ? std::min(static_cast<size_t>(max_size), kReadSize) + : kReadSize)) { + if (r < 0) { if (errno == EINTR || errno == EAGAIN) continue; return false; } @@ -56,6 +57,26 @@ bool ReadFrom(const std::function<int(void *, int)> &read_func, string *content, return true; } +bool ReadFrom(const std::function<int(void *, size_t)> &read_func, void *data, + size_t size) { + static const size_t kReadSize = 4096; // read 4K chunks + size_t offset = 0; + while (int r = read_func(reinterpret_cast<char *>(data) + offset, + std::min(kReadSize, size))) { + if (r < 0) { + if (errno == EINTR || errno == EAGAIN) continue; + return false; + } + offset += r; + if (size > static_cast<size_t>(r)) { + size -= r; + } else { + break; + } + } + return true; +} + bool WriteTo(const std::function<int(const void *, size_t)> &write_func, const void *data, size_t size) { int r = write_func(data, size); @@ -65,8 +86,9 @@ bool WriteTo(const std::function<int(const void *, size_t)> &write_func, return r == static_cast<int>(size); } -bool WriteFile(const std::string &content, const std::string &filename) { - return WriteFile(content.c_str(), content.size(), filename); +bool WriteFile(const std::string &content, const std::string &filename, + unsigned int perm) { + return WriteFile(content.c_str(), content.size(), filename, perm); } string Dirname(const string &path) { diff --git a/src/main/cpp/util/file.h b/src/main/cpp/util/file.h index efe963c6d7..2f29d15d9e 100644 --- a/src/main/cpp/util/file.h +++ b/src/main/cpp/util/file.h @@ -38,12 +38,19 @@ class IPipe { // If `max_size` is positive, the method reads at most that many bytes; // otherwise the method reads everything. // Returns false on error. Can be called from a signal handler. -bool ReadFrom(const std::function<int(void *, int)> &read_func, +bool ReadFrom(const std::function<int(void *, size_t)> &read_func, std::string *content, int max_size = 0); -// Writes `size` bytes from `data` into file 'filename' and makes it executable. +// Reads up to `size` bytes using `read_func` into `data`. +// There must be enough memory allocated at `data`. +// Returns true on success, false on error. +bool ReadFrom(const std::function<int(void *, size_t)> &read_func, void *data, + size_t size); + +// Writes `content` into file `filename`, and chmods it to `perm`. // Returns false on failure, sets errno. -bool WriteFile(const void *data, size_t size, const std::string &filename); +bool WriteFile(const std::string &content, const std::string &filename, + unsigned int perm = 0755); // Writes `size` bytes from `data` into a destination using `write_func`. // Returns false on failure, sets errno. @@ -66,7 +73,8 @@ std::string JoinPath(const std::string &path1, const std::string &path2); // Does not follow symlinks / junctions. // // Populates `result` with the full paths of the files. Every entry will have -// `path` as its prefix. If `path` is a file, `result` contains just this file. +// `path` as its prefix. If `path` is a file, `result` contains just this +// file. void GetAllFilesUnder(const std::string &path, std::vector<std::string> *result); diff --git a/src/main/cpp/util/file_platform.h b/src/main/cpp/util/file_platform.h index b104ee7e6a..f4da9a68f8 100644 --- a/src/main/cpp/util/file_platform.h +++ b/src/main/cpp/util/file_platform.h @@ -60,9 +60,15 @@ std::pair<std::string, std::string> SplitPath(const std::string &path); bool ReadFile(const std::string &filename, std::string *content, int max_size = 0); -// Writes 'content' into file 'filename', and makes it executable. +// Reads up to `size` bytes from the file `filename` into `data`. +// There must be enough memory allocated at `data`. +// Returns true on success, false on error. +bool ReadFile(const std::string &filename, void *data, size_t size); + +// Writes `size` bytes from `data` into file `filename` and chmods it to `perm`. // Returns false on failure, sets errno. -bool WriteFile(const std::string &content, const std::string &filename); +bool WriteFile(const void *data, size_t size, const std::string &filename, + unsigned int perm = 0755); enum RenameDirectoryResult { kRenameDirectorySuccess = 0, diff --git a/src/main/cpp/util/file_posix.cc b/src/main/cpp/util/file_posix.cc index 30fd8cd9e3..410de6744e 100644 --- a/src/main/cpp/util/file_posix.cc +++ b/src/main/cpp/util/file_posix.cc @@ -185,10 +185,19 @@ bool ReadFile(const string &filename, string *content, int max_size) { return result; } -bool WriteFile(const void *data, size_t size, const string &filename) { +bool ReadFile(const string &filename, void *data, size_t size) { + int fd = open(filename.c_str(), O_RDONLY); + if (fd == -1) return false; + bool result = ReadFrom( + [fd](void *buf, size_t len) { return read(fd, buf, len); }, data, size); + close(fd); + return result; +} + +bool WriteFile(const void *data, size_t size, const string &filename, + unsigned int perm) { UnlinkPath(filename); // We don't care about the success of this. - int fd = - open(filename.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0755); // chmod +x + int fd = open(filename.c_str(), O_CREAT | O_WRONLY | O_TRUNC, perm); if (fd == -1) { return false; } diff --git a/src/main/cpp/util/file_windows.cc b/src/main/cpp/util/file_windows.cc index 26cc47df65..f4e4e9239f 100644 --- a/src/main/cpp/util/file_windows.cc +++ b/src/main/cpp/util/file_windows.cc @@ -526,42 +526,69 @@ bool AsShortWindowsPath(const string& path, string* result) { return true; } -bool ReadFile(const string& filename, string* content, int max_size) { +static bool OpenFileForReading(const string& filename, HANDLE* result) { if (filename.empty()) { return false; } if (IsDevNull(filename)) { - content->clear(); return true; } wstring wfilename; if (!AsWindowsPathWithUncPrefix(filename, &wfilename)) { return false; } - windows_util::AutoHandle handle(::CreateFileW( + *result = ::CreateFileW( /* lpFileName */ wfilename.c_str(), /* dwDesiredAccess */ GENERIC_READ, /* dwShareMode */ FILE_SHARE_READ, /* lpSecurityAttributes */ NULL, /* dwCreationDisposition */ OPEN_EXISTING, /* dwFlagsAndAttributes */ FILE_ATTRIBUTE_NORMAL, - /* hTemplateFile */ NULL)); - if (!handle.IsValid()) { + /* hTemplateFile */ NULL); + return true; +} + +bool ReadFile(const string& filename, string* content, int max_size) { + HANDLE handle; + if (!OpenFileForReading(filename, &handle)) { return false; } - HANDLE h = handle; - bool result = ReadFrom( - [h](void* buf, int len) { + windows_util::AutoHandle autohandle(handle); + if (!autohandle.IsValid()) { + return false; + } + content->clear(); + return ReadFrom( + [handle](void* buf, int len) { DWORD actually_read = 0; - ::ReadFile(h, buf, len, &actually_read, NULL); + ::ReadFile(handle, buf, len, &actually_read, NULL); return actually_read; }, content, max_size); - return result; } -bool WriteFile(const void* data, size_t size, const string& filename) { +bool ReadFile(const string& filename, void* data, size_t size) { + HANDLE handle; + if (!OpenFileForReading(filename, &handle)) { + return false; + } + + windows_util::AutoHandle autohandle(handle); + if (!autohandle.IsValid()) { + return false; + } + return ReadFrom( + [handle](void* buf, int len) { + DWORD actually_read = 0; + ::ReadFile(handle, buf, len, &actually_read, NULL); + return actually_read; + }, + data, size); +} + +bool WriteFile(const void* data, size_t size, const string& filename, + unsigned int perm) { if (IsDevNull(filename)) { return true; // mimic write(2) behavior with /dev/null } @@ -583,6 +610,8 @@ bool WriteFile(const void* data, size_t size, const string& filename) { return false; } + // TODO(laszlocsomor): respect `perm` and set the file permissions accoridngly + HANDLE h = handle; bool result = WriteTo( [h](const void* buf, size_t bufsize) { diff --git a/src/test/cpp/util/file_test.cc b/src/test/cpp/util/file_test.cc index 4173954559..1a02de5d78 100644 --- a/src/test/cpp/util/file_test.cc +++ b/src/test/cpp/util/file_test.cc @@ -57,7 +57,7 @@ TEST(FileTest, TestMultiThreadedPipe) { ASSERT_EQ(0, strncmp(buffer, "hello world", 11)); } -TEST(FileTest, TestReadFile) { +TEST(FileTest, TestReadFileIntoString) { const char* tempdir = getenv("TEST_TMPDIR"); ASSERT_NE(nullptr, tempdir); ASSERT_NE(0, tempdir[0]); @@ -79,6 +79,31 @@ TEST(FileTest, TestReadFile) { ASSERT_EQ(std::string(""), actual); } +TEST(FileTest, TestReadFileIntoBuffer) { + const char* tempdir = getenv("TEST_TMPDIR"); + EXPECT_NE(nullptr, tempdir); + EXPECT_NE(0, tempdir[0]); + + std::string filename(JoinPath(tempdir, "test.readfile")); + AutoFileStream fh(fopen(filename.c_str(), "wt")); + EXPECT_TRUE(fh.IsOpen()); + EXPECT_EQ(11, fwrite("hello world", 1, 11, fh)); + fh.Close(); + + char buffer[30]; + memset(buffer, 0, 30); + ASSERT_TRUE(ReadFile(filename, buffer, 5)); + ASSERT_EQ(string("hello"), string(buffer)); + + memset(buffer, 0, 30); + ASSERT_TRUE(ReadFile(filename, buffer, 30)); + ASSERT_EQ(string("hello world"), string(buffer)); + + memset(buffer, 0, 30); + ASSERT_TRUE(ReadFile("/dev/null", buffer, 42)); + ASSERT_EQ(string(""), string(buffer)); +} + TEST(FileTest, TestWriteFile) { const char* tempdir = getenv("TEST_TMPDIR"); ASSERT_NE(nullptr, tempdir); |