* errno will be set appropriately by the failing system primitive.
*/
template <class Container>
-bool readFile(const char* file_name, Container& out,
- size_t num_bytes = std::numeric_limits<size_t>::max()) {
+bool readFile(
+ int fd,
+ Container& out,
+ size_t num_bytes = std::numeric_limits<size_t>::max()) {
static_assert(sizeof(out[0]) == 1,
"readFile: only containers with byte-sized elements accepted");
- assert(file_name);
-
- const auto fd = openNoInt(file_name, O_RDONLY);
- if (fd == -1) return false;
size_t soFar = 0; // amount of bytes successfully read
SCOPE_EXIT {
- assert(out.size() >= soFar); // resize better doesn't throw
+ DCHECK(out.size() >= soFar); // resize better doesn't throw
out.resize(soFar);
- // Ignore errors when closing the file
- closeNoInt(fd);
};
// Obtain file size:
return true;
}
+/**
+ * Same as above, but takes in a file name instead of fd
+ */
+template <class Container>
+bool readFile(
+ const char* file_name,
+ Container& out,
+ size_t num_bytes = std::numeric_limits<size_t>::max()) {
+ DCHECK(file_name);
+
+ const auto fd = openNoInt(file_name, O_RDONLY);
+ if (fd == -1) {
+ return false;
+ }
+
+ SCOPE_EXIT {
+ // Ignore errors when closing the file
+ closeNoInt(fd);
+ };
+
+ return readFile(fd, out, num_bytes);
+}
+
/**
* Writes container to file. The container is assumed to be
* contiguous, with element size equal to 1, and offering STL-like
#include <glog/logging.h>
#include <gtest/gtest.h>
+#include <folly/File.h>
#include <folly/Range.h>
#include <folly/String.h>
}
TEST(String, readFile) {
- srand(time(nullptr));
- const string tmpPrefix = to<string>("/tmp/folly-file-util-test-",
- getpid(), "-", rand(), "-");
- const string afile = tmpPrefix + "myfile";
- const string emptyFile = tmpPrefix + "myfile2";
-
- SCOPE_EXIT {
- unlink(afile.c_str());
- unlink(emptyFile.c_str());
- };
+ const TemporaryFile afileTemp, emptyFileTemp;
+ auto afile = afileTemp.path();
+ auto emptyFile = emptyFileTemp.path();
EXPECT_TRUE(writeFile(string(), emptyFile.c_str()));
EXPECT_TRUE(writeFile(StringPiece("bar"), afile.c_str()));
}
}
+class ReadFileFd : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ ASSERT_TRUE(writeFile(StringPiece("bar"), aFile.path().c_str()));
+ }
+
+ TemporaryFile aFile;
+};
+
+TEST_F(ReadFileFd, ReadZeroBytes) {
+ std::string contents;
+ EXPECT_TRUE(readFile(aFile.fd(), contents, 0));
+ EXPECT_EQ("", contents);
+}
+
+TEST_F(ReadFileFd, ReadPartial) {
+ std::string contents;
+ EXPECT_TRUE(readFile(aFile.fd(), contents, 2));
+ EXPECT_EQ("ba", contents);
+}
+
+TEST_F(ReadFileFd, ReadFull) {
+ std::string contents;
+ EXPECT_TRUE(readFile(aFile.fd(), contents));
+ EXPECT_EQ("bar", contents);
+}
+
+TEST_F(ReadFileFd, WriteOnlyFd) {
+ File f(aFile.path().string(), O_WRONLY);
+ std::string contents;
+ EXPECT_FALSE(readFile(f.fd(), contents));
+ PLOG(INFO);
+}
+
+TEST_F(ReadFileFd, InvalidFd) {
+ File f(aFile.path().string());
+ f.close();
+ std::string contents;
+ EXPECT_FALSE(readFile(f.fd(), contents));
+ PLOG(INFO);
+}
}} // namespaces