1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
// **************************************************************************
// * This file is part of the FreeFileSync project. It is distributed under *
// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
#ifndef LONGPATHPREFIX_H_INCLUDED
#define LONGPATHPREFIX_H_INCLUDED
#include "win.h"
#include "zstring.h"
namespace zen
{
//handle filenames longer-equal 260 (== MAX_PATH) characters by applying \\?\-prefix; see: http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx#maxpath
/*
1. path must be absolute
2. if path is smaller than MAX_PATH nothing is changed! caveat: FindFirstFile() "Prepending the string "\\?\" does not allow access to the root directory."
3. path may already contain \\?\-prefix
*/
Zstring applyLongPathPrefix(const Zstring& path); //noexcept
Zstring applyLongPathPrefixCreateDir(const Zstring& path); //noexcept -> special rule for ::CreateDirectory()/::CreateDirectoryEx(): MAX_PATH - 12(=^ 8.3 filename) is threshold
Zstring removeLongPathPrefix(const Zstring& path); //noexcept
Zstring ntPathToWin32Path(const Zstring& path); //noexcept
/*
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx#NT_Namespaces
As used by GetModuleFileNameEx() and symlinks (FSCTL_GET_REPARSE_POINT):
E.g.:
\??\C:\folder -> C:\folder
\SystemRoot -> C:\Windows
*/
}
//################## implementation ##################
//there are two flavors of long path prefix: one for UNC paths, one for regular paths
const wchar_t LONG_PATH_PREFIX [] = L"\\\\?\\"; //don't use Zstring as global constant: avoid static initialization order problem in global namespace!
const wchar_t LONG_PATH_PREFIX_UNC[] = L"\\\\?\\UNC"; //
template <size_t maxPath> inline
Zstring applyLongPathPrefixImpl(const Zstring& path)
{
assert(!path.empty()); //nicely check almost all WinAPI accesses!
assert(!zen::isWhiteSpace(path[0]));
//http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx#naming_conventions))
/*
- special names like ".NUL" create all kinds of trouble (e.g. CreateDirectory() reports success, but does nothing)
unless prefix is supplied => accept as limitation
*/
if (path.length() >= maxPath || //maximum allowed path length without prefix is (MAX_PATH - 1)
endsWith(path, L' ') || //by default all Win32 APIs trim trailing spaces and period, unless long path prefix is supplied!
endsWith(path, L'.')) //note: adding long path prefix might screw up relative paths "." and ".."!
if (!startsWith(path, LONG_PATH_PREFIX))
{
if (startsWith(path, L"\\\\")) //UNC-name, e.g. \\zenju-pc\Users
return LONG_PATH_PREFIX_UNC + afterFirst(path, L'\\'); //convert to \\?\UNC\zenju-pc\Users
else
return LONG_PATH_PREFIX + path; //prepend \\?\ prefix
}
return path; //fallback
}
inline
Zstring zen::applyLongPathPrefix(const Zstring& path)
{
return applyLongPathPrefixImpl<MAX_PATH>(path);
}
inline
Zstring zen::applyLongPathPrefixCreateDir(const Zstring& path) //noexcept
{
//special rule for ::CreateDirectoryEx(): MAX_PATH - 12(=^ 8.3 filename) is threshold
return applyLongPathPrefixImpl<MAX_PATH - 12> (path);
}
inline
Zstring zen::removeLongPathPrefix(const Zstring& path) //noexcept
{
if (zen::startsWith(path, LONG_PATH_PREFIX))
{
if (zen::startsWith(path, LONG_PATH_PREFIX_UNC)) //UNC-name
return replaceCpy(path, LONG_PATH_PREFIX_UNC, Zstr("\\"), false);
else
return replaceCpy(path, LONG_PATH_PREFIX, Zstr(""), false);
}
return path; //fallback
}
inline
Zstring zen::ntPathToWin32Path(const Zstring& path) //noexcept
{
if (startsWith(path, L"\\??\\"))
return Zstring(path.c_str() + 4, path.length() - 4);
if (startsWith(path, L"\\SystemRoot\\"))
{
DWORD bufSize = ::GetEnvironmentVariable(L"SystemRoot", nullptr, 0);
if (bufSize > 0)
{
std::vector<wchar_t> buf(bufSize);
DWORD charsWritten = ::GetEnvironmentVariable(L"SystemRoot", //_In_opt_ LPCTSTR lpName,
&buf[0], //_Out_opt_ LPTSTR lpBuffer,
bufSize); //_In_ DWORD nSize
if (charsWritten != 0 && charsWritten < bufSize)
return replaceCpy(path, L"\\SystemRoot\\", appendSeparator(Zstring(&buf[0], charsWritten)), false);
}
}
return path;
}
#endif //LONGPATHPREFIX_H_INCLUDED
|