aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--include/winapi/file.hpp3
-rw-r--r--include/winapi/path.hpp25
-rw-r--r--include/winapi/stream.hpp4
-rw-r--r--src/file.cpp27
-rw-r--r--src/path.cpp47
-rw-r--r--src/stream.cpp7
6 files changed, 107 insertions, 6 deletions
diff --git a/include/winapi/file.hpp b/include/winapi/file.hpp
index 60a8f1d..221047b 100644
--- a/include/winapi/file.hpp
+++ b/include/winapi/file.hpp
@@ -6,6 +6,7 @@
#pragma once
#include "handle.hpp"
+#include "path.hpp"
#include <string>
#include <utility>
@@ -17,7 +18,9 @@ public:
explicit File(Handle&& handle) : Handle{std::move(handle)} {}
static Handle open_for_reading(const std::string&);
+ static Handle open_for_reading(const CanonicalPath&);
static Handle open_for_writing(const std::string&);
+ static Handle open_for_writing(const CanonicalPath&);
using Handle::close;
diff --git a/include/winapi/path.hpp b/include/winapi/path.hpp
new file mode 100644
index 0000000..f2b0aa9
--- /dev/null
+++ b/include/winapi/path.hpp
@@ -0,0 +1,25 @@
+// Copyright (c) 2020 Egor Tensin <Egor.Tensin@gmail.com>
+// This file is part of the "winapi-common" project.
+// For details, see https://github.com/egor-tensin/winapi-common.
+// Distributed under the MIT License.
+
+#pragma once
+
+#include <string>
+
+namespace winapi {
+
+class CanonicalPath {
+public:
+ static std::string canonicalize(const std::string&);
+
+ explicit CanonicalPath(const std::string&);
+
+ std::string get() const { return m_path; }
+ std::string path() const { return get(); }
+
+private:
+ std::string m_path;
+};
+
+} // namespace winapi
diff --git a/include/winapi/stream.hpp b/include/winapi/stream.hpp
index 6b4bc38..ed5b40c 100644
--- a/include/winapi/stream.hpp
+++ b/include/winapi/stream.hpp
@@ -6,6 +6,7 @@
#pragma once
#include "handle.hpp"
+#include "path.hpp"
#include "pipe.hpp"
#include <boost/config.hpp>
@@ -45,6 +46,7 @@ inline void swap(Stream& a, Stream& b) BOOST_NOEXCEPT_OR_NOTHROW {
struct Stdin : Stream {
Stdin();
explicit Stdin(const std::string& file);
+ explicit Stdin(const CanonicalPath& file);
explicit Stdin(Pipe&);
// VS 2013 won't generate these automatically.
@@ -62,6 +64,7 @@ struct Stdin : Stream {
struct Stdout : Stream {
Stdout();
explicit Stdout(const std::string& file);
+ explicit Stdout(const CanonicalPath& file);
explicit Stdout(Pipe&);
// VS 2013 won't generate these automatically.
@@ -79,6 +82,7 @@ struct Stdout : Stream {
struct Stderr : Stream {
Stderr();
explicit Stderr(const std::string& file);
+ explicit Stderr(const CanonicalPath& file);
explicit Stderr(Pipe&);
// VS 2013 won't generate these automatically.
diff --git a/src/file.cpp b/src/file.cpp
index cb9be81..a299d70 100644
--- a/src/file.cpp
+++ b/src/file.cpp
@@ -6,6 +6,7 @@
#include <winapi/error.hpp>
#include <winapi/file.hpp>
#include <winapi/handle.hpp>
+#include <winapi/path.hpp>
#include <winapi/utf8.hpp>
#include <cstring>
@@ -14,6 +15,14 @@
namespace winapi {
namespace {
+std::wstring to_system_path(const std::string& path) {
+ return widen(path);
+}
+
+std::wstring to_system_path(const CanonicalPath& path) {
+ return widen(R"(\\?\)" + path.get());
+}
+
struct CreateFileParams {
static CreateFileParams read() {
CreateFileParams params;
@@ -39,15 +48,13 @@ private:
CreateFileParams() = default;
};
-Handle open_file(const std::string& path, const CreateFileParams& params) {
- const auto unicode_path = LR"(\\?\)" + widen(path);
-
+Handle open_file(const std::wstring& path, const CreateFileParams& params) {
SECURITY_ATTRIBUTES attributes;
std::memset(&attributes, 0, sizeof(attributes));
attributes.nLength = sizeof(attributes);
attributes.bInheritHandle = TRUE;
- const auto handle = ::CreateFileW(unicode_path.c_str(),
+ const auto handle = ::CreateFileW(path.c_str(),
params.dwDesiredAccess,
params.dwShareMode,
&attributes,
@@ -65,11 +72,19 @@ Handle open_file(const std::string& path, const CreateFileParams& params) {
} // namespace
Handle File::open_for_reading(const std::string& path) {
- return open_file(path, CreateFileParams::read());
+ return open_file(to_system_path(path), CreateFileParams::read());
+}
+
+Handle File::open_for_reading(const CanonicalPath& path) {
+ return open_file(to_system_path(path), CreateFileParams::read());
}
Handle File::open_for_writing(const std::string& path) {
- return open_file(path, CreateFileParams::write());
+ return open_file(to_system_path(path), CreateFileParams::write());
+}
+
+Handle File::open_for_writing(const CanonicalPath& path) {
+ return open_file(to_system_path(path), CreateFileParams::write());
}
} // namespace winapi
diff --git a/src/path.cpp b/src/path.cpp
new file mode 100644
index 0000000..2c2deda
--- /dev/null
+++ b/src/path.cpp
@@ -0,0 +1,47 @@
+// Copyright (c) 2020 Egor Tensin <Egor.Tensin@gmail.com>
+// This file is part of the "winapi-common" project.
+// For details, see https://github.com/egor-tensin/winapi-common.
+// Distributed under the MIT License.
+
+#include <winapi/error.hpp>
+#include <winapi/path.hpp>
+#include <winapi/utf8.hpp>
+
+#include <windows.h>
+
+#include <string>
+#include <vector>
+
+namespace winapi {
+namespace {
+
+std::wstring do_canonicalize(const std::wstring& path) {
+ std::vector<wchar_t> buffer;
+ buffer.resize(MAX_PATH);
+
+ while (true) {
+ const auto nch = ::GetFullPathNameW(path.c_str(), buffer.size(), buffer.data(), NULL);
+
+ if (nch == 0) {
+ throw error::windows(GetLastError(), "GetFullPathNameW");
+ }
+
+ if (nch < buffer.size()) {
+ return {buffer.data(), nch};
+ }
+
+ if (nch > buffer.size()) {
+ buffer.resize(2 * buffer.size());
+ }
+ }
+}
+
+} // namespace
+
+CanonicalPath::CanonicalPath(const std::string& path) : m_path(canonicalize(path)) {}
+
+std::string CanonicalPath::canonicalize(const std::string& path) {
+ return narrow(do_canonicalize(widen(path)));
+}
+
+} // namespace winapi
diff --git a/src/stream.cpp b/src/stream.cpp
index b31635e..f9285e6 100644
--- a/src/stream.cpp
+++ b/src/stream.cpp
@@ -5,6 +5,7 @@
#include <winapi/file.hpp>
#include <winapi/handle.hpp>
+#include <winapi/path.hpp>
#include <winapi/stream.hpp>
#include <string>
@@ -21,10 +22,16 @@ Stderr::Stderr() : Stream{Handle::std_err()} {}
Stdin::Stdin(const std::string& path) : Stream{File::open_for_reading(path)} {}
+Stdin::Stdin(const CanonicalPath& path) : Stream{File::open_for_reading(path)} {}
+
Stdout::Stdout(const std::string& path) : Stream{File::open_for_writing(path)} {}
+Stdout::Stdout(const CanonicalPath& path) : Stream{File::open_for_writing(path)} {}
+
Stderr::Stderr(const std::string& path) : Stream{File::open_for_writing(path)} {}
+Stderr::Stderr(const CanonicalPath& path) : Stream{File::open_for_writing(path)} {}
+
Stdin::Stdin(Pipe& pipe) : Stream{std::move(pipe.read_end())} {
pipe.write_end().dont_inherit();
}