diff options
-rw-r--r-- | CMakeLists.txt | 7 | ||||
-rw-r--r-- | include/winapi/file.hpp | 37 | ||||
-rw-r--r-- | src/file.cpp | 42 |
3 files changed, 86 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 8553200..035ea3a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,6 +17,13 @@ target_link_libraries(winapi_common PUBLIC Boost::disable_autolinking Boost::boo install(TARGETS winapi_common ARCHIVE DESTINATION lib) install(DIRECTORY include/winapi DESTINATION include) +if(MINGW) + # FILE_ID_INFO and friends require at least 0x0602: + target_compile_definitions(winapi_common PUBLIC + NTDDI_VERSION=NTDDI_WIN8 + _WIN32_WINNT=_WIN32_WINNT_WIN8) +endif() + if(WINAPI_COMMON_TESTS) add_subdirectory(test) endif() diff --git a/include/winapi/file.hpp b/include/winapi/file.hpp index b9688e9..78187d9 100644 --- a/include/winapi/file.hpp +++ b/include/winapi/file.hpp @@ -8,15 +8,34 @@ #include "handle.hpp" #include "path.hpp" +#include <boost/functional/hash.hpp> + +#include <windows.h> + +#include <cstddef> +#include <functional> #include <string> #include <utility> namespace winapi { +bool operator==(const FILE_ID_128& a, const FILE_ID_128& b); + class File : private Handle { public: + struct ID { + const FILE_ID_INFO impl; + + bool operator==(const ID& other) const { + return impl.VolumeSerialNumber == other.impl.VolumeSerialNumber && + impl.FileId == other.impl.FileId; + } + }; + static Handle open_r(const std::string&); static Handle open_r(const CanonicalPath&); + static Handle open_read_attributes(const std::string&); + static Handle open_read_attributes(const CanonicalPath&); static Handle open_w(const std::string&); static Handle open_w(const CanonicalPath&); @@ -29,6 +48,24 @@ public: using Handle::read; using Handle::write; + + std::size_t get_size() const; + + ID query_id() const; }; } // namespace winapi + +namespace std { + +template <> +struct hash<winapi::File::ID> { + std::size_t operator()(const winapi::File::ID& id) const { + std::size_t seed = 0; + boost::hash_combine(seed, id.impl.VolumeSerialNumber); + boost::hash_combine(seed, id.impl.FileId.Identifier); + return seed; + } +}; + +} // namespace std diff --git a/src/file.cpp b/src/file.cpp index 165f36e..2b04f80 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -9,7 +9,10 @@ #include <winapi/path.hpp> #include <winapi/utf8.hpp> +#include <cstddef> +#include <cstdint> #include <cstring> +#include <stdexcept> #include <string> namespace winapi { @@ -32,6 +35,13 @@ struct CreateFileParams { return params; } + static CreateFileParams read_attributes() { + auto params = read(); + params.dwDesiredAccess = FILE_READ_ATTRIBUTES; + params.dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; + return params; + } + static CreateFileParams write() { CreateFileParams params; params.dwDesiredAccess = GENERIC_WRITE; @@ -87,6 +97,38 @@ Handle File::open_r(const CanonicalPath& path) { return open_file(to_system_path(path), CreateFileParams::read()); } +Handle File::open_read_attributes(const std::string& path) { + return open_file(to_system_path(path), CreateFileParams::read_attributes()); +} + +Handle File::open_read_attributes(const CanonicalPath& path) { + return open_file(to_system_path(path), CreateFileParams::read_attributes()); +} + +std::size_t File::get_size() const { + LARGE_INTEGER size; + + if (!GetFileSizeEx(get(), &size)) + throw error::windows(GetLastError(), "GetFileSizeEx"); + + if (size.QuadPart < 0 || size.QuadPart > SIZE_MAX) + throw std::runtime_error{"invalid file size"}; + return static_cast<std::size_t>(size.QuadPart); +} + +bool operator==(const FILE_ID_128& a, const FILE_ID_128& b) { + return 0 == std::memcmp(a.Identifier, b.Identifier, sizeof(a.Identifier)); +} + +File::ID File::query_id() const { + FILE_ID_INFO id; + + if (!GetFileInformationByHandleEx(get(), FileIdInfo, &id, sizeof(id))) + throw error::windows(GetLastError(), "GetFileInformationByHandleEx"); + + return {id}; +} + Handle File::open_w(const std::string& path) { return open_file(to_system_path(path), CreateFileParams::write()); } |