summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2022-04-13 23:05:39 +0200
committerCarl Hetherington <cth@carlh.net>2022-05-05 21:46:30 +0200
commit75002393c81ca0d26b07069e6f92e6f82753882f (patch)
treed6553ebb55bdc06e906eb849573f9b33ac158ac9 /src
parentd0d456fcae355a07ac27102ae9da2680bece6454 (diff)
Copy and use fix_long_path from DoM.
Diffstat (limited to 'src')
-rw-r--r--src/file.cc43
-rw-r--r--src/file.h3
2 files changed, 45 insertions, 1 deletions
diff --git a/src/file.cc b/src/file.cc
index fceb905b..c80f5e58 100644
--- a/src/file.cc
+++ b/src/file.cc
@@ -50,7 +50,7 @@ File::File(boost::filesystem::path path, std::string mode)
#ifdef LIBDCP_WINDOWS
std::wstring mode_wide(mode.begin(), mode.end());
/* c_str() here should give a UTF-16 string */
- _file = _wfopen(path.c_str(), mode_wide.c_str());
+ _file = _wfopen(fix_long_path(path).c_str(), mode_wide.c_str());
#else
_file = fopen(path.c_str(), mode.c_str());
#endif
@@ -104,3 +104,44 @@ File::operator bool() const
return _file != nullptr;
}
+
+/** Windows can't "by default" cope with paths longer than 260 characters, so if you pass such a path to
+ * any boost::filesystem method it will fail. There is a "fix" for this, which is to prepend
+ * the string \\?\ to the path. This will make it work, so long as:
+ * - the path is absolute.
+ * - the path only uses backslashes.
+ * - individual path components are "short enough" (probably less than 255 characters)
+ *
+ * See https://www.boost.org/doc/libs/1_57_0/libs/filesystem/doc/reference.html under
+ * "Warning: Long paths on Windows" for some details.
+ *
+ * Our fopen_boost uses this method to get this fix, but any other calls to boost::filesystem
+ * will not unless this method is explicitly called to pre-process the pathname.
+ */
+boost::filesystem::path
+dcp::fix_long_path (boost::filesystem::path long_path)
+{
+#ifdef LIBDCP_WINDOWS
+ using namespace boost::filesystem;
+
+ if (boost::algorithm::starts_with(long_path.string(), "\\\\")) {
+ /* This could mean it starts with \\ (i.e. a SMB path) or \\?\ (a long path)
+ * or a variety of other things... anyway, we'll leave it alone.
+ */
+ return long_path;
+ }
+
+ /* We have to make the path canonical but we can't call canonical() on the long path
+ * as it will fail. So we'll sort of do it ourselves (possibly badly).
+ */
+ path fixed = "\\\\?\\";
+ if (long_path.is_absolute()) {
+ fixed += long_path.make_preferred();
+ } else {
+ fixed += boost::filesystem::current_path() / long_path.make_preferred();
+ }
+ return fixed;
+#else
+ return long_path;
+#endif
+}
diff --git a/src/file.h b/src/file.h
index e50c6005..23204349 100644
--- a/src/file.h
+++ b/src/file.h
@@ -74,5 +74,8 @@ private:
};
+boost::filesystem::path fix_long_path(boost::filesystem::path long_path);
+
+
}