diff options
-rw-r--r-- | libadhocutil/fileUtils.cpp | 89 | ||||
-rw-r--r-- | libadhocutil/fileUtils.h | 65 | ||||
-rw-r--r-- | libadhocutil/unittests/testFileUtils.cpp | 52 |
3 files changed, 191 insertions, 15 deletions
diff --git a/libadhocutil/fileUtils.cpp b/libadhocutil/fileUtils.cpp index 23fce0e..5273836 100644 --- a/libadhocutil/fileUtils.cpp +++ b/libadhocutil/fileUtils.cpp @@ -1,10 +1,13 @@ #include "fileUtils.h" +#include "compileTimeFormatter.h" #include <unistd.h> #include <sys.h> #include <sys/mman.h> namespace AdHoc { namespace FileUtils { + AdHocFormatter(FD, "FD %?"); + boost::filesystem::path operator/(const boost::filesystem::path & p, unsigned int n) { auto pp = p.begin(); @@ -43,8 +46,43 @@ namespace AdHoc { return fh; } - FileHandleStat::FileHandleStat(const boost::filesystem::path & path) : - FileHandle(path) + FileHandleStat::FileHandleStat(int fd) : + FileHandle(fd) + { + refreshStat(); + } + + FileHandleStat::FileHandleStat(const boost::filesystem::path & path, int flags) : + FileHandle(path, flags) + { + refreshStat(path); + } + + FileHandleStat::FileHandleStat(const boost::filesystem::path & path, int flags, int mode) : + FileHandle(path, flags, mode) + { + refreshStat(path); + } + + const struct stat & + FileHandleStat::getStat() const + { + return st; + } + + const struct stat & + FileHandleStat::refreshStat() + { + if (fstat(fh, &st)) { + // LCOV_EXCL_START can't think of a way to test open succeeding and fstat failing + throw SystemExceptionOn("fstat(2) failed", strerror(errno), errno, FD::get(fh)); + // LCOV_EXCL_STOP + } + return st; + } + + void + FileHandleStat::refreshStat(const boost::filesystem::path & path) { if (fstat(fh, &st)) { // LCOV_EXCL_START can't think of a way to test open succeeding and fstat failing @@ -53,25 +91,54 @@ namespace AdHoc { } } - const struct stat & - FileHandleStat::getStat() const + MemMap::MemMap(int d, int flags) : + FileHandleStat(d), + data(setupMap(flags)) { - return st; } - MemMap::MemMap(const boost::filesystem::path & path) : - FileHandleStat(path), - data(mmap(0, st.st_size, PROT_READ, MAP_SHARED, fh, 0)) + MemMap::MemMap(const boost::filesystem::path & path, int flags) : + FileHandleStat(path, flags), + data(setupMap(path, flags)) + { + } + + MemMap::MemMap(const boost::filesystem::path & path, int flags, int mode) : + FileHandleStat(path, flags, mode), + data(setupMap(path, flags)) { - if (data == (void*)-1) { - throw SystemExceptionOn("mmap(2) failed", strerror(errno), errno, path.string()); - } } MemMap::~MemMap() { munmap(data, st.st_size); } + + void * + MemMap::setupMapInt(int flags) const + { + return mmap(0, st.st_size, flags & (O_WRONLY | O_RDWR) ? PROT_WRITE : PROT_READ, MAP_SHARED, fh, 0); + } + + void * + MemMap::setupMap(int flags) const + { + auto data = setupMapInt(flags); + if (data == (void*)-1) { + throw SystemExceptionOn("mmap(2) failed", strerror(errno), errno, FD::get(fh)); + } + return data; + } + + void * + MemMap::setupMap(const boost::filesystem::path & path, int flags) const + { + auto data = setupMapInt(flags); + if (data == (void*)-1) { + throw SystemExceptionOn("mmap(2) failed", strerror(errno), errno, path.string()); + } + return data; + } } } diff --git a/libadhocutil/fileUtils.h b/libadhocutil/fileUtils.h index 4df8c97..708652f 100644 --- a/libadhocutil/fileUtils.h +++ b/libadhocutil/fileUtils.h @@ -22,6 +22,11 @@ namespace AdHoc { class DLL_PUBLIC FileHandle { public: /** + * Move constructor. + */ + FileHandle(FileHandle &&) = default; + + /** * Construct from an existing file descriptor. * @param fd An open file descriptor. */ @@ -63,10 +68,30 @@ namespace AdHoc { class DLL_PUBLIC FileHandleStat : public FileHandle { public: /** + * Move constructor. + */ + FileHandleStat(FileHandleStat &&) = default; + + /** + * Construct from an existing file descriptor. + * @param fd An open file descriptor. + */ + FileHandleStat(int fd); + + /** * Open a new file handle (with the default flags). * @param path Path of file to open. + * @param flags File handle flags */ - FileHandleStat(const boost::filesystem::path & path); + FileHandleStat(const boost::filesystem::path & path, int flags = O_RDONLY); + + /** + * Open a new file handle. + * @param path Path of file to open. + * @param flags File handle flags + * @param mode File handle mode + */ + FileHandleStat(const boost::filesystem::path & path, int flags, int mode); /** * Get the stat structure. @@ -74,9 +99,18 @@ namespace AdHoc { */ const struct stat & getStat() const; + /** + * Refresh and return the stat structure. + * @return The stat structure. + */ + const struct stat & refreshStat(); + protected: /// The stat structure. struct stat st; + + private: + DLL_PRIVATE void refreshStat(const boost::filesystem::path & path); }; /** @@ -85,14 +119,41 @@ namespace AdHoc { class DLL_PUBLIC MemMap : public FileHandleStat { public: /** + * Move constructor. + */ + MemMap(MemMap &&) = default; + + /** + * Construct from an existing file descriptor. + * @param fd An open file descriptor. + * @param flags File handle flags + */ + MemMap(int fd, int flags = O_RDONLY); + + /** * Open a new file handle (with the default flags). * @param path Path of file to open. + * @param flags File handle flags + */ + MemMap(const boost::filesystem::path & path, int flags = O_RDONLY); + + /** + * Open a new file handle. + * @param path Path of file to open. + * @param flags File handle flags + * @param mode File handle mode */ - MemMap(const boost::filesystem::path & path); + MemMap(const boost::filesystem::path & path, int flags, int mode); + ~MemMap(); /// The file data. void * const data; + + private: + DLL_PUBLIC void * setupMapInt(int flags) const; + DLL_PUBLIC void * setupMap(int flags) const; + DLL_PUBLIC void * setupMap(const boost::filesystem::path & path, int flags) const; }; } } diff --git a/libadhocutil/unittests/testFileUtils.cpp b/libadhocutil/unittests/testFileUtils.cpp index 0e1cb79..648281c 100644 --- a/libadhocutil/unittests/testFileUtils.cpp +++ b/libadhocutil/unittests/testFileUtils.cpp @@ -5,14 +5,62 @@ #include <definedDirs.h> #include <sys.h> -BOOST_AUTO_TEST_CASE( raw ) +template <typename T> +void testRaw() { int f = open("/proc/self/exe", O_RDONLY); BOOST_REQUIRE(f != -1); - AdHoc::FileUtils::FileHandle fh(f); + T fh(f); BOOST_REQUIRE_EQUAL(f, fh); } +BOOST_AUTO_TEST_CASE( raw ) +{ + testRaw<AdHoc::FileUtils::FileHandle>(); + testRaw<AdHoc::FileUtils::FileHandleStat>(); + testRaw<AdHoc::FileUtils::MemMap>(); +} + +template <typename T, typename ... P> +T openfh(P ... p) +{ + T fh(rootDir / "testFileUtils.cpp", p...); + return fh; +} + +template <typename T, typename ... P> +T moveTest(P ... p) +{ + T fh = openfh<T>(p...); + char out; + BOOST_REQUIRE_EQUAL(1, read(fh, &out, 1)); + return fh; +} + +BOOST_AUTO_TEST_CASE( moveFileHandle ) +{ + moveTest<AdHoc::FileUtils::FileHandle>(); + moveTest<AdHoc::FileUtils::FileHandle>(O_RDONLY); + moveTest<AdHoc::FileUtils::FileHandle>(O_RDONLY, O_NONBLOCK); +} + +BOOST_AUTO_TEST_CASE( moveFileHandleStat ) +{ + auto f = moveTest<AdHoc::FileUtils::FileHandleStat>(); + BOOST_REQUIRE_EQUAL(0100644, f.getStat().st_mode); + moveTest<AdHoc::FileUtils::FileHandleStat>(O_RDONLY); + moveTest<AdHoc::FileUtils::FileHandleStat>(O_RDONLY, O_NONBLOCK); +} + +BOOST_AUTO_TEST_CASE( moveMemMap ) +{ + auto f = moveTest<AdHoc::FileUtils::MemMap>(); + BOOST_REQUIRE_EQUAL(0100644, f.getStat().st_mode); + BOOST_REQUIRE_EQUAL(0, memcmp(f.data, "#define BOOST_TEST_MODULE FileUtils", 35)); + moveTest<AdHoc::FileUtils::MemMap>(O_RDONLY); + moveTest<AdHoc::FileUtils::MemMap>(O_RDONLY, O_NONBLOCK); +} + BOOST_AUTO_TEST_CASE( memmap ) { AdHoc::FileUtils::MemMap f(rootDir / "testFileUtils.cpp"); |