зеркало из https://github.com/mozilla/gecko-dev.git
fix for #82821. fix several problems (including an infinite loop problem during folder discovery)
cause by long folder names on platforms with filename limitations. r/sr=mscott,bienvneu,a=leaf/chofmann
This commit is contained in:
Родитель
8c19d4b3ed
Коммит
e7f5c26fb9
|
@ -38,15 +38,7 @@
|
|||
#include "nsITransport.h"
|
||||
#include "nsIFileTransportService.h"
|
||||
#include "nsIMsgFolderCompactor.h"
|
||||
#if defined(XP_OS2)
|
||||
#define MAX_FILE_LENGTH_WITHOUT_EXTENSION 8
|
||||
#elif defined(XP_MAC)
|
||||
#define MAX_FILE_LENGTH_WITHOUT_EXTENSION 26
|
||||
#elif defined(XP_WIN32)
|
||||
#define MAX_FILE_LENGTH_WITHOUT_EXTENSION 256
|
||||
#else
|
||||
#define MAX_FILE_LENGTH_WITHOUT_EXTENSION 32000
|
||||
#endif
|
||||
#include "nsMsgUtils.h"
|
||||
|
||||
|
||||
static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID);
|
||||
|
@ -580,69 +572,44 @@ nsresult nsMsgDBFolder::GetOfflineStoreOutputStream(nsIOutputStream **outputStre
|
|||
return rv;
|
||||
}
|
||||
|
||||
// XXX todo
|
||||
// move these to a common location and remove all the hard coded ".msf"
|
||||
#define SUMMARY_SUFFIX ".msf"
|
||||
#define SUMMARY_SUFFIX_LEN 4
|
||||
|
||||
// path coming in is the root path without the leaf name,
|
||||
// on the way out, it's the whole path.
|
||||
nsresult nsMsgDBFolder::CreatePlatformLeafNameForDisk(const char *userLeafName, nsFileSpec &path, char **resultName)
|
||||
nsresult nsMsgDBFolder::CreateFileSpecForDB(const char *userLeafName, nsFileSpec &path, nsIFileSpec **dbFileSpec)
|
||||
{
|
||||
#if 0
|
||||
const int charLimit = MAX_FILE_LENGTH_WITHOUT_EXTENSION; // set on platform specific basis
|
||||
#endif
|
||||
#if defined(XP_MAC)
|
||||
nsCAutoString illegalChars(":");
|
||||
#elif defined(XP_OS2)
|
||||
nsCAutoString illegalChars("\"/\\[]:;=,|?<>*$. ");
|
||||
#elif defined(XP_WIN32)
|
||||
nsCAutoString illegalChars("\"/\\[]:;=,|?<>*$");
|
||||
#else // UNIX (what about beos?)
|
||||
nsCAutoString illegalChars;
|
||||
#endif
|
||||
NS_ENSURE_ARG_POINTER(dbFileSpec);
|
||||
NS_ENSURE_ARG_POINTER(userLeafName);
|
||||
|
||||
if (!resultName || !userLeafName)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
*resultName = nsnull;
|
||||
nsCAutoString proposedDBName(userLeafName);
|
||||
NS_MsgHashIfNecessary(proposedDBName);
|
||||
|
||||
// mangledLeaf is the new leaf name.
|
||||
// If userLeafName (a) contains all legal characters
|
||||
// (b) is within the valid length for the given platform
|
||||
// (c) does not already exist on the disk
|
||||
// then we simply return nsCRT::strdup(userLeafName)
|
||||
// Otherwise we mangle it
|
||||
// mangledPath is the entire path to the newly mangled leaf name
|
||||
nsCAutoString mangledLeaf(userLeafName);
|
||||
// (note, the caller of this will be using the dbFileSpec to call db->Open()
|
||||
// will turn the path into summary spec, and append the ".msf" extension)
|
||||
//
|
||||
// we want db->Open() to create a new summary file
|
||||
// so we have to jump through some hoops to make sure the .msf it will
|
||||
// create is unique. now that we've got the "safe" proposedDBName,
|
||||
// we append ".msf" to see if the file exists. if so, we make the name
|
||||
// unique and then string off the ".msf" so that we pass the right thing
|
||||
// into Open(). this isn't ideal, since this is not atomic
|
||||
// but it will make do.
|
||||
proposedDBName+= SUMMARY_SUFFIX;
|
||||
path += proposedDBName.get();
|
||||
if (path.Exists())
|
||||
{
|
||||
path.MakeUnique();
|
||||
proposedDBName = path.GetLeafName();
|
||||
}
|
||||
// now, take the ".msf" off
|
||||
proposedDBName.Truncate(proposedDBName.Length() - SUMMARY_SUFFIX_LEN);
|
||||
path.SetLeafName(proposedDBName);
|
||||
|
||||
PRInt32 illegalCharacterIndex = mangledLeaf.FindCharInSet(illegalChars);
|
||||
|
||||
if (illegalCharacterIndex == kNotFound)
|
||||
{
|
||||
path += (const char *) mangledLeaf;
|
||||
if (!path.Exists())
|
||||
{
|
||||
// if there are no illegal characters
|
||||
// and the file doesn't already exist, then don't do anything to the string
|
||||
// Note that this might be truncated to charLength, but if so, the file still
|
||||
// does not exist, so we are OK.
|
||||
*resultName = mangledLeaf.ToNewCString();
|
||||
return (*resultName) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// First, replace all illegal characters with '_'
|
||||
mangledLeaf.ReplaceChar(illegalChars, '_');
|
||||
|
||||
path += (const char *) mangledLeaf;
|
||||
}
|
||||
// if we are here, then any of the following may apply:
|
||||
// (a) there were illegal characters
|
||||
// (b) the file already existed
|
||||
|
||||
// Now, we have to loop until we find a filename that doesn't already
|
||||
// exist on the disk
|
||||
path.SetLeafName(mangledLeaf.get());
|
||||
path.MakeUnique();
|
||||
*resultName = path.GetLeafName();
|
||||
return NS_OK;
|
||||
NS_NewFileSpecWithSpec(path, dbFileSpec);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -103,7 +103,7 @@ protected:
|
|||
nsresult CheckWithNewMessagesStatus(PRBool messageAdded);
|
||||
nsresult OnKeyAddedOrDeleted(nsMsgKey aKeyChanged, nsMsgKey aParentKey , PRInt32 aFlags,
|
||||
nsIDBChangeListener * aInstigator, PRBool added, PRBool doFlat, PRBool doThread);
|
||||
nsresult CreatePlatformLeafNameForDisk(const char *userLeafName, nsFileSpec &baseDir, char **resultName);
|
||||
nsresult CreateFileSpecForDB(const char *userLeafName, nsFileSpec &baseDir, nsIFileSpec **dbFileSpec);
|
||||
|
||||
nsresult GetFolderCacheKey(nsIFileSpec **aFileSpec);
|
||||
nsresult GetFolderCacheElemFromFileSpec(nsIFileSpec *fileSpec, nsIMsgFolderCacheElement **cacheElement);
|
||||
|
|
|
@ -41,10 +41,6 @@ static NS_DEFINE_CID(kImapUrlCID, NS_IMAPURL_CID);
|
|||
static NS_DEFINE_CID(kCMailboxUrl, NS_MAILBOXURL_CID);
|
||||
static NS_DEFINE_CID(kCNntpUrlCID, NS_NNTPURL_CID);
|
||||
|
||||
#if defined(DEBUG_sspitzer_) || defined(DEBUG_seth_)
|
||||
#define DEBUG_NS_MsgHashIfNecessary 1
|
||||
#endif
|
||||
|
||||
nsresult GetMessageServiceContractIDForURI(const char *uri, nsString &contractID)
|
||||
{
|
||||
|
||||
|
@ -236,38 +232,51 @@ static PRUint32 StringHash(const char *ubuf)
|
|||
nsresult NS_MsgHashIfNecessary(nsCAutoString &name)
|
||||
{
|
||||
#if defined(XP_MAC)
|
||||
nsCAutoString illegalChars(":");
|
||||
const PRUint32 MAX_LEN = 25;
|
||||
#elif defined(XP_UNIX) || defined(XP_PC) || defined(XP_BEOS)
|
||||
#elif defined(XP_UNIX) || defined(XP_BEOS)
|
||||
nsCAutoString illegalChars; // is this correct for BEOS?
|
||||
const PRUint32 MAX_LEN = 55;
|
||||
#elif defined(XP_WIN32)
|
||||
nsCAutoString illegalChars("\"/\\[]:;=,|?<>*$");
|
||||
const PRUint32 MAX_LEN = 55;
|
||||
#elif defined(XP_OS2)
|
||||
nsCAutoString illegalChars("\"/\\[]:;=,|?<>*$. ");
|
||||
const PRUint32 MAX_LEN = 8;
|
||||
#else
|
||||
#error need_to_define_your_max_filename_length
|
||||
#endif
|
||||
nsCAutoString str(name);
|
||||
|
||||
#ifdef DEBUG_NS_MsgHashIfNecessary
|
||||
printf("in: %s\n",str.get());
|
||||
#endif
|
||||
|
||||
// Given a name, use either that name, if it fits on our
|
||||
// filesystem, or a hashified version of it, if the name is too
|
||||
// long to fit.
|
||||
// Given a filename, make it safe for filesystem
|
||||
// certain filenames require hashing because they
|
||||
// are too long or contain illegal characters
|
||||
PRInt32 illegalCharacterIndex = str.FindCharInSet(illegalChars);
|
||||
char hashedname[MAX_LEN + 1];
|
||||
PRBool needshash = PL_strlen(str.get()) > MAX_LEN;
|
||||
#if defined(XP_WIN16) || defined(XP_OS2)
|
||||
if (!needshash) {
|
||||
needshash = PL_strchr(str.get(), '.') != nsnull ||
|
||||
PL_strchr(str.get(), ':') != nsnull;
|
||||
}
|
||||
#endif
|
||||
PL_strncpy(hashedname, str.get(), MAX_LEN + 1);
|
||||
if (needshash) {
|
||||
PR_snprintf(hashedname + MAX_LEN - 8, 9, "%08lx",
|
||||
if (illegalCharacterIndex == kNotFound)
|
||||
{
|
||||
// no illegal chars, it's just too long
|
||||
// keep the initial part of the string, but hash to make it fit
|
||||
if (str.Length() > MAX_LEN)
|
||||
{
|
||||
PL_strncpy(hashedname, str.get(), MAX_LEN + 1);
|
||||
PR_snprintf(hashedname + MAX_LEN - 8, 9, "%08lx",
|
||||
(unsigned long) StringHash(str.get()));
|
||||
name = hashedname;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// found illegal chars, hash the whole thing
|
||||
// if we do substitution, then hash, two strings
|
||||
// could hash to the same value.
|
||||
// for example, on mac: "foo__bar", "foo:_bar", "foo::bar"
|
||||
// would map to "foo_bar". this way, all three will map to
|
||||
// different values
|
||||
PR_snprintf(hashedname, 9, "%08lx",
|
||||
(unsigned long) StringHash(str.get()));
|
||||
name = hashedname;
|
||||
}
|
||||
name = hashedname;
|
||||
#ifdef DEBUG_NS_MsgHashIfNecessary
|
||||
printf("out: %s\n",hashedname);
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -721,7 +721,14 @@ NS_IMETHODIMP nsImapMailFolder::CreateClientSubfolderInfo(const char *folderName
|
|||
nsCAutoString uri (mURI);
|
||||
parentName.Right(leafName, leafName.Length() - folderStart - 1);
|
||||
parentName.Truncate(folderStart);
|
||||
path += parentName;
|
||||
|
||||
// the parentName might be too long or have some illegal chars
|
||||
// so we make it safe
|
||||
nsCAutoString safeParentName;
|
||||
safeParentName.AssignWithConversion(parentName);
|
||||
NS_MsgHashIfNecessary(safeParentName);
|
||||
path += safeParentName;
|
||||
|
||||
rv = CreateDirectoryForFolder(path);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
uri.Append('/');
|
||||
|
@ -748,22 +755,13 @@ NS_IMETHODIMP nsImapMailFolder::CreateClientSubfolderInfo(const char *folderName
|
|||
rv = nsComponentManager::CreateInstance(kCMailDB, nsnull, NS_GET_IID(nsIMsgDatabase), (void **) getter_AddRefs(mailDBFactory));
|
||||
if (NS_SUCCEEDED(rv) && mailDBFactory)
|
||||
{
|
||||
nsCOMPtr<nsIMsgDatabase> unusedDB;
|
||||
nsCOMPtr<nsIMsgDatabase> unusedDB;
|
||||
nsCOMPtr <nsIFileSpec> dbFileSpec;
|
||||
|
||||
nsXPIDLCString uniqueLeafName;
|
||||
nsCAutoString proposedDBName(folderName);
|
||||
proposedDBName += ".msf";
|
||||
// warning, path will be changed
|
||||
rv = CreateFileSpecForDB(folderName, path, getter_AddRefs(dbFileSpec));
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
rv = CreatePlatformLeafNameForDisk(proposedDBName, path, getter_Copies(uniqueLeafName));
|
||||
|
||||
// take off the ".msf" on the end.
|
||||
proposedDBName = uniqueLeafName;
|
||||
proposedDBName.Truncate(proposedDBName.Length() - 4);
|
||||
|
||||
path.SetLeafName(proposedDBName);
|
||||
|
||||
NS_NewFileSpecWithSpec(path, getter_AddRefs(dbFileSpec));
|
||||
rv = mailDBFactory->Open(dbFileSpec, PR_TRUE, PR_TRUE, (nsIMsgDatabase **) getter_AddRefs(unusedDB));
|
||||
|
||||
if (NS_SUCCEEDED(rv) && unusedDB)
|
||||
|
@ -5490,20 +5488,13 @@ NS_IMETHODIMP nsImapMailFolder::RenameClient( nsIMsgFolder *msgFolder, const cha
|
|||
nsCOMPtr<nsIMsgDatabase> unusedDB;
|
||||
nsCOMPtr <nsIFileSpec> dbFileSpec;
|
||||
|
||||
nsXPIDLCString uniqueLeafName;
|
||||
nsCAutoString proposedDBName(newLeafName.ToNewCString());
|
||||
//nsCAutoString proposedDBName(folderName);
|
||||
proposedDBName += ".msf";
|
||||
nsCAutoString proposedDBName;
|
||||
proposedDBName.AssignWithConversion(newLeafName);
|
||||
|
||||
rv = CreatePlatformLeafNameForDisk(proposedDBName, path, getter_Copies(uniqueLeafName));
|
||||
// warning, path will be changed
|
||||
rv = CreateFileSpecForDB(proposedDBName.get(), path, getter_AddRefs(dbFileSpec));
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
// take off the ".msf" on the end.
|
||||
proposedDBName = uniqueLeafName;
|
||||
proposedDBName.Truncate(proposedDBName.Length() - 4);
|
||||
|
||||
path.SetLeafName(proposedDBName);
|
||||
|
||||
NS_NewFileSpecWithSpec(path, getter_AddRefs(dbFileSpec));
|
||||
// it's OK to use Open and not OpenFolderDB here, since we don't use the DB.
|
||||
rv = mailDBFactory->Open(dbFileSpec, PR_TRUE, PR_TRUE, (nsIMsgDatabase **) getter_AddRefs(unusedDB));
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче