I tried the UNC path approach by prepending that to `mResolvedPath`, but that it's not enough. It seems there is an issue on `GetFileAttributesExW` and a UNC file path exceeding the MAX_PATH. I cannot find similar cases by searching "GetFileAttributesExW", and "UNC file path", though. Will keep working on it to see if I can fix the file name too long issue by adding the UNC prefix. My patch roughly likes: ``` diff --git a/xpcom/io/nsLocalFileWin.cpp b/xpcom/io/nsLocalFileWin.cpp --- a/xpcom/io/nsLocalFileWin.cpp +++ b/xpcom/io/nsLocalFileWin.cpp @@ -500,17 +514,17 @@ static void FileTimeToPRTime(const FILET #endif } // 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() /* || aName.FindCharInSet(u"?*") != kNotFound*/) { return NS_ERROR_INVALID_ARG; } if (!::GetFileAttributesExW(aName.get(), GetFileExInfoStandard, &fileData)) { return ConvertWinError(GetLastError()); } if (fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { @@ -832,21 +846,21 @@ nsresult nsLocalFile::ResolveAndStat() { AUTO_PROFILER_LABEL("nsLocalFile::ResolveAndStat", OTHER); // we can't resolve/stat anything that isn't a valid NSPR addressable path if (mWorkingPath.IsEmpty()) { return NS_ERROR_FILE_INVALID_PATH; } // this is usually correct - mResolvedPath.Assign(mWorkingPath); + AssignResolvedPath(); // Make sure root paths have a trailing slash. - nsAutoString nsprPath(mWorkingPath); - if (mWorkingPath.Length() == 2 && mWorkingPath.CharAt(1) == u':') { + nsAutoString nsprPath(mResolvedPath); + if (mResolvedPath.Length() == 2 && mResolvedPath.CharAt(1) == u':') { nsprPath.Append('\\'); } // first we will see if the working path exists. If it doesn't then // there is nothing more that can be done nsresult rv = GetFileInfo(nsprPath, &mFileInfo64); if (NS_FAILED(rv)) { return rv; @@ -862,17 +876,17 @@ nsresult nsLocalFile::ResolveAndStat() { } // we need to resolve this shortcut to what it points to, this will // set mResolvedPath. Even if it fails we need to have the resolved // path equal to working path for those functions that always use // the resolved path. rv = ResolveShortcut(); if (NS_FAILED(rv)) { - mResolvedPath.Assign(mWorkingPath); + AssignResolvedPath(); return rv; } mResolveDirty = false; // get the details of the resolved path rv = GetFileInfo(mResolvedPath, &mFileInfo64); if (NS_FAILED(rv)) { return rv; @@ -896,17 +910,17 @@ nsresult nsLocalFile::Resolve() { } // we can't resolve/stat anything that isn't a valid NSPR addressable path if (mWorkingPath.IsEmpty()) { return NS_ERROR_FILE_INVALID_PATH; } // this is usually correct - mResolvedPath.Assign(mWorkingPath); + AssignResolvedPath(); // if this isn't a shortcut file or we aren't following symlinks then // we're done. if (!mFollowSymlinks || !IsShortcutPath(mWorkingPath)) { mResolveDirty = false; return NS_OK; } @@ -3270,16 +3284,27 @@ void nsLocalFile::EnsureShortPath() { // wide characters not including null termination is returned. if (lengthNeeded != 0 && lengthNeeded < ArrayLength(shortPath)) { mShortWorkingPath.Assign(shortPath); } else { mShortWorkingPath.Assign(mWorkingPath); } } +void nsLocalFile::AssignResolvedPath() { + MOZ_ASSERT(!StringBeginsWith(mWorkingPath, NS_LITERAL_STRING("\\\\?\\"))); + if (mWorkingPath.Length() >= (MAX_PATH - 12)) { + mResolvedPath.AssignLiteral("\\\\?\\"); + mResolvedPath.Append(mWorkingPath); + return; + } + + mResolvedPath.Assign(mWorkingPath); +} + NS_IMPL_ISUPPORTS_INHERITED(nsDriveEnumerator, nsSimpleEnumerator, nsIDirectoryEnumerator) nsDriveEnumerator::nsDriveEnumerator() {} nsDriveEnumerator::~nsDriveEnumerator() {} nsresult nsDriveEnumerator::Init() { diff --git a/xpcom/io/nsLocalFileWin.h b/xpcom/io/nsLocalFileWin.h --- a/xpcom/io/nsLocalFileWin.h +++ b/xpcom/io/nsLocalFileWin.h @@ -83,16 +83,18 @@ class nsLocalFile final : public nsILoca } nsresult ResolveAndStat(); nsresult Resolve(); nsresult ResolveShortcut(); void EnsureShortPath(); + void AssignResolvedPath(); + nsresult CopyMove(nsIFile* aNewParentDir, const nsAString& aNewName, uint32_t aOptions); nsresult CopySingleFile(nsIFile* aSource, nsIFile* aDest, const nsAString& aNewName, uint32_t aOptions); nsresult SetModDate(int64_t aLastModifiedTime, const wchar_t* aFilePath); nsresult HasFileAttribute(DWORD aFileAttrib, bool* aResult); nsresult AppendInternal(const nsString& aNode, bool aMultipleComponents); ``` Testing that with a long file uri (its file path exceeds 260 characters), and the temporary directory metadata file could be created. However, it couldn't be renamed to a normal directory metadata file. I got `ERROR_PATH_NOT_FOUND` while renaming it. The error code was returned when calling `::GetFileAttributesExW` in `GetFileInfo`. To verify that this issue is not directly related to the UNC prefix, I tested that with a file uri which would have 259 characters for the temporary directory metadata file (so that the `mResolvedPath` would prepend with `\\?\` by my current patch; note: it's because I can not differentiate the file type before getting the info so I assume file type is directory, for now, to avoid the shorter restriction on directories). The origin can be initialized and the indexedDB database can be generated.
Bug 1536796 Comment 75 Edit History
Note: The actual edited comment in the bug view page will always show the original commenter’s name and original timestamp.
I tried the UNC path approach by prepending that to `mResolvedPath`, but that it's not enough. It seems there is an issue on `GetFileAttributesExW` and a UNC file path exceeding the MAX_PATH. I cannot find similar cases by searching "GetFileAttributesExW", and "UNC file path", though. Will keep working on it to see if I can fix the file name too long issue by adding the UNC prefix. My patch roughly likes: ``` diff --git a/xpcom/io/nsLocalFileWin.cpp b/xpcom/io/nsLocalFileWin.cpp --- a/xpcom/io/nsLocalFileWin.cpp +++ b/xpcom/io/nsLocalFileWin.cpp @@ -500,17 +514,17 @@ static void FileTimeToPRTime(const FILET #endif } // 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() /* || aName.FindCharInSet(u"?*") != kNotFound*/) { return NS_ERROR_INVALID_ARG; } if (!::GetFileAttributesExW(aName.get(), GetFileExInfoStandard, &fileData)) { return ConvertWinError(GetLastError()); } if (fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { @@ -832,21 +846,21 @@ nsresult nsLocalFile::ResolveAndStat() { AUTO_PROFILER_LABEL("nsLocalFile::ResolveAndStat", OTHER); // we can't resolve/stat anything that isn't a valid NSPR addressable path if (mWorkingPath.IsEmpty()) { return NS_ERROR_FILE_INVALID_PATH; } // this is usually correct - mResolvedPath.Assign(mWorkingPath); + AssignResolvedPath(); // Make sure root paths have a trailing slash. - nsAutoString nsprPath(mWorkingPath); - if (mWorkingPath.Length() == 2 && mWorkingPath.CharAt(1) == u':') { + nsAutoString nsprPath(mResolvedPath); + if (mResolvedPath.Length() == 2 && mResolvedPath.CharAt(1) == u':') { nsprPath.Append('\\'); } // first we will see if the working path exists. If it doesn't then // there is nothing more that can be done nsresult rv = GetFileInfo(nsprPath, &mFileInfo64); if (NS_FAILED(rv)) { return rv; @@ -862,17 +876,17 @@ nsresult nsLocalFile::ResolveAndStat() { } // we need to resolve this shortcut to what it points to, this will // set mResolvedPath. Even if it fails we need to have the resolved // path equal to working path for those functions that always use // the resolved path. rv = ResolveShortcut(); if (NS_FAILED(rv)) { - mResolvedPath.Assign(mWorkingPath); + AssignResolvedPath(); return rv; } mResolveDirty = false; // get the details of the resolved path rv = GetFileInfo(mResolvedPath, &mFileInfo64); if (NS_FAILED(rv)) { return rv; @@ -896,17 +910,17 @@ nsresult nsLocalFile::Resolve() { } // we can't resolve/stat anything that isn't a valid NSPR addressable path if (mWorkingPath.IsEmpty()) { return NS_ERROR_FILE_INVALID_PATH; } // this is usually correct - mResolvedPath.Assign(mWorkingPath); + AssignResolvedPath(); // if this isn't a shortcut file or we aren't following symlinks then // we're done. if (!mFollowSymlinks || !IsShortcutPath(mWorkingPath)) { mResolveDirty = false; return NS_OK; } @@ -3270,16 +3284,27 @@ void nsLocalFile::EnsureShortPath() { // wide characters not including null termination is returned. if (lengthNeeded != 0 && lengthNeeded < ArrayLength(shortPath)) { mShortWorkingPath.Assign(shortPath); } else { mShortWorkingPath.Assign(mWorkingPath); } } +void nsLocalFile::AssignResolvedPath() { + MOZ_ASSERT(!StringBeginsWith(mWorkingPath, NS_LITERAL_STRING("\\\\?\\"))); + if (mWorkingPath.Length() >= (MAX_PATH - 12)) { + mResolvedPath.AssignLiteral("\\\\?\\"); + mResolvedPath.Append(mWorkingPath); + return; + } + + mResolvedPath.Assign(mWorkingPath); +} + NS_IMPL_ISUPPORTS_INHERITED(nsDriveEnumerator, nsSimpleEnumerator, nsIDirectoryEnumerator) nsDriveEnumerator::nsDriveEnumerator() {} nsDriveEnumerator::~nsDriveEnumerator() {} nsresult nsDriveEnumerator::Init() { diff --git a/xpcom/io/nsLocalFileWin.h b/xpcom/io/nsLocalFileWin.h --- a/xpcom/io/nsLocalFileWin.h +++ b/xpcom/io/nsLocalFileWin.h @@ -83,16 +83,18 @@ class nsLocalFile final : public nsILoca } nsresult ResolveAndStat(); nsresult Resolve(); nsresult ResolveShortcut(); void EnsureShortPath(); + void AssignResolvedPath(); + nsresult CopyMove(nsIFile* aNewParentDir, const nsAString& aNewName, uint32_t aOptions); nsresult CopySingleFile(nsIFile* aSource, nsIFile* aDest, const nsAString& aNewName, uint32_t aOptions); nsresult SetModDate(int64_t aLastModifiedTime, const wchar_t* aFilePath); nsresult HasFileAttribute(DWORD aFileAttrib, bool* aResult); nsresult AppendInternal(const nsString& aNode, bool aMultipleComponents); ``` Testing that with a long file uri (its file path exceeds 260 characters), and the temporary directory metadata file could be created. However, it couldn't be renamed to a normal directory metadata file. I got `ERROR_PATH_NOT_FOUND` while renaming it. The error code was returned when calling `::GetFileAttributesExW` in `GetFileInfo`. To verify that this issue is not directly related to the way I add the UNC prefix, I tested that with a file uri which would have 259 characters for the temporary directory metadata file (so that the `mResolvedPath` would prepend with `\\?\` by my current patch; note: it's because I can not differentiate the file type before getting the info so I assume file type is directory, for now, to avoid the shorter restriction on directories). The origin can be initialized and the indexedDB database can be generated.