mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
Bug 1536796 - P2 - Handle disable string paring in nsLocalFileWin; r=sg,dom-workers-and-storage-reviewers,froydnj,janv
In the Windows API, the maximum length for a path is MAX_PATH in general. However, the Windows API has many functions that also have Unicode versions to permit an extended-length path for a maximum total path length of 32,767 characters. To specify an extended-length path, use the "\\?\" prefix. A path component which ends with a dot is not allowed for Windows API. However, using the "\\?\" prefix can also resolved this issue. This patch aims to fix the issues which are mentioned above by prepending the prefix to the path of nsLocalFile if mDisableStringParsing is set to true. Differential Revision: https://phabricator.services.mozilla.com/D67014 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
4debe01abb
commit
4e96941288
@ -19,6 +19,8 @@ bool IsAllowedPath(const nsAString& aFilePath);
|
||||
bool IsAllowedPath(const nsACString& aFilePath);
|
||||
#endif
|
||||
|
||||
extern const char kPathSeparator;
|
||||
|
||||
namespace testing {
|
||||
|
||||
void SetBlockUNCPaths(bool aBlock);
|
||||
|
@ -59,6 +59,7 @@
|
||||
#include "mozilla/WidgetUtils.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using mozilla::FilePreferences::kPathSeparator;
|
||||
|
||||
#define CHECK_mWorkingPath() \
|
||||
do { \
|
||||
@ -78,6 +79,39 @@ using namespace mozilla;
|
||||
# define DRIVE_REMOTE 4
|
||||
#endif
|
||||
|
||||
constexpr auto kDevicePathSpecifier = NS_LITERAL_STRING("\\\\?\\");
|
||||
|
||||
namespace {
|
||||
|
||||
bool StartsWithDiskDesignatorAndBackslash(const nsAString& aAbsolutePath) {
|
||||
// aAbsolutePath can only be (in regular expression):
|
||||
// UNC path: ^\\\\.*
|
||||
// A single backslash: ^\\.*
|
||||
// A disk designator with a backslash: ^[A-Za-z]:\\.*
|
||||
return aAbsolutePath.Length() >= 3 && aAbsolutePath.CharAt(1) == L':' &&
|
||||
aAbsolutePath.CharAt(2) == kPathSeparator;
|
||||
}
|
||||
|
||||
nsresult NewLocalFile(const nsAString& aPath, bool aFollowLinks,
|
||||
bool aUseDOSDevicePathSyntax, nsIFile** aResult) {
|
||||
RefPtr<nsLocalFile> file = new nsLocalFile();
|
||||
|
||||
file->SetFollowLinks(aFollowLinks);
|
||||
file->SetUseDOSDevicePathSyntax(aUseDOSDevicePathSyntax);
|
||||
|
||||
if (!aPath.IsEmpty()) {
|
||||
nsresult rv = file->InitWithPath(aPath);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
file.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
static HWND GetMostRecentNavigatorHWND() {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIWindowMediator> winMediator(
|
||||
@ -164,7 +198,7 @@ nsresult nsLocalFile::RevealFile(const nsString& aResolvedPath) {
|
||||
class nsDriveEnumerator : public nsSimpleEnumerator,
|
||||
public nsIDirectoryEnumerator {
|
||||
public:
|
||||
nsDriveEnumerator();
|
||||
explicit nsDriveEnumerator(bool aUseDOSDevicePathSyntax);
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSISIMPLEENUMERATOR
|
||||
NS_FORWARD_NSISIMPLEENUMERATORBASE(nsSimpleEnumerator::)
|
||||
@ -200,6 +234,7 @@ class nsDriveEnumerator : public nsSimpleEnumerator,
|
||||
nsString mDrives;
|
||||
nsAString::const_iterator mStartOfCurrentDrive;
|
||||
nsAString::const_iterator mEndOfDrivesString;
|
||||
const bool mUseDOSDevicePathSyntax;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -445,12 +480,21 @@ static void FileTimeToPRTime(const FILETIME* aFiletime, PRTime* aPrtm) {
|
||||
// copied from nsprpub/pr/src/{io/prfile.c | md/windows/w95io.c} with some
|
||||
// changes : PR_GetFileInfo64, _PR_MD_GETFILEINFO64
|
||||
static nsresult GetFileInfo(const nsString& aName, PRFileInfo64* aInfo) {
|
||||
WIN32_FILE_ATTRIBUTE_DATA fileData;
|
||||
|
||||
if (aName.IsEmpty() || aName.FindCharInSet(u"?*") != kNotFound) {
|
||||
if (aName.IsEmpty()) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// Checking u"?*" for the file path excluding the kDevicePathSpecifier.
|
||||
// ToDo: Check if checking "?" for the file path is still needed.
|
||||
const int32_t offset = StringBeginsWith(aName, kDevicePathSpecifier)
|
||||
? kDevicePathSpecifier.Length()
|
||||
: 0;
|
||||
|
||||
if (aName.FindCharInSet(u"?*", offset) != kNotFound) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
WIN32_FILE_ATTRIBUTE_DATA fileData;
|
||||
if (!::GetFileAttributesExW(aName.get(), GetFileExInfoStandard, &fileData)) {
|
||||
return ConvertWinError(GetLastError());
|
||||
}
|
||||
@ -488,9 +532,6 @@ static nsresult OpenDir(const nsString& aName, nsDir** aDir) {
|
||||
}
|
||||
|
||||
*aDir = nullptr;
|
||||
if (aName.Length() + 3 >= MAX_PATH) {
|
||||
return NS_ERROR_FILE_NAME_TOO_LONG;
|
||||
}
|
||||
|
||||
nsDir* d = new nsDir();
|
||||
nsAutoString filename(aName);
|
||||
@ -704,9 +745,13 @@ NS_IMPL_ISUPPORTS_INHERITED(nsDirEnumerator, nsSimpleEnumerator,
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsLocalFile::nsLocalFile()
|
||||
: mDirty(true), mResolveDirty(true), mFollowSymlinks(false) {}
|
||||
: mDirty(true),
|
||||
mResolveDirty(true),
|
||||
mFollowSymlinks(false),
|
||||
mUseDOSDevicePathSyntax(false) {}
|
||||
|
||||
nsLocalFile::nsLocalFile(const nsAString& aFilePath) : mFollowSymlinks(false) {
|
||||
nsLocalFile::nsLocalFile(const nsAString& aFilePath)
|
||||
: mFollowSymlinks(false), mUseDOSDevicePathSyntax(false) {
|
||||
InitWithPath(aFilePath);
|
||||
}
|
||||
|
||||
@ -743,6 +788,7 @@ nsLocalFile::nsLocalFile(const nsLocalFile& aOther)
|
||||
: mDirty(true),
|
||||
mResolveDirty(true),
|
||||
mFollowSymlinks(aOther.mFollowSymlinks),
|
||||
mUseDOSDevicePathSyntax(aOther.mUseDOSDevicePathSyntax),
|
||||
mWorkingPath(aOther.mWorkingPath) {}
|
||||
|
||||
// Resolve the shortcut file from mWorkingPath and write the path
|
||||
@ -937,6 +983,15 @@ nsLocalFile::InitWithPath(const nsAString& aFilePath) {
|
||||
mWorkingPath.Truncate(mWorkingPath.Length() - 1);
|
||||
}
|
||||
|
||||
// Bug 1626514: make sure that we don't end up with multiple prefixes.
|
||||
|
||||
// Prepend the "\\?\" prefix if the useDOSDevicePathSyntax is set and the path
|
||||
// starts with a disk designator and backslash.
|
||||
if (mUseDOSDevicePathSyntax &&
|
||||
StartsWithDiskDesignatorAndBackslash(mWorkingPath)) {
|
||||
mWorkingPath = kDevicePathSpecifier + mWorkingPath;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1468,6 +1523,8 @@ nsLocalFile::SetLeafName(const nsAString& aLeafName) {
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalFile::GetPath(nsAString& aResult) {
|
||||
MOZ_ASSERT_IF(mUseDOSDevicePathSyntax,
|
||||
!StartsWithDiskDesignatorAndBackslash(mWorkingPath));
|
||||
aResult = mWorkingPath;
|
||||
return NS_OK;
|
||||
}
|
||||
@ -1618,6 +1675,24 @@ nsresult nsLocalFile::CopySingleFile(nsIFile* aSourceFile, nsIFile* aDestParent,
|
||||
return rv;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
nsCOMPtr<nsILocalFileWin> srcWinFile = do_QueryInterface(aSourceFile);
|
||||
MOZ_ASSERT(srcWinFile);
|
||||
|
||||
bool srcUseDOSDevicePathSyntax;
|
||||
srcWinFile->GetUseDOSDevicePathSyntax(&srcUseDOSDevicePathSyntax);
|
||||
|
||||
nsCOMPtr<nsILocalFileWin> destWinFile = do_QueryInterface(aDestParent);
|
||||
MOZ_ASSERT(destWinFile);
|
||||
|
||||
bool destUseDOSDevicePathSyntax;
|
||||
destWinFile->GetUseDOSDevicePathSyntax(&destUseDOSDevicePathSyntax);
|
||||
|
||||
MOZ_ASSERT(srcUseDOSDevicePathSyntax == destUseDOSDevicePathSyntax,
|
||||
"Copy or Move files with different values for "
|
||||
"useDOSDevicePathSyntax would fail");
|
||||
#endif
|
||||
|
||||
if (FilePreferences::IsBlockedUNCPath(destPath)) {
|
||||
return NS_ERROR_FILE_ACCESS_DENIED;
|
||||
}
|
||||
@ -2547,8 +2622,8 @@ nsLocalFile::GetParent(nsIFile** aParent) {
|
||||
|
||||
nsCOMPtr<nsIFile> localFile;
|
||||
nsresult rv =
|
||||
NS_NewLocalFile(parentPath, mFollowSymlinks, getter_AddRefs(localFile));
|
||||
|
||||
NewLocalFile(parentPath, mFollowSymlinks, mUseDOSDevicePathSyntax,
|
||||
getter_AddRefs(localFile));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
@ -2810,8 +2885,32 @@ nsLocalFile::Equals(nsIFile* aInFile, bool* aResult) {
|
||||
nsAutoString inFilePath;
|
||||
lf->GetCanonicalPath(inFilePath);
|
||||
|
||||
bool inUseDOSDevicePathSyntax;
|
||||
lf->GetUseDOSDevicePathSyntax(&inUseDOSDevicePathSyntax);
|
||||
|
||||
// Remove the prefix for both inFilePath and mShortWorkingPath if the
|
||||
// useDOSDevicePathSyntax from them are not the same.
|
||||
// This is added because of Omnijar. It compare files from different moduals
|
||||
// with itself
|
||||
nsAutoString shortWorkingPath;
|
||||
if (inUseDOSDevicePathSyntax == mUseDOSDevicePathSyntax) {
|
||||
shortWorkingPath = mShortWorkingPath;
|
||||
} else if (inUseDOSDevicePathSyntax &&
|
||||
StringBeginsWith(inFilePath, kDevicePathSpecifier)) {
|
||||
MOZ_ASSERT(!StringBeginsWith(mShortWorkingPath, kDevicePathSpecifier));
|
||||
|
||||
shortWorkingPath = mShortWorkingPath;
|
||||
inFilePath = Substring(inFilePath, kDevicePathSpecifier.Length());
|
||||
} else if (mUseDOSDevicePathSyntax &&
|
||||
StringBeginsWith(mShortWorkingPath, kDevicePathSpecifier)) {
|
||||
MOZ_ASSERT(!StringBeginsWith(inFilePath, kDevicePathSpecifier));
|
||||
|
||||
shortWorkingPath =
|
||||
Substring(mShortWorkingPath, kDevicePathSpecifier.Length());
|
||||
}
|
||||
|
||||
// Ok : Win9x
|
||||
*aResult = _wcsicmp(mShortWorkingPath.get(), inFilePath.get()) == 0;
|
||||
*aResult = _wcsicmp(shortWorkingPath.get(), inFilePath.get()) == 0;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -2851,6 +2950,9 @@ nsLocalFile::GetTarget(nsAString& aResult) {
|
||||
aResult.Truncate();
|
||||
Resolve();
|
||||
|
||||
MOZ_ASSERT_IF(mUseDOSDevicePathSyntax,
|
||||
!StartsWithDiskDesignatorAndBackslash(mResolvedPath));
|
||||
|
||||
aResult = mResolvedPath;
|
||||
return NS_OK;
|
||||
}
|
||||
@ -2873,7 +2975,8 @@ nsLocalFile::GetDirectoryEntriesImpl(nsIDirectoryEnumerator** aEntries) {
|
||||
|
||||
*aEntries = nullptr;
|
||||
if (mWorkingPath.EqualsLiteral("\\\\.")) {
|
||||
RefPtr<nsDriveEnumerator> drives = new nsDriveEnumerator;
|
||||
RefPtr<nsDriveEnumerator> drives =
|
||||
new nsDriveEnumerator(mUseDOSDevicePathSyntax);
|
||||
rv = drives->Init();
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
@ -2959,6 +3062,24 @@ nsLocalFile::GetUseDOSDevicePathSyntax(bool* aUseDOSDevicePathSyntax) {
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalFile::SetUseDOSDevicePathSyntax(bool aUseDOSDevicePathSyntax) {
|
||||
if (mUseDOSDevicePathSyntax == aUseDOSDevicePathSyntax) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mUseDOSDevicePathSyntax) {
|
||||
if (StringBeginsWith(mWorkingPath, kDevicePathSpecifier)) {
|
||||
MakeDirty();
|
||||
// Remove the prefix
|
||||
mWorkingPath = Substring(mWorkingPath, kDevicePathSpecifier.Length());
|
||||
}
|
||||
} else {
|
||||
if (StartsWithDiskDesignatorAndBackslash(mWorkingPath)) {
|
||||
MakeDirty();
|
||||
// Prepend the prefix
|
||||
mWorkingPath = kDevicePathSpecifier + mWorkingPath;
|
||||
}
|
||||
}
|
||||
|
||||
mUseDOSDevicePathSyntax = aUseDOSDevicePathSyntax;
|
||||
return NS_OK;
|
||||
}
|
||||
@ -3282,7 +3403,8 @@ void nsLocalFile::EnsureShortPath() {
|
||||
NS_IMPL_ISUPPORTS_INHERITED(nsDriveEnumerator, nsSimpleEnumerator,
|
||||
nsIDirectoryEnumerator)
|
||||
|
||||
nsDriveEnumerator::nsDriveEnumerator() {}
|
||||
nsDriveEnumerator::nsDriveEnumerator(bool aUseDOSDevicePathSyntax)
|
||||
: mUseDOSDevicePathSyntax(aUseDOSDevicePathSyntax) {}
|
||||
|
||||
nsDriveEnumerator::~nsDriveEnumerator() {}
|
||||
|
||||
@ -3326,7 +3448,7 @@ nsDriveEnumerator::GetNext(nsISupports** aNext) {
|
||||
mStartOfCurrentDrive = ++driveEnd;
|
||||
|
||||
nsIFile* file;
|
||||
nsresult rv = NS_NewLocalFile(drive, false, &file);
|
||||
nsresult rv = NewLocalFile(drive, false, mUseDOSDevicePathSyntax, &file);
|
||||
|
||||
*aNext = file;
|
||||
return rv;
|
||||
|
@ -65,7 +65,7 @@ class nsLocalFile final : public nsILocalFileWin {
|
||||
bool mResolveDirty;
|
||||
bool mFollowSymlinks; // should we follow symlinks when working on this file
|
||||
|
||||
bool mUseDOSDevicePathSyntax = false;
|
||||
bool mUseDOSDevicePathSyntax;
|
||||
|
||||
// this string will always be in native format!
|
||||
nsString mWorkingPath;
|
||||
|
Loading…
Reference in New Issue
Block a user