@@ -98,6 +98,68 @@ constexpr bool IsWindowsDeviceRoot(const char c) noexcept {
9898 return (c >= ' a' && c <= ' z' ) || (c >= ' A' && c <= ' Z' );
9999}
100100
101+ enum class WindowsNamespacedPathType {
102+ kNotNamespaced ,
103+ kDriveAbsolutePath ,
104+ kUNCPath ,
105+ kOtherNamespacedPath ,
106+ };
107+
108+ static WindowsNamespacedPathType ClassifyWindowsNamespacedPath (
109+ std::string_view path) {
110+ if (!(path.size () >= 4 && path[0 ] == ' \\ ' && path[1 ] == ' \\ ' &&
111+ path[2 ] == ' ?' && path[3 ] == ' \\ ' )) {
112+ return WindowsNamespacedPathType::kNotNamespaced ;
113+ }
114+
115+ if (path.size () >= 7 && IsWindowsDeviceRoot (path[4 ]) && path[5 ] == ' :' &&
116+ IsPathSeparator (path[6 ])) {
117+ return WindowsNamespacedPathType::kDriveAbsolutePath ;
118+ }
119+
120+ if (path.size () >= 8 && ToLower (path[4 ]) == ' u' &&
121+ ToLower (path[5 ]) == ' n' && ToLower (path[6 ]) == ' c' &&
122+ path[7 ] == ' \\ ' ) {
123+ size_t i = 8 ;
124+ const size_t server_start = i;
125+ while (i < path.size () && !IsPathSeparator (path[i])) {
126+ i++;
127+ }
128+ if (i == server_start || i == path.size ()) {
129+ return WindowsNamespacedPathType::kOtherNamespacedPath ;
130+ }
131+
132+ while (i < path.size () && IsPathSeparator (path[i])) {
133+ i++;
134+ }
135+ const size_t share_start = i;
136+ while (i < path.size () && !IsPathSeparator (path[i])) {
137+ i++;
138+ }
139+ if (i == share_start) {
140+ return WindowsNamespacedPathType::kOtherNamespacedPath ;
141+ }
142+
143+ return WindowsNamespacedPathType::kUNCPath ;
144+ }
145+
146+ return WindowsNamespacedPathType::kOtherNamespacedPath ;
147+ }
148+
149+ static void StripExtendedPathPrefixForPathResolve (std::string& path) {
150+ switch (ClassifyWindowsNamespacedPath (path)) {
151+ case WindowsNamespacedPathType::kDriveAbsolutePath :
152+ path = path.substr (4 );
153+ return ;
154+ case WindowsNamespacedPathType::kUNCPath :
155+ path = " \\\\ " + path.substr (8 );
156+ return ;
157+ case WindowsNamespacedPathType::kNotNamespaced :
158+ case WindowsNamespacedPathType::kOtherNamespacedPath :
159+ return ;
160+ }
161+ }
162+
101163std::string PathResolve (Environment* env,
102164 const std::vector<std::string_view>& paths) {
103165 std::string resolvedDevice = " " ;
@@ -132,6 +194,8 @@ std::string PathResolve(Environment* env,
132194 }
133195 }
134196
197+ StripExtendedPathPrefixForPathResolve (path);
198+
135199 const size_t len = path.length ();
136200 int rootEnd = 0 ;
137201 std::string device = " " ;
@@ -330,11 +394,16 @@ void ToNamespacedPath(Environment* env, BufferValue* path) {
330394// namespace-prefixed path.
331395void FromNamespacedPath (std::string* path) {
332396#ifdef _WIN32
333- if (path->starts_with (" \\\\ ?\\ UNC\\ " )) {
334- *path = path->substr (8 );
335- path->insert (0 , " \\\\ " );
336- } else if (path->starts_with (" \\\\ ?\\ " )) {
337- *path = path->substr (4 );
397+ switch (ClassifyWindowsNamespacedPath (*path)) {
398+ case WindowsNamespacedPathType::kUNCPath :
399+ *path = " \\\\ " + path->substr (8 );
400+ return ;
401+ case WindowsNamespacedPathType::kDriveAbsolutePath :
402+ *path = path->substr (4 );
403+ return ;
404+ case WindowsNamespacedPathType::kNotNamespaced :
405+ case WindowsNamespacedPathType::kOtherNamespacedPath :
406+ return ;
338407 }
339408#endif
340409}
0 commit comments