зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1689598 r=tkikuchi,mhowell,dmajor,valentin
Differential Revision: https://phabricator.services.mozilla.com/D103523
This commit is contained in:
Родитель
5e6c5a38ff
Коммит
7f3e59e909
|
@ -43,6 +43,13 @@ XPCOMUtils.defineLazyServiceGetter(
|
|||
"nsIProtocolHandler"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
"fileProtocolHandler",
|
||||
"@mozilla.org/network/protocol;1?name=file",
|
||||
"nsIFileProtocolHandler"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this,
|
||||
"fixupSchemeTypos",
|
||||
|
@ -822,7 +829,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"
|
||||
|
||||
|
@ -311,6 +312,109 @@ static __int64 MyFileSeek64(HANDLE aHandle, __int64 aDistance,
|
|||
return li.QuadPart;
|
||||
}
|
||||
|
||||
// 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
|
||||
|
@ -921,6 +1025,10 @@ nsLocalFile::InitWithPath(const nsAString& aFilePath) {
|
|||
}
|
||||
}
|
||||
|
||||
if (IsSpecialNTFSPath(aFilePath)) {
|
||||
return NS_ERROR_FILE_UNRECOGNIZED_PATH;
|
||||
}
|
||||
|
||||
mWorkingPath = aFilePath;
|
||||
// kill any trailing '\'
|
||||
if (mWorkingPath.Last() == L'\\') {
|
||||
|
@ -1236,6 +1344,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;
|
||||
}
|
||||
|
||||
|
@ -1442,10 +1556,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;
|
||||
}
|
||||
mWorkingPath.Append(aLeafName);
|
||||
if (IsSpecialNTFSPath(newDir)) {
|
||||
return NS_ERROR_FILE_UNRECOGNIZED_PATH;
|
||||
}
|
||||
|
||||
mWorkingPath.Assign(newDir);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче