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
16 inline bool EnsureLongPath(nsAString
& aDosPath
) {
17 nsAutoString
inputPath(aDosPath
);
19 DWORD requiredLength
= GetLongPathNameW(
20 inputPath
.get(), reinterpret_cast<wchar_t*>(aDosPath
.BeginWriting()),
22 if (!requiredLength
) {
25 if (requiredLength
< aDosPath
.Length()) {
26 // When GetLongPathNameW deems the last argument too small,
27 // it returns a value, but when you pass that value back, it's
28 // satisfied and returns a number that's one smaller. If the above
29 // check was == instead of <, the loop would go on forever with
30 // GetLongPathNameW returning oscillating values!
31 aDosPath
.Truncate(requiredLength
);
34 aDosPath
.SetLength(requiredLength
);
38 inline bool NtPathToDosPath(const nsAString
& aNtPath
, nsAString
& aDosPath
) {
40 if (aNtPath
.IsEmpty()) {
43 constexpr auto symLinkPrefix
= u
"\\??\\"_ns
;
44 uint32_t ntPathLen
= aNtPath
.Length();
45 uint32_t symLinkPrefixLen
= symLinkPrefix
.Length();
46 if (ntPathLen
>= 6 && aNtPath
.CharAt(5) == L
':' &&
47 ntPathLen
>= symLinkPrefixLen
&&
48 Substring(aNtPath
, 0, symLinkPrefixLen
).Equals(symLinkPrefix
)) {
49 // Symbolic link for DOS device. Just strip off the prefix.
54 nsAutoString logicalDrives
;
56 DWORD requiredLength
= GetLogicalDriveStringsW(
57 logicalDrives
.Length(),
58 reinterpret_cast<wchar_t*>(logicalDrives
.BeginWriting()));
59 if (!requiredLength
) {
62 if (requiredLength
< logicalDrives
.Length()) {
63 // When GetLogicalDriveStringsW deems the first argument too small,
64 // it returns a value, but when you pass that value back, it's
65 // satisfied and returns a number that's one smaller. If the above
66 // check was == instead of <, the loop would go on forever with
67 // GetLogicalDriveStringsW returning oscillating values!
68 logicalDrives
.Truncate(requiredLength
);
69 // logicalDrives now has the format "C:\\\0D:\\\0Z:\\\0". That is,
70 // the sequence drive letter, colon, backslash, U+0000 repeats.
73 logicalDrives
.SetLength(requiredLength
);
76 const char16_t
* cur
= logicalDrives
.BeginReading();
77 const char16_t
* end
= logicalDrives
.EndReading();
79 targetPath
.SetLength(MAX_PATH
);
80 wchar_t driveTemplate
[] = L
" :";
82 // Unfortunately QueryDosDevice doesn't support the idiom for querying the
83 // output buffer size, so it may require retries.
84 driveTemplate
[0] = *cur
;
85 DWORD targetPathLen
= 0;
86 SetLastError(ERROR_SUCCESS
);
88 targetPathLen
= QueryDosDeviceW(
89 driveTemplate
, reinterpret_cast<wchar_t*>(targetPath
.BeginWriting()),
91 if (targetPathLen
|| GetLastError() != ERROR_INSUFFICIENT_BUFFER
) {
94 targetPath
.SetLength(targetPath
.Length() * 2);
97 // Need to use wcslen here because targetPath contains embedded NULL chars
98 size_t firstTargetPathLen
= wcslen(targetPath
.get());
99 const char16_t
* pathComponent
=
100 aNtPath
.BeginReading() + firstTargetPathLen
;
101 bool found
= _wcsnicmp(char16ptr_t(aNtPath
.BeginReading()),
102 targetPath
.get(), firstTargetPathLen
) == 0 &&
103 *pathComponent
== L
'\\';
105 aDosPath
= driveTemplate
;
106 aDosPath
+= pathComponent
;
107 return EnsureLongPath(aDosPath
);
110 // Find the next U+0000 within the logical string
112 // This loop skips the drive letter, the colon
113 // and the backslash.
116 // Skip over the U+0000 that ends a drive entry
117 // within the logical string
120 // Try to handle UNC paths. NB: This must happen after we've checked drive
121 // mappings in case a UNC path is mapped to a drive!
122 constexpr auto uncPrefix
= u
"\\\\"_ns
;
123 constexpr auto deviceMupPrefix
= u
"\\Device\\Mup\\"_ns
;
124 if (StringBeginsWith(aNtPath
, deviceMupPrefix
)) {
125 aDosPath
= uncPrefix
;
126 aDosPath
+= Substring(aNtPath
, deviceMupPrefix
.Length());
129 constexpr auto deviceLanmanRedirectorPrefix
=
130 u
"\\Device\\LanmanRedirector\\"_ns
;
131 if (StringBeginsWith(aNtPath
, deviceLanmanRedirectorPrefix
)) {
132 aDosPath
= uncPrefix
;
133 aDosPath
+= Substring(aNtPath
, deviceLanmanRedirectorPrefix
.Length());
139 bool HandleToFilename(HANDLE aHandle
, const LARGE_INTEGER
& aOffset
,
140 nsAString
& aFilename
);
142 uint32_t GetExecutableArchitecture(const wchar_t* aPath
);
144 } // namespace mozilla
146 #endif // mozilla_FileUtilsWin_h