Bug 1746052, don't allow Windows reserved filenames when sanitizing filenames. Move MangleTextToValidFileName to nsLocalFileWin and rename it to CheckForReservedFileName, r=Gijs

Differential Revision: https://phabricator.services.mozilla.com/D138737
This commit is contained in:
Neil Deakin 2022-05-05 19:46:48 +00:00
parent 679f61ea4c
commit c1e573cd3c
5 changed files with 35 additions and 33 deletions

View File

@ -168,6 +168,8 @@ interface nsIMIMEService : nsISupports {
* character, either ' ' or an ideographic space 0x3000 if present.
* - Unless VALIDATE_DONT_TRUNCATE is specified, the filename is truncated
* to a maximum length, preserving the extension if possible.
* - Some filenames are invalid on certain platforms. These are replaced if
* possible.
*
* If the VALIDATE_NO_DEFAULT_FILENAME flag is not specified, and after the
* rules above are applied, the resulting filename is empty, a default

View File

@ -105,6 +105,7 @@
#ifdef XP_WIN
# include "nsWindowsHelpers.h"
# include "nsLocalFile.h"
#endif
#include "mozilla/Components.h"
@ -3451,6 +3452,10 @@ nsExternalHelperAppService::ValidateFileNameForSaving(
}
}
#ifdef XP_WIN
nsLocalFile::CheckForReservedFileName(fileName);
#endif
// If no filename is present, use a default filename.
if (!(aFlags & VALIDATE_NO_DEFAULT_FILENAME) &&
(fileName.Length() == 0 || fileName.RFind(".") == 0)) {

View File

@ -44,6 +44,7 @@
#include "imgIEncoder.h"
#include "imgITools.h"
#include "WinUtils.h"
#include "nsLocalFile.h"
#include "mozilla/LazyIdleThread.h"
#include <algorithm>
@ -1087,36 +1088,6 @@ nsDataObj ::GetFileContents(FORMATETC& aFE, STGMEDIUM& aSTG) {
} // GetFileContents
//
// Given a unicode string, we ensure that it contains only characters which are
// valid within the file system. Remove all forbidden characters from the name,
// and completely disallow any title that starts with a forbidden name and
// extension (e.g. "nul" is invalid, but "nul." and "nul.txt" are also invalid
// and will cause problems).
//
// It would seem that this is more functionality suited to being in nsIFile.
//
static void MangleTextToValidFilename(nsString& aText) {
static const char* forbiddenNames[] = {
"COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8",
"COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7",
"LPT8", "LPT9", "CON", "PRN", "AUX", "NUL", "CLOCK$"};
aText.StripChars(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS);
aText.CompressWhitespace(true, true);
uint32_t nameLen;
for (size_t n = 0; n < ArrayLength(forbiddenNames); ++n) {
nameLen = (uint32_t)strlen(forbiddenNames[n]);
if (aText.EqualsIgnoreCase(forbiddenNames[n], nameLen)) {
// invalid name is either the entire string, or a prefix with a period
if (aText.Length() == nameLen || aText.CharAt(nameLen) == char16_t('.')) {
aText.Truncate();
break;
}
}
}
}
//
// Given a unicode string, convert it down to a valid local charset filename
// with the supplied extension. This ensures that we do not cut MBCS characters
@ -1129,7 +1100,7 @@ static bool CreateFilenameFromTextA(nsString& aText, const char* aExtension,
// ensure that the supplied name doesn't have invalid characters. If
// a valid mangled filename couldn't be created then it will leave the
// text empty.
MangleTextToValidFilename(aText);
nsLocalFile::CheckForReservedFileName(aText);
if (aText.IsEmpty()) return false;
// repeatably call WideCharToMultiByte as long as the title doesn't fit in the
@ -1161,7 +1132,7 @@ static bool CreateFilenameFromTextW(nsString& aText, const wchar_t* aExtension,
// ensure that the supplied name doesn't have invalid characters. If
// a valid mangled filename couldn't be created then it will leave the
// text empty.
MangleTextToValidFilename(aText);
nsLocalFile::CheckForReservedFileName(aText);
if (aText.IsEmpty()) return false;
const int extensionLen = wcslen(aExtension);
@ -2183,7 +2154,7 @@ HRESULT nsDataObj::GetDownloadDetails(nsIURI** aSourceURI,
if (srcFileName.IsEmpty()) return E_FAIL;
// make the name safe for the filesystem
MangleTextToValidFilename(srcFileName);
nsLocalFile::CheckForReservedFileName(srcFileName);
sourceURI.swap(*aSourceURI);
aFilename = srcFileName;

View File

@ -191,6 +191,26 @@ nsresult nsLocalFile::RevealFile(const nsString& aResolvedPath) {
return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE;
}
// static
void nsLocalFile::CheckForReservedFileName(nsString& aFileName) {
static const char* forbiddenNames[] = {
"COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8",
"COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7",
"LPT8", "LPT9", "CON", "PRN", "AUX", "NUL", "CLOCK$"};
uint32_t nameLen;
for (size_t n = 0; n < ArrayLength(forbiddenNames); ++n) {
nameLen = (uint32_t)strlen(forbiddenNames[n]);
if (aFileName.EqualsIgnoreCase(forbiddenNames[n], nameLen)) {
// invalid name is either the entire string, or a prefix with a period
if (aFileName.Length() == nameLen ||
aFileName.CharAt(nameLen) == char16_t('.')) {
aFileName.Truncate();
}
}
}
}
class nsDriveEnumerator : public nsSimpleEnumerator,
public nsIDirectoryEnumerator {
public:

View File

@ -49,6 +49,10 @@ class nsLocalFile final : public nsILocalFileWin {
// Called off the main thread to open the window revealing the file
static nsresult RevealFile(const nsString& aResolvedPath);
// Checks if the filename is one of the windows reserved filenames
// (com1, com2, etc...) and truncates the string if so.
static void CheckForReservedFileName(nsString& aFileName);
private:
// CopyMove and CopySingleFile constants for |options| parameter:
enum CopyFileOption {