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:
sspitzer%netscape.com 2001-05-31 05:26:08 +00:00
Родитель 8c19d4b3ed
Коммит e7f5c26fb9
4 изменённых файлов: 86 добавлений и 119 удалений

Просмотреть файл

@ -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));