aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Laszlo Csomor <laszlocsomor@google.com>2017-02-27 12:25:11 +0000
committerGravatar Yue Gan <yueg@google.com>2017-02-27 15:10:04 +0000
commit5f27712d09a501c8d5da20b43484490076b749f2 (patch)
tree6d1e263f5e3ace226ed3f8cc1d9548c1162e9476 /src
parentabc933266ebdebe0bd8fc8cc78a8aed3f4fc87fb (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.cc38
-rw-r--r--src/main/cpp/util/file.h16
-rw-r--r--src/main/cpp/util/file_platform.h10
-rw-r--r--src/main/cpp/util/file_posix.cc15
-rw-r--r--src/main/cpp/util/file_windows.cc51
-rw-r--r--src/test/cpp/util/file_test.cc27
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);