Commit 5676ec29 authored by Gijs Kruitbosch's avatar Gijs Kruitbosch
Browse files

Bug 1689598. a=jcristau

Differential Revision: https://phabricator.services.mozilla.com/D103523
parent 3f17a3b3
......@@ -40,6 +40,13 @@ XPCOMUtils.defineLazyServiceGetter(
"nsIProtocolHandler"
);
XPCOMUtils.defineLazyServiceGetter(
this,
"fileProtocolHandler",
"@mozilla.org/network/protocol;1?name=file",
"nsIFileProtocolHandler"
);
XPCOMUtils.defineLazyPreferenceGetter(
this,
"fixupSchemeTypos",
......@@ -860,7 +867,9 @@ function fileURIFixup(uriString) {
// object. The URL of that is returned if successful.
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
file.initWithPath(uriString);
return Services.io.newFileURI(file);
return Services.io.newURI(
fileProtocolHandler.getURLSpecFromActualFile(file)
);
} catch (ex) {
// Not a file uri.
}
......
......@@ -6,6 +6,7 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/TextUtils.h"
#include "mozilla/UniquePtrExtensions.h"
#include "mozilla/Utf8.h"
......@@ -327,6 +328,109 @@ static bool IsShortcutPath(const nsAString& aPath) {
return len >= 4 && (StringTail(aPath, 4).LowerCaseEqualsASCII(".lnk"));
}
// Check whether a path is a volume root. Expects paths to be \-terminated.
static bool IsRootPath(const nsAString& aPath) {
// Easy cases first:
if (aPath.Last() != L'\\') {
return false;
}
if (StringEndsWith(aPath, u":\\"_ns)) {
return true;
}
nsAString::const_iterator begin, end;
aPath.BeginReading(begin);
aPath.EndReading(end);
// We know we've got a trailing slash, skip that:
end--;
// Find the next last slash:
if (RFindInReadable(u"\\"_ns, begin, end)) {
// Reset iterator:
aPath.EndReading(end);
end--;
auto lastSegment = Substring(++begin, end);
if (lastSegment.IsEmpty()) {
return false;
}
// Check if we end with e.g. "c$", a drive letter in UNC or network shares
if (lastSegment.Last() == L'$' && lastSegment.Length() == 2 &&
IsAsciiAlpha(lastSegment.First())) {
return true;
}
// Volume GUID paths:
if (StringBeginsWith(lastSegment, u"Volume{"_ns) &&
lastSegment.Last() == L'}') {
return true;
}
}
return false;
}
static auto kSpecialNTFSFilesInRoot = {
u"$MFT"_ns, u"$MFTMirr"_ns, u"$LogFile"_ns, u"$Volume"_ns,
u"$AttrDef"_ns, u"$Bitmap"_ns, u"$Boot"_ns, u"$BadClus"_ns,
u"$Secure"_ns, u"$UpCase"_ns, u"$Extend"_ns};
static bool IsSpecialNTFSPath(const nsAString& aFilePath) {
nsAString::const_iterator begin, end;
aFilePath.BeginReading(begin);
aFilePath.EndReading(end);
auto iter = begin;
// Early exit if there's no '$' (common case)
if (!FindCharInReadable(L'$', iter, end)) {
return false;
}
iter = begin;
// Any use of ':$' is illegal in filenames anyway; while we support some
// ADS stuff (ie ":Zone.Identifier"), none of them use the ':$' syntax:
if (FindInReadable(u":$"_ns, iter, end)) {
return true;
}
auto normalized = mozilla::MakeUniqueFallible<wchar_t[]>(MAX_PATH);
if (!normalized) {
return true;
}
auto flatPath = PromiseFlatString(aFilePath);
auto fullPathRV =
GetFullPathNameW(flatPath.get(), MAX_PATH - 1, normalized.get(), nullptr);
if (fullPathRV == 0 || fullPathRV > MAX_PATH - 1) {
return false;
}
nsString normalizedPath(normalized.get());
normalizedPath.BeginReading(begin);
normalizedPath.EndReading(end);
iter = begin;
auto kDelimiters = u"\\:"_ns;
while (iter != end && FindCharInReadable(L'$', iter, end)) {
for (auto str : kSpecialNTFSFilesInRoot) {
if (StringBeginsWith(Substring(iter, end), str,
nsCaseInsensitiveStringComparator)) {
// If we're enclosed by separators or the beginning/end of the string,
// this is one of the special files. Check if we're on a volume root.
auto iterCopy = iter;
iterCopy.advance(str.Length());
// We check for both \ and : here because the filename could be
// followd by a colon and a stream name/type, which shouldn't affect
// our check:
if (iterCopy == end || kDelimiters.Contains(*iterCopy)) {
iterCopy = iter;
// At the start of this path component, we don't need to care about
// colons: we would have caught those in the check for `:$` above.
if (iterCopy == begin || *(--iterCopy) == L'\\') {
return IsRootPath(Substring(begin, iter));
}
}
}
}
iter++;
}
return false;
}
//-----------------------------------------------------------------------------
// We need the following three definitions to make |OpenFile| convert a file
// handle to an NSPR file descriptor correctly when |O_APPEND| flag is
......@@ -967,6 +1071,10 @@ nsLocalFile::InitWithPath(const nsAString& aFilePath) {
}
}
if (IsSpecialNTFSPath(aFilePath)) {
return NS_ERROR_FILE_UNRECOGNIZED_PATH;
}
mWorkingPath = aFilePath;
// kill any trailing '\'
if (mWorkingPath.Last() == L'\\') {
......@@ -1292,6 +1400,12 @@ nsresult nsLocalFile::AppendInternal(const nsString& aNode,
mWorkingPath.Append('\\');
mWorkingPath.Append(aNode);
if (IsSpecialNTFSPath(mWorkingPath)) {
// Revert changes to mWorkingPath:
mWorkingPath.SetLength(mWorkingPath.Length() - aNode.Length() - 1);
return NS_ERROR_FILE_UNRECOGNIZED_PATH;
}
return NS_OK;
}
......@@ -1503,10 +1617,17 @@ nsLocalFile::SetLeafName(const nsAString& aLeafName) {
// cannot use nsCString::RFindChar() due to 0x5c problem
int32_t offset = mWorkingPath.RFindChar(L'\\');
nsString newDir;
if (offset) {
mWorkingPath.Truncate(offset + 1);
newDir = Substring(mWorkingPath, 0, offset + 1) + aLeafName;
} else {
newDir = mWorkingPath + aLeafName;
}
if (IsSpecialNTFSPath(newDir)) {
return NS_ERROR_FILE_UNRECOGNIZED_PATH;
}
mWorkingPath.Append(aLeafName);
mWorkingPath.Assign(newDir);
return NS_OK;
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment