diff options
Diffstat (limited to 'xpcom/io/FileUtilsWin.h')
-rw-r--r-- | xpcom/io/FileUtilsWin.h | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/xpcom/io/FileUtilsWin.h b/xpcom/io/FileUtilsWin.h new file mode 100644 index 000000000..e32e9fd6e --- /dev/null +++ b/xpcom/io/FileUtilsWin.h @@ -0,0 +1,144 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_FileUtilsWin_h +#define mozilla_FileUtilsWin_h + +#include <windows.h> + +#include "mozilla/Scoped.h" +#include "nsStringGlue.h" + +namespace mozilla { + +inline bool +EnsureLongPath(nsAString& aDosPath) +{ + uint32_t aDosPathOriginalLen = aDosPath.Length(); + auto inputPath = PromiseFlatString(aDosPath); + // Try to get the long path, or else get the required length of the long path + DWORD longPathLen = GetLongPathNameW(inputPath.get(), + reinterpret_cast<wchar_t*>(aDosPath.BeginWriting()), + aDosPathOriginalLen); + if (longPathLen == 0) { + return false; + } + aDosPath.SetLength(longPathLen); + if (longPathLen <= aDosPathOriginalLen) { + // Our string happened to be long enough for the first call to succeed. + return true; + } + // Now we have a large enough buffer, get the actual string + longPathLen = GetLongPathNameW(inputPath.get(), + reinterpret_cast<wchar_t*>(aDosPath.BeginWriting()), aDosPath.Length()); + if (longPathLen == 0) { + return false; + } + // This success check should always be less-than because longPathLen excludes + // the null terminator on success, but includes it in the first call that + // returned the required size. + if (longPathLen < aDosPath.Length()) { + aDosPath.SetLength(longPathLen); + return true; + } + // We shouldn't reach this, but if we do then it's a failure! + return false; +} + +inline bool +NtPathToDosPath(const nsAString& aNtPath, nsAString& aDosPath) +{ + aDosPath.Truncate(); + if (aNtPath.IsEmpty()) { + return true; + } + NS_NAMED_LITERAL_STRING(symLinkPrefix, "\\??\\"); + uint32_t ntPathLen = aNtPath.Length(); + uint32_t symLinkPrefixLen = symLinkPrefix.Length(); + if (ntPathLen >= 6 && aNtPath.CharAt(5) == L':' && + ntPathLen >= symLinkPrefixLen && + Substring(aNtPath, 0, symLinkPrefixLen).Equals(symLinkPrefix)) { + // Symbolic link for DOS device. Just strip off the prefix. + aDosPath = aNtPath; + aDosPath.Cut(0, 4); + return true; + } + nsAutoString logicalDrives; + DWORD len = 0; + while (true) { + len = GetLogicalDriveStringsW( + len, reinterpret_cast<wchar_t*>(logicalDrives.BeginWriting())); + if (!len) { + return false; + } else if (len > logicalDrives.Length()) { + logicalDrives.SetLength(len); + } else { + break; + } + } + const char16_t* cur = logicalDrives.BeginReading(); + const char16_t* end = logicalDrives.EndReading(); + nsString targetPath; + targetPath.SetLength(MAX_PATH); + wchar_t driveTemplate[] = L" :"; + do { + // Unfortunately QueryDosDevice doesn't support the idiom for querying the + // output buffer size, so it may require retries. + driveTemplate[0] = *cur; + DWORD targetPathLen = 0; + SetLastError(ERROR_SUCCESS); + while (true) { + targetPathLen = QueryDosDeviceW(driveTemplate, + reinterpret_cast<wchar_t*>(targetPath.BeginWriting()), + targetPath.Length()); + if (targetPathLen || GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + break; + } + targetPath.SetLength(targetPath.Length() * 2); + } + if (targetPathLen) { + // Need to use wcslen here because targetPath contains embedded NULL chars + size_t firstTargetPathLen = wcslen(targetPath.get()); + const char16_t* pathComponent = aNtPath.BeginReading() + + firstTargetPathLen; + bool found = _wcsnicmp(char16ptr_t(aNtPath.BeginReading()), targetPath.get(), + firstTargetPathLen) == 0 && + *pathComponent == L'\\'; + if (found) { + aDosPath = driveTemplate; + aDosPath += pathComponent; + return EnsureLongPath(aDosPath); + } + } + // Advance to the next NUL character in logicalDrives + while (*cur++); + } while (cur != end); + // Try to handle UNC paths. NB: This must happen after we've checked drive + // mappings in case a UNC path is mapped to a drive! + NS_NAMED_LITERAL_STRING(uncPrefix, "\\\\"); + NS_NAMED_LITERAL_STRING(deviceMupPrefix, "\\Device\\Mup\\"); + if (StringBeginsWith(aNtPath, deviceMupPrefix)) { + aDosPath = uncPrefix; + aDosPath += Substring(aNtPath, deviceMupPrefix.Length()); + return true; + } + NS_NAMED_LITERAL_STRING(deviceLanmanRedirectorPrefix, + "\\Device\\LanmanRedirector\\"); + if (StringBeginsWith(aNtPath, deviceLanmanRedirectorPrefix)) { + aDosPath = uncPrefix; + aDosPath += Substring(aNtPath, deviceLanmanRedirectorPrefix.Length()); + return true; + } + return false; +} + +bool +HandleToFilename(HANDLE aHandle, const LARGE_INTEGER& aOffset, + nsAString& aFilename); + +} // namespace mozilla + +#endif // mozilla_FileUtilsWin_h |