Fix typo in 9b54bd30006c008b4a951331b273613d5bac3abf
[pm.git] / xpcom / io / FileUtilsWin.h
blobe32e9fd6ea7c59d31b1ad67b2aa1f58c6e381852
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
10 #include <windows.h>
12 #include "mozilla/Scoped.h"
13 #include "nsStringGlue.h"
15 namespace mozilla {
17 inline bool
18 EnsureLongPath(nsAString& aDosPath)
20 uint32_t aDosPathOriginalLen = aDosPath.Length();
21 auto inputPath = PromiseFlatString(aDosPath);
22 // Try to get the long path, or else get the required length of the long path
23 DWORD longPathLen = GetLongPathNameW(inputPath.get(),
24 reinterpret_cast<wchar_t*>(aDosPath.BeginWriting()),
25 aDosPathOriginalLen);
26 if (longPathLen == 0) {
27 return false;
29 aDosPath.SetLength(longPathLen);
30 if (longPathLen <= aDosPathOriginalLen) {
31 // Our string happened to be long enough for the first call to succeed.
32 return true;
34 // Now we have a large enough buffer, get the actual string
35 longPathLen = GetLongPathNameW(inputPath.get(),
36 reinterpret_cast<wchar_t*>(aDosPath.BeginWriting()), aDosPath.Length());
37 if (longPathLen == 0) {
38 return false;
40 // This success check should always be less-than because longPathLen excludes
41 // the null terminator on success, but includes it in the first call that
42 // returned the required size.
43 if (longPathLen < aDosPath.Length()) {
44 aDosPath.SetLength(longPathLen);
45 return true;
47 // We shouldn't reach this, but if we do then it's a failure!
48 return false;
51 inline bool
52 NtPathToDosPath(const nsAString& aNtPath, nsAString& aDosPath)
54 aDosPath.Truncate();
55 if (aNtPath.IsEmpty()) {
56 return true;
58 NS_NAMED_LITERAL_STRING(symLinkPrefix, "\\??\\");
59 uint32_t ntPathLen = aNtPath.Length();
60 uint32_t symLinkPrefixLen = symLinkPrefix.Length();
61 if (ntPathLen >= 6 && aNtPath.CharAt(5) == L':' &&
62 ntPathLen >= symLinkPrefixLen &&
63 Substring(aNtPath, 0, symLinkPrefixLen).Equals(symLinkPrefix)) {
64 // Symbolic link for DOS device. Just strip off the prefix.
65 aDosPath = aNtPath;
66 aDosPath.Cut(0, 4);
67 return true;
69 nsAutoString logicalDrives;
70 DWORD len = 0;
71 while (true) {
72 len = GetLogicalDriveStringsW(
73 len, reinterpret_cast<wchar_t*>(logicalDrives.BeginWriting()));
74 if (!len) {
75 return false;
76 } else if (len > logicalDrives.Length()) {
77 logicalDrives.SetLength(len);
78 } else {
79 break;
82 const char16_t* cur = logicalDrives.BeginReading();
83 const char16_t* end = logicalDrives.EndReading();
84 nsString targetPath;
85 targetPath.SetLength(MAX_PATH);
86 wchar_t driveTemplate[] = L" :";
87 do {
88 // Unfortunately QueryDosDevice doesn't support the idiom for querying the
89 // output buffer size, so it may require retries.
90 driveTemplate[0] = *cur;
91 DWORD targetPathLen = 0;
92 SetLastError(ERROR_SUCCESS);
93 while (true) {
94 targetPathLen = QueryDosDeviceW(driveTemplate,
95 reinterpret_cast<wchar_t*>(targetPath.BeginWriting()),
96 targetPath.Length());
97 if (targetPathLen || GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
98 break;
100 targetPath.SetLength(targetPath.Length() * 2);
102 if (targetPathLen) {
103 // Need to use wcslen here because targetPath contains embedded NULL chars
104 size_t firstTargetPathLen = wcslen(targetPath.get());
105 const char16_t* pathComponent = aNtPath.BeginReading() +
106 firstTargetPathLen;
107 bool found = _wcsnicmp(char16ptr_t(aNtPath.BeginReading()), targetPath.get(),
108 firstTargetPathLen) == 0 &&
109 *pathComponent == L'\\';
110 if (found) {
111 aDosPath = driveTemplate;
112 aDosPath += pathComponent;
113 return EnsureLongPath(aDosPath);
116 // Advance to the next NUL character in logicalDrives
117 while (*cur++);
118 } while (cur != end);
119 // Try to handle UNC paths. NB: This must happen after we've checked drive
120 // mappings in case a UNC path is mapped to a drive!
121 NS_NAMED_LITERAL_STRING(uncPrefix, "\\\\");
122 NS_NAMED_LITERAL_STRING(deviceMupPrefix, "\\Device\\Mup\\");
123 if (StringBeginsWith(aNtPath, deviceMupPrefix)) {
124 aDosPath = uncPrefix;
125 aDosPath += Substring(aNtPath, deviceMupPrefix.Length());
126 return true;
128 NS_NAMED_LITERAL_STRING(deviceLanmanRedirectorPrefix,
129 "\\Device\\LanmanRedirector\\");
130 if (StringBeginsWith(aNtPath, deviceLanmanRedirectorPrefix)) {
131 aDosPath = uncPrefix;
132 aDosPath += Substring(aNtPath, deviceLanmanRedirectorPrefix.Length());
133 return true;
135 return false;
138 bool
139 HandleToFilename(HANDLE aHandle, const LARGE_INTEGER& aOffset,
140 nsAString& aFilename);
142 } // namespace mozilla
144 #endif // mozilla_FileUtilsWin_h