1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_FileUtilsWin_h
8 #define mozilla_FileUtilsWin_h
12 #include "mozilla/Scoped.h"
17 inline bool EnsureLongPath(nsAString
& aDosPath
) {
18 nsAutoString
inputPath(aDosPath
);
20 DWORD requiredLength
= GetLongPathNameW(
21 inputPath
.get(), reinterpret_cast<wchar_t*>(aDosPath
.BeginWriting()),
23 if (!requiredLength
) {
26 if (requiredLength
< aDosPath
.Length()) {
27 // When GetLongPathNameW deems the last argument too small,
28 // it returns a value, but when you pass that value back, it's
29 // satisfied and returns a number that's one smaller. If the above
30 // check was == instead of <, the loop would go on forever with
31 // GetLongPathNameW returning oscillating values!
32 aDosPath
.Truncate(requiredLength
);
35 aDosPath
.SetLength(requiredLength
);
39 inline bool NtPathToDosPath(const nsAString
& aNtPath
, nsAString
& aDosPath
) {
41 if (aNtPath
.IsEmpty()) {
44 constexpr auto symLinkPrefix
= u
"\\??\\"_ns
;
45 uint32_t ntPathLen
= aNtPath
.Length();
46 uint32_t symLinkPrefixLen
= symLinkPrefix
.Length();
47 if (ntPathLen
>= 6 && aNtPath
.CharAt(5) == L
':' &&
48 ntPathLen
>= symLinkPrefixLen
&&
49 Substring(aNtPath
, 0, symLinkPrefixLen
).Equals(symLinkPrefix
)) {
50 // Symbolic link for DOS device. Just strip off the prefix.
55 nsAutoString logicalDrives
;
57 DWORD requiredLength
= GetLogicalDriveStringsW(
58 logicalDrives
.Length(),
59 reinterpret_cast<wchar_t*>(logicalDrives
.BeginWriting()));
60 if (!requiredLength
) {
63 if (requiredLength
< logicalDrives
.Length()) {
64 // When GetLogicalDriveStringsW deems the first argument too small,
65 // it returns a value, but when you pass that value back, it's
66 // satisfied and returns a number that's one smaller. If the above
67 // check was == instead of <, the loop would go on forever with
68 // GetLogicalDriveStringsW returning oscillating values!
69 logicalDrives
.Truncate(requiredLength
);
70 // logicalDrives now has the format "C:\\\0D:\\\0Z:\\\0". That is,
71 // the sequence drive letter, colon, backslash, U+0000 repeats.
74 logicalDrives
.SetLength(requiredLength
);
77 const char16_t
* cur
= logicalDrives
.BeginReading();
78 const char16_t
* end
= logicalDrives
.EndReading();
80 targetPath
.SetLength(MAX_PATH
);
81 wchar_t driveTemplate
[] = L
" :";
83 // Unfortunately QueryDosDevice doesn't support the idiom for querying the
84 // output buffer size, so it may require retries.
85 driveTemplate
[0] = *cur
;
86 DWORD targetPathLen
= 0;
87 SetLastError(ERROR_SUCCESS
);
89 targetPathLen
= QueryDosDeviceW(
90 driveTemplate
, reinterpret_cast<wchar_t*>(targetPath
.BeginWriting()),
92 if (targetPathLen
|| GetLastError() != ERROR_INSUFFICIENT_BUFFER
) {
95 targetPath
.SetLength(targetPath
.Length() * 2);
98 // Need to use wcslen here because targetPath contains embedded NULL chars
99 size_t firstTargetPathLen
= wcslen(targetPath
.get());
100 const char16_t
* pathComponent
=
101 aNtPath
.BeginReading() + firstTargetPathLen
;
102 bool found
= _wcsnicmp(char16ptr_t(aNtPath
.BeginReading()),
103 targetPath
.get(), firstTargetPathLen
) == 0 &&
104 *pathComponent
== L
'\\';
106 aDosPath
= driveTemplate
;
107 aDosPath
+= pathComponent
;
108 return EnsureLongPath(aDosPath
);
111 // Find the next U+0000 within the logical string
113 // This loop skips the drive letter, the colon
114 // and the backslash.
117 // Skip over the U+0000 that ends a drive entry
118 // within the logical string
121 // Try to handle UNC paths. NB: This must happen after we've checked drive
122 // mappings in case a UNC path is mapped to a drive!
123 constexpr auto uncPrefix
= u
"\\\\"_ns
;
124 constexpr auto deviceMupPrefix
= u
"\\Device\\Mup\\"_ns
;
125 if (StringBeginsWith(aNtPath
, deviceMupPrefix
)) {
126 aDosPath
= uncPrefix
;
127 aDosPath
+= Substring(aNtPath
, deviceMupPrefix
.Length());
130 constexpr auto deviceLanmanRedirectorPrefix
=
131 u
"\\Device\\LanmanRedirector\\"_ns
;
132 if (StringBeginsWith(aNtPath
, deviceLanmanRedirectorPrefix
)) {
133 aDosPath
= uncPrefix
;
134 aDosPath
+= Substring(aNtPath
, deviceLanmanRedirectorPrefix
.Length());
140 bool HandleToFilename(HANDLE aHandle
, const LARGE_INTEGER
& aOffset
,
141 nsAString
& aFilename
);
143 uint32_t GetExecutableArchitecture(const wchar_t* aPath
);
145 } // namespace mozilla
147 #endif // mozilla_FileUtilsWin_h