fix for #137886. Detect defunct previously migrated profiles and offer to re-migrate.

this is pref controlled, "profile.seconds_until_defunct.  by default,
we'll never offer to remigrate.  initial patch by ccarlen.
r=ccarlen,racham,sr=bienvenu
This commit is contained in:
sspitzer%netscape.com 2002-04-26 01:37:04 +00:00
Родитель 3faab993b1
Коммит a376f9f56c
13 изменённых файлов: 575 добавлений и 195 удалений

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

@ -623,6 +623,15 @@ pref("mousewheel.withaltkey.sysnumlines",false);
pref("profile.confirm_automigration",true);
// the amount of time (in seconds) that must elapse
// before we think your mozilla profile is defunct
// and you'd benefit from re-migrating from 4.x
// see bug #137886 for more details
//
// if -1, we never think your profile is defunct
// and users will never see the remigrate UI.
pref("profile.seconds_until_defunct", -1);
// Customizable toolbar stuff
pref("custtoolbar.personal_toolbar_folder", "");

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

@ -87,7 +87,8 @@ interface nsIProfileInternal : nsIProfile {
void migrateProfileInfo();
void migrateAllProfiles();
void migrateProfile(in wstring profileName, in boolean showProgressAsModalWindow);
void migrateProfile(in wstring profileName);
void remigrateProfile(in wstring profileName);
void forgetCurrentProfile();
/**
@ -108,6 +109,12 @@ interface nsIProfileInternal : nsIProfile {
*/
nsILocalFile getOriginalProfileDir(in wstring profileName);
/**
* Returns the date on which a profile was last used.
* value is in milliseconds since midnight Jan 1, 1970 GMT (same as nsIFile)
*/
PRInt64 getProfileLastModTime(in wstring profileName);
attribute boolean automigrate;
readonly attribute nsIFile defaultProfileParentDir;
readonly attribute wstring firstProfile;

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

@ -76,7 +76,7 @@ function RenameProfile()
}
}
}
profile.migrateProfile( profilename, true );
profile.migrateProfile( profilename );
}
else
return false;

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

@ -183,7 +183,7 @@ function onStart()
}
}
}
profile.migrateProfile( profilename, true );
profile.migrateProfile( profilename );
}
else
return false;

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

@ -9,3 +9,7 @@ mailDirName=Mail
# newsDirName needs to be set to the same value as in 4.x
# see bug #55449
newsDirName=News
# see nsAppShellService::CheckAndRemigrateDefunctProfile()
# for where the confirmRemigration entries are used
# LOCALIZATION NOTE: Do not translate Unicode (\uXXXX) characters.
confirmRemigration=A more recent Netscape 4.5+ version of this profile (which contains your bookmarks, email settings, address books and preferences) was found.\u000aWould you like to use the more recent profile?

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

@ -328,7 +328,6 @@ nsProfile::~nsProfile()
if (--gInstanceCount == 0) {
delete gProfileDataAccess;
delete gLocaleProfiles;
NS_IF_RELEASE(sApp_PrefsDirectory50);
@ -1058,9 +1057,43 @@ NS_IMETHODIMP nsProfile::GetOriginalProfileDir(const PRUnichar *profileName, nsI
NS_ENSURE_ARG_POINTER(originalDir);
*originalDir = nsnull;
Update4xProfileInfo();
return gProfileDataAccess->GetOriginalProfileDir(profileName, originalDir);
}
NS_IMETHODIMP nsProfile::GetProfileLastModTime(const PRUnichar *profileName, PRInt64 *_retval)
{
NS_ENSURE_ARG(profileName);
NS_ENSURE_ARG_POINTER(_retval);
nsresult rv;
// First, see if we can get the lastModTime from the registry.
// We only started putting it there from mozilla1.0.1
// The mod time will be zero if it has not been set.
ProfileStruct *profileInfo = nsnull;
rv = gProfileDataAccess->GetValue(profileName, &profileInfo);
if (NS_SUCCEEDED(rv)) {
PRInt64 lastModTime = profileInfo->lastModTime;
delete profileInfo;
if (!LL_IS_ZERO(lastModTime)) {
*_retval = lastModTime;
return NS_OK;
}
}
// Since we couldn't get a valid mod time from the registry,
// check the date of prefs.js. Since August, 2000 it is always
// written out on quitting the application.
nsCOMPtr<nsIFile> profileDir;
rv = GetProfileDir(profileName, getter_AddRefs(profileDir));
if (NS_FAILED(rv))
return rv;
rv = profileDir->Append("prefs.js");
if (NS_FAILED(rv))
return rv;
return profileDir->GetLastModifiedTime(_retval);
}
NS_IMETHODIMP nsProfile::GetDefaultProfileParentDir(nsIFile **aDefaultProfileParentDir)
{
NS_ENSURE_ARG_POINTER(aDefaultProfileParentDir);
@ -1172,9 +1205,12 @@ nsProfile::SetCurrentProfile(const PRUnichar * aCurrentProfile)
// Phase 3: Notify observers of a profile change
observerService->NotifyObservers(subject, "profile-before-change", context.get());
UpdateCurrentProfileModTime(PR_FALSE);
}
// Do the profile switch
mCurrentProfileName.Assign(aCurrentProfile);
gProfileDataAccess->SetCurrentProfile(aCurrentProfile);
gProfileDataAccess->mProfileDataChanged = PR_TRUE;
gProfileDataAccess->UpdateRegistry(nsnull);
@ -1233,31 +1269,37 @@ NS_IMETHODIMP nsProfile::ShutDownCurrentProfile(PRUint32 shutDownType)
{
nsresult rv;
nsCOMPtr<nsIObserverService> observerService =
do_GetService("@mozilla.org/observer-service;1", &rv);
NS_ENSURE_TRUE(observerService, NS_ERROR_FAILURE);
nsISupports *subject = (nsISupports *)((nsIProfile *)this);
NS_NAMED_LITERAL_STRING(cleanseString, "shutdown-cleanse");
NS_NAMED_LITERAL_STRING(persistString, "shutdown-persist");
const nsAFlatString& context = (shutDownType == SHUTDOWN_CLEANSE) ? cleanseString : persistString;
// Phase 1: See if anybody objects to the profile being changed.
mProfileChangeVetoed = PR_FALSE;
observerService->NotifyObservers(subject, "profile-approve-change", context.get());
if (mProfileChangeVetoed)
// if shutDownType is not a well know value, skip the notifications
// see DoOnShutdown() in nsAppRunner.cpp for where we use this behaviour to our benefit
if (shutDownType == SHUTDOWN_PERSIST || shutDownType == SHUTDOWN_CLEANSE) {
nsCOMPtr<nsIObserverService> observerService =
do_GetService("@mozilla.org/observer-service;1", &rv);
NS_ENSURE_TRUE(observerService, NS_ERROR_FAILURE);
nsISupports *subject = (nsISupports *)((nsIProfile *)this);
NS_NAMED_LITERAL_STRING(cleanseString, "shutdown-cleanse");
NS_NAMED_LITERAL_STRING(persistString, "shutdown-persist");
const nsAFlatString& context = (shutDownType == SHUTDOWN_CLEANSE) ? cleanseString : persistString;
// Phase 1: See if anybody objects to the profile being changed.
mProfileChangeVetoed = PR_FALSE;
observerService->NotifyObservers(subject, "profile-approve-change", context.get());
if (mProfileChangeVetoed)
return NS_OK;
// Phase 2: Send the "teardown" notification
observerService->NotifyObservers(subject, "profile-change-teardown", context.get());
// Phase 3: Notify observers of a profile change
observerService->NotifyObservers(subject, "profile-before-change", context.get());
// Phase 2: Send the "teardown" notification
observerService->NotifyObservers(subject, "profile-change-teardown", context.get());
// Phase 3: Notify observers of a profile change
observerService->NotifyObservers(subject, "profile-before-change", context.get());
}
rv = UndefineFileLocations();
NS_ASSERTION(NS_SUCCEEDED(rv), "Could not undefine file locations");
UpdateCurrentProfileModTime(PR_TRUE);
mCurrentProfileAvailable = PR_FALSE;
mCurrentProfileName.Truncate(0);
return NS_OK;
}
@ -1440,7 +1482,8 @@ nsresult nsProfile::SetProfileDir(const PRUnichar *profileName, nsIFile *profile
rv = profileDir->Exists(&exists);
if (NS_SUCCEEDED(rv) && !exists)
rv = profileDir->Create(nsIFile::DIRECTORY_TYPE, 0775);
if (NS_FAILED(rv)) return rv;
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsILocalFile> localFile(do_QueryInterface(profileDir));
NS_ENSURE_TRUE(localFile, NS_ERROR_FAILURE);
@ -1448,12 +1491,16 @@ nsresult nsProfile::SetProfileDir(const PRUnichar *profileName, nsIFile *profile
ProfileStruct* aProfile = new ProfileStruct();
NS_ENSURE_TRUE(aProfile, NS_ERROR_OUT_OF_MEMORY);
aProfile->profileName = profileName;
aProfile->profileName = profileName;
aProfile->SetResolvedProfileDir(localFile);
aProfile->isMigrated = PR_TRUE;
aProfile->isImportType = PR_FALSE;
// convert "now" from microsecs to millisecs
PRInt64 oneThousand = LL_INIT(0, 1000);
PRInt64 nowInMilliSecs = PR_Now();
LL_DIV(aProfile->creationTime, nowInMilliSecs, oneThousand);
gProfileDataAccess->SetValue(aProfile);
delete aProfile;
@ -1771,6 +1818,7 @@ NS_IMETHODIMP nsProfile::ForgetCurrentProfile()
gProfileDataAccess->mForgetProfileCalled = PR_TRUE;
mCurrentProfileAvailable = PR_FALSE;
mCurrentProfileName.Truncate(0);
return rv;
}
@ -1943,6 +1991,22 @@ char * nsProfile::GetOldRegLocation()
return nsnull;
}
nsresult nsProfile::UpdateCurrentProfileModTime(PRBool updateRegistry)
{
nsresult rv;
// convert "now" from microsecs to millisecs
PRInt64 oneThousand = LL_INIT(0, 1000);
PRInt64 nowInMilliSecs = PR_Now();
LL_DIV(nowInMilliSecs, nowInMilliSecs, oneThousand);
rv = gProfileDataAccess->SetProfileLastModTime(mCurrentProfileName.get(), nowInMilliSecs);
if (NS_SUCCEEDED(rv) && updateRegistry) {
gProfileDataAccess->mProfileDataChanged = PR_TRUE;
gProfileDataAccess->UpdateRegistry(nsnull);
}
return rv;
}
// Migrate profile information from the 4x registry to 5x registry.
NS_IMETHODIMP nsProfile::MigrateProfileInfo()
@ -2080,41 +2144,22 @@ nsresult nsProfile::UndefineFileLocations()
// Set the profile to the current profile....debatable.
// Calls PrefMigration service to do the Copy and Diverge
// of 4x Profile information
NS_IMETHODIMP
nsProfile::MigrateProfile(const PRUnichar* profileName, PRBool showProgressAsModalWindow)
nsresult
nsProfile::MigrateProfileInternal(const PRUnichar* profileName,
nsIFile* oldProfDir,
nsIFile* newProfDir)
{
NS_ENSURE_ARG_POINTER(profileName);
nsresult rv = NS_OK;
#if defined(DEBUG_profile)
printf("Inside Migrate Profile routine.\n" );
#endif
nsCOMPtr<nsIFile> oldProfDir;
nsCOMPtr<nsIFile> newProfDir;
rv = GetProfileDir(profileName, getter_AddRefs(oldProfDir));
if (NS_FAILED(rv)) return rv;
rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILES_ROOT_DIR, getter_AddRefs(newProfDir));
if (NS_FAILED(rv)) return rv;
rv = newProfDir->AppendUnicode(profileName);
if (NS_FAILED(rv)) return rv;
// This is unfortunate: There is no CreateUniqueUnicode
rv = newProfDir->CreateUnique(nsIFile::DIRECTORY_TYPE, 0775);
if (NS_FAILED(rv)) return rv;
// always create level indirection when migrating
rv = AddLevelOfIndirection(newProfDir);
if (NS_FAILED(rv)) return rv;
// Call migration service to do the work.
nsCOMPtr <nsIPrefMigration> pPrefMigrator;
rv = nsComponentManager::CreateInstance(kPrefMigrationCID,
nsresult rv = nsComponentManager::CreateInstance(kPrefMigrationCID,
nsnull,
NS_GET_IID(nsIPrefMigration),
getter_AddRefs(pPrefMigrator));
@ -2137,7 +2182,7 @@ nsProfile::MigrateProfile(const PRUnichar* profileName, PRBool showProgressAsMod
// you can do this a bunch of times.
rv = pPrefMigrator->AddProfilePaths(oldProfDirStr, newProfDirStr);
rv = pPrefMigrator->ProcessPrefs(showProgressAsModalWindow);
rv = pPrefMigrator->ProcessPrefs(PR_TRUE); // param is ignored
if (NS_FAILED(rv)) return rv;
// check for diskspace errors
@ -2198,12 +2243,90 @@ nsProfile::MigrateProfile(const PRUnichar* profileName, PRBool showProgressAsMod
rv = SetProfileDir(profileName, newProfDir);
if (NS_FAILED(rv)) return rv;
gProfileDataAccess->SetMigratedFromDir(profileName, oldProfDirLocal);
gProfileDataAccess->mProfileDataChanged = PR_TRUE;
gProfileDataAccess->UpdateRegistry(nsnull);
return rv;
}
NS_IMETHODIMP
nsProfile::MigrateProfile(const PRUnichar* profileName)
{
NS_ENSURE_ARG(profileName);
nsresult rv = NS_OK;
nsCOMPtr<nsIFile> oldProfDir;
nsCOMPtr<nsIFile> newProfDir;
rv = GetProfileDir(profileName, getter_AddRefs(oldProfDir));
if (NS_FAILED(rv))
return rv;
rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILES_ROOT_DIR, getter_AddRefs(newProfDir));
if (NS_FAILED(rv))
return rv;
rv = newProfDir->AppendUnicode(profileName);
if (NS_FAILED(rv))
return rv;
rv = newProfDir->CreateUnique(nsIFile::DIRECTORY_TYPE, 0775);
if (NS_FAILED(rv))
return rv;
// always create level indirection when migrating
rv = AddLevelOfIndirection(newProfDir);
if (NS_FAILED(rv))
return rv;
return MigrateProfileInternal(profileName, oldProfDir, newProfDir);
}
NS_IMETHODIMP
nsProfile::RemigrateProfile(const PRUnichar* profileName)
{
NS_ENSURE_ARG_POINTER(profileName);
nsCOMPtr<nsIFile> profileDir;
nsresult rv = GetProfileDir(profileName, getter_AddRefs(profileDir));
NS_ENSURE_SUCCESS(rv,rv);
nsCOMPtr<nsIFile> newProfileDir;
rv = profileDir->Clone(getter_AddRefs(newProfileDir));
NS_ENSURE_SUCCESS(rv,rv);
// The profile list used by GetOriginalProfileDir is the one with ALL 4.x
// profiles - even ones for which there's a moz profile of the same name.
nsCOMPtr<nsILocalFile> oldProfileDir;
rv = GetOriginalProfileDir(profileName, getter_AddRefs(oldProfileDir));
NS_ENSURE_SUCCESS(rv,rv);
// In case of error, we'll restore what we've renamed.
nsXPIDLCString origDirLeafName;
rv = profileDir->GetLeafName(getter_Copies(origDirLeafName));
NS_ENSURE_SUCCESS(rv,rv);
// Backup what we're remigrating by renaming it and leaving in place
// XXX todo: what if <xxxxxxxx>.slt-old already exists?
nsCAutoString newDirLeafName(origDirLeafName + NS_LITERAL_CSTRING("-old"));
rv = profileDir->MoveTo(nsnull, newDirLeafName.get());
NS_ENSURE_SUCCESS(rv,rv);
// Create a new directory for the remigrated profile
rv = newProfileDir->Create(nsIFile::DIRECTORY_TYPE, 0775);
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to create new directory for the remigrated profile");
if (NS_SUCCEEDED(rv))
rv = MigrateProfileInternal(profileName, oldProfileDir, newProfileDir);
if (NS_FAILED(rv)) {
newProfileDir->Remove(PR_TRUE);
profileDir->MoveTo(nsnull, origDirLeafName);
}
return rv;
}
nsresult
nsProfile::ShowProfileWizard(void)
{
@ -2266,7 +2389,7 @@ NS_IMETHODIMP nsProfile::MigrateAllProfiles()
if (NS_FAILED(rv)) return rv;
for (PRUint32 i = 0; i < numOldProfiles; i++)
{
rv = MigrateProfile(nameArray[i], PR_FALSE /* don't show progress as modal window */);
rv = MigrateProfile(nameArray[i]);
if (NS_FAILED(rv)) break;
}
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(numOldProfiles, nameArray);

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

@ -87,6 +87,9 @@ private:
nsresult UndefineFileLocations();
nsresult Update4xProfileInfo();
char * GetOldRegLocation();
nsresult UpdateCurrentProfileModTime(PRBool updateRegistry);
nsresult MigrateProfileInternal(const PRUnichar *profileName,
nsIFile *oldProfDir, nsIFile *newProfDir);
PRBool mStartingUp;
PRBool mAutomigrate;
@ -94,13 +97,14 @@ private:
PRBool mDiskSpaceErrorQuitCalled;
PRBool mProfileChangeVetoed;
nsString mCurrentProfileName;
PRBool mCurrentProfileAvailable;
PRBool mIsUILocaleSpecified;
nsAutoString mUILocaleName;
nsString mUILocaleName;
PRBool mIsContentLocaleSpecified;
nsAutoString mContentLocaleName;
nsString mContentLocaleName;
public:
nsProfile();

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

@ -42,9 +42,6 @@
#include "nsICharsetConverterManager.h"
#include "nsIPlatformCharset.h"
#define MAX_PERSISTENT_DATA_SIZE 1000
#define NUM_HEX_BYTES 8
#define ISHEX(c) ( ((c) >= '0' && (c) <= '9') || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F') )
#if defined (XP_UNIX)
#define USER_ENVIRONMENT_VARIABLE "USER"
@ -76,7 +73,9 @@ static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CI
#define kRegistryDirectoryString (NS_LITERAL_STRING("directory"))
#define kRegistryNeedMigrationString (NS_LITERAL_STRING("NeedMigration"))
#define kRegistryMozRegDataMovedString (NS_LITERAL_STRING("OldRegDataMoved"))
#define kRegistryCreationTimeString (NS_LITERAL_CSTRING("CreationTime"))
#define kRegistryLastModTimeString (NS_LITERAL_CSTRING("LastModTime"))
#define kRegistryMigratedFromString (NS_LITERAL_CSTRING("MigFromDir"))
#define kRegistryVersionString (NS_LITERAL_STRING("Version"))
#define kRegistryVersion_1_0 (NS_LITERAL_STRING("1.0"))
#define kRegistryCurrentVersion (NS_LITERAL_STRING("1.0"))
@ -223,10 +222,9 @@ nsProfileAccess::GetValue(const PRUnichar* profileName, ProfileStruct** aProfile
nsresult
nsProfileAccess::SetValue(ProfileStruct* aProfile)
{
NS_ASSERTION(aProfile, "Invalid profile");
NS_ENSURE_ARG(aProfile);
PRInt32 index = 0;
PRBool isNewProfile = PR_FALSE;
ProfileStruct* profileItem;
index = FindProfileIndex(aProfile->profileName.get(), aProfile->isImportType);
@ -234,43 +232,21 @@ nsProfileAccess::SetValue(ProfileStruct* aProfile)
if (index >= 0)
{
profileItem = (ProfileStruct *) (mProfiles->ElementAt(index));
*profileItem = *aProfile;
profileItem->updateProfileEntry = PR_TRUE;
}
else
{
isNewProfile = PR_TRUE;
profileItem = new ProfileStruct();
profileItem = new ProfileStruct(*aProfile);
if (!profileItem)
return NS_ERROR_OUT_OF_MEMORY;
profileItem->profileName = aProfile->profileName;
}
aProfile->CopyProfileLocation(profileItem);
profileItem->isMigrated = aProfile->isMigrated;
profileItem->isImportType = aProfile->isImportType;
profileItem->updateProfileEntry = PR_TRUE;
if (!aProfile->NCProfileName.IsEmpty())
profileItem->NCProfileName = aProfile->NCProfileName;
if (!aProfile->NCDeniedService.IsEmpty())
profileItem->NCDeniedService = aProfile->NCDeniedService;
if (!aProfile->NCEmailAddress.IsEmpty())
profileItem->NCEmailAddress = aProfile->NCEmailAddress;
if (!aProfile->NCHavePregInfo.IsEmpty())
profileItem->NCHavePregInfo = aProfile->NCHavePregInfo;
if (isNewProfile) {
if (!mProfiles) {
mProfiles = new nsVoidArray;
if (!mProfiles)
mProfiles = new nsVoidArray();
return NS_ERROR_OUT_OF_MEMORY;
}
mProfiles->AppendElement((void*)profileItem);
}
@ -350,12 +326,6 @@ nsProfileAccess::FillProfileInfo(nsIFile* regName)
kRegistryVersionString.get(),
getter_Copies(tmpVersion));
if (tmpVersion == nsnull)
{
fixRegEntries = PR_TRUE;
mProfileDataChanged = PR_TRUE;
}
// Get the preg info
rv = registry->GetString(profilesTreeKey,
kRegistryHavePREGInfoString.get(),
@ -440,8 +410,23 @@ nsProfileAccess::FillProfileInfo(nsIFile* regName)
profileItem->updateProfileEntry = PR_TRUE;
profileItem->profileName = NS_STATIC_CAST(const PRUnichar*, profile);
rv = profileItem->InternalizeLocation(registry, profKey, PR_FALSE, fixRegEntries);
PRInt64 tmpLongLong;
rv = registry->GetLongLong(profKey,
kRegistryCreationTimeString.get(),
&tmpLongLong);
if (NS_SUCCEEDED(rv))
profileItem->creationTime = tmpLongLong;
rv = registry->GetLongLong(profKey,
kRegistryLastModTimeString.get(),
&tmpLongLong);
if (NS_SUCCEEDED(rv))
profileItem->lastModTime = tmpLongLong;
rv = profileItem->InternalizeLocation(registry, profKey, PR_FALSE);
NS_ASSERTION(NS_SUCCEEDED(rv), "Internalizing profile location failed");
// Not checking the error since most won't have this info
profileItem->InternalizeMigratedFromLocation(registry, profKey);
profileItem->isMigrated = isMigratedString.Equals(kRegistryYesString);
@ -768,6 +753,14 @@ nsProfileAccess::UpdateRegistry(nsIFile* regName)
kRegistryNCHavePREGInfoString.get(),
profileItem->NCHavePregInfo.get());
registry->SetLongLong(profKey,
kRegistryCreationTimeString.get(),
&profileItem->creationTime);
registry->SetLongLong(profKey,
kRegistryLastModTimeString.get(),
&profileItem->lastModTime);
rv = profileItem->ExternalizeLocation(registry, profKey);
if (NS_FAILED(rv)) {
NS_ASSERTION(PR_FALSE, "Could not update profile location");
@ -775,6 +768,7 @@ nsProfileAccess::UpdateRegistry(nsIFile* regName)
if (NS_FAILED(rv)) return rv;
continue;
}
profileItem->ExternalizeMigratedFromLocation(registry, profKey);
profileItem->updateProfileEntry = PR_FALSE;
}
@ -818,11 +812,20 @@ nsProfileAccess::UpdateRegistry(nsIFile* regName)
kRegistryNCHavePREGInfoString.get(),
profileItem->NCHavePregInfo.get());
registry->SetLongLong(profKey,
kRegistryCreationTimeString.get(),
&profileItem->creationTime);
registry->SetLongLong(profKey,
kRegistryLastModTimeString.get(),
&profileItem->lastModTime);
rv = profileItem->ExternalizeLocation(registry, profKey);
if (NS_FAILED(rv)) {
NS_ASSERTION(PR_FALSE, "Could not update profile location");
continue;
}
profileItem->ExternalizeMigratedFromLocation(registry, profKey);
profileItem->updateProfileEntry = PR_FALSE;
}
@ -873,6 +876,40 @@ nsProfileAccess::GetOriginalProfileDir(const PRUnichar *profileName, nsILocalFil
}
return NS_ERROR_FAILURE;
}
nsresult
nsProfileAccess::SetMigratedFromDir(const PRUnichar *profileName, nsILocalFile *originalDir)
{
NS_ENSURE_ARG(profileName);
NS_ENSURE_ARG(originalDir);
PRInt32 index = FindProfileIndex(profileName, PR_FALSE);
if (index >= 0)
{
ProfileStruct* profileItem = (ProfileStruct *) (mProfiles->ElementAt(index));
profileItem->migratedFrom = originalDir;
profileItem->updateProfileEntry = PR_TRUE;
return NS_OK;
}
return NS_ERROR_FAILURE;
}
nsresult
nsProfileAccess::SetProfileLastModTime(const PRUnichar *profileName, PRInt64 lastModTime)
{
NS_ENSURE_ARG(profileName);
PRInt32 index = FindProfileIndex(profileName, PR_FALSE);
if (index >= 0)
{
ProfileStruct* profileItem = (ProfileStruct *) (mProfiles->ElementAt(index));
profileItem->lastModTime = lastModTime;
profileItem->updateProfileEntry = PR_TRUE;
return NS_OK;
}
return NS_ERROR_FAILURE;
}
// Return the list of profiles, 4x, 5x, or both.
nsresult
nsProfileAccess::GetProfileList(PRInt32 whichKind, PRUint32 *length, PRUnichar ***result)
@ -1063,7 +1100,7 @@ nsProfileAccess::Get4xProfileInfo(const char *registryName, PRBool fromImport)
profileItem->updateProfileEntry = PR_TRUE;
profileItem->profileName = convertedProfName;
rv = profileItem->InternalizeLocation(oldReg, key, PR_TRUE, PR_FALSE);
rv = profileItem->InternalizeLocation(oldReg, key, PR_TRUE);
NS_ASSERTION(NS_SUCCEEDED(rv), "Could not get 4x profile location");
profileItem->isMigrated = PR_FALSE;
profileItem->isImportType = fromImport;
@ -1218,20 +1255,53 @@ nsProfileAccess::DetermineForceMigration(PRBool *forceMigration)
// class ProfileStruct
// **********************************************************************
ProfileStruct::ProfileStruct(const ProfileStruct& src) :
profileName(src.profileName), isMigrated(src.isMigrated),
NCProfileName(src.NCProfileName), NCDeniedService(src.NCDeniedService),
NCEmailAddress(src.NCEmailAddress), NCHavePregInfo(src.NCHavePregInfo),
updateProfileEntry(src.updateProfileEntry),
isImportType(src.isImportType),
regLocationData(src.regLocationData)
ProfileStruct::ProfileStruct() :
isMigrated(PR_FALSE), updateProfileEntry(PR_FALSE),
isImportType(PR_FALSE),
creationTime(LL_ZERO), lastModTime(LL_ZERO)
{
if (src.resolvedLocation) {
}
ProfileStruct::ProfileStruct(const ProfileStruct& src)
{
*this = src;
}
ProfileStruct& ProfileStruct::operator=(const ProfileStruct& rhs)
{
profileName = rhs.profileName;
isMigrated = rhs.isMigrated;
NCProfileName = rhs.NCProfileName;
NCDeniedService = rhs.NCDeniedService;
NCEmailAddress = rhs.NCEmailAddress;
NCHavePregInfo = rhs.NCHavePregInfo;
updateProfileEntry = rhs.updateProfileEntry;
isImportType = rhs.isImportType;
creationTime = rhs.creationTime;
lastModTime = rhs.lastModTime;
nsresult rv;
nsCOMPtr<nsIFile> file;
nsresult rv = src.resolvedLocation->Clone(getter_AddRefs(file));
resolvedLocation = nsnull;
if (rhs.resolvedLocation) {
regLocationData.Truncate(0);
rv = rhs.resolvedLocation->Clone(getter_AddRefs(file));
if (NS_SUCCEEDED(rv))
resolvedLocation = do_QueryInterface(file);
file = nsnull;
}
else
regLocationData = rhs.regLocationData;
migratedFrom = nsnull;
if (rhs.migratedFrom) {
rv = rhs.migratedFrom->Clone(getter_AddRefs(file));
if (NS_SUCCEEDED(rv))
migratedFrom = do_QueryInterface(file);
}
return *this;
}
nsresult ProfileStruct::GetResolvedProfileDir(nsILocalFile **aDirectory)
@ -1270,7 +1340,7 @@ nsresult ProfileStruct::CopyProfileLocation(ProfileStruct *destStruct)
return NS_OK;
}
nsresult ProfileStruct::InternalizeLocation(nsIRegistry *aRegistry, nsRegistryKey profKey, PRBool is4x, PRBool isOld50)
nsresult ProfileStruct::InternalizeLocation(nsIRegistry *aRegistry, nsRegistryKey profKey, PRBool is4x)
{
nsresult rv;
nsCOMPtr<nsILocalFile> tempLocal;
@ -1315,90 +1385,24 @@ nsresult ProfileStruct::InternalizeLocation(nsIRegistry *aRegistry, nsRegistryKe
{
nsXPIDLString regData;
if (isOld50) // Some format which was used around M10-M11. Can we forget about it?
{
rv = aRegistry->GetString(profKey,
kRegistryDirectoryString.get(),
getter_Copies(regData));
if (NS_FAILED(rv)) return rv;
PRBool haveHexBytes = PR_TRUE;
// Decode the directory name to return the ordinary string
nsCAutoString regDataCString; regDataCString.AssignWithConversion(regData);
nsInputStringStream stream(regDataCString.get());
char bigBuffer[MAX_PERSISTENT_DATA_SIZE + 1];
// The first 8 bytes of the data should be a hex version of the data size to follow.
PRInt32 bytesRead = NUM_HEX_BYTES;
bytesRead = stream.read(bigBuffer, bytesRead);
if (bytesRead != NUM_HEX_BYTES)
haveHexBytes = PR_FALSE;
if (haveHexBytes)
{
bigBuffer[NUM_HEX_BYTES] = '\0';
for (int i = 0; i < NUM_HEX_BYTES; i++)
{
if (!(ISHEX(bigBuffer[i])))
{
haveHexBytes = PR_FALSE;
break;
}
}
}
nsAutoString dirNameString;
if (haveHexBytes)
{
PR_sscanf(bigBuffer, "%x", (PRUint32*)&bytesRead);
if (bytesRead > MAX_PERSISTENT_DATA_SIZE)
{
// Try to tolerate encoded values with no length header
bytesRead = NUM_HEX_BYTES +
stream.read(bigBuffer + NUM_HEX_BYTES,
MAX_PERSISTENT_DATA_SIZE - NUM_HEX_BYTES);
}
else
{
// Now we know how many bytes to read, do it.
bytesRead = stream.read(bigBuffer, bytesRead);
}
// Make sure we are null terminated
bigBuffer[bytesRead]='\0';
dirNameString.AssignWithConversion(nsDependentCString(bigBuffer, bytesRead).get());
}
else
dirNameString = regData;
rv = NS_NewUnicodeLocalFile(dirNameString.get(), PR_TRUE, getter_AddRefs(tempLocal));
}
else
{
rv = aRegistry->GetString(profKey,
kRegistryDirectoryString.get(),
getter_Copies(regData));
if (NS_FAILED(rv)) return rv;
regLocationData = regData;
rv = aRegistry->GetString(profKey,
kRegistryDirectoryString.get(),
getter_Copies(regData));
if (NS_FAILED(rv)) return rv;
regLocationData = regData;
#ifdef XP_MAC
// For a brief time, this was a unicode path
PRInt32 firstColon = regLocationData.FindChar(PRUnichar(':'));
if (firstColon == -1)
{
rv = NS_NewLocalFile(nsnull, PR_TRUE, getter_AddRefs(tempLocal));
if (NS_SUCCEEDED(rv))
rv = tempLocal->SetPersistentDescriptor(NS_ConvertUCS2toUTF8(regLocationData).get());
}
else
#endif
rv = NS_NewUnicodeLocalFile(regLocationData.get(), PR_TRUE, getter_AddRefs(tempLocal));
// For a brief time, this was a unicode path
PRInt32 firstColon = regLocationData.FindChar(PRUnichar(':'));
if (firstColon == -1)
{
rv = NS_NewLocalFile(nsnull, PR_TRUE, getter_AddRefs(tempLocal));
if (NS_SUCCEEDED(rv))
rv = tempLocal->SetPersistentDescriptor(NS_ConvertUCS2toUTF8(regLocationData).get());
}
else
#endif
rv = NS_NewUnicodeLocalFile(regLocationData.get(), PR_TRUE, getter_AddRefs(tempLocal));
}
if (NS_SUCCEEDED(rv) && tempLocal)
@ -1459,6 +1463,59 @@ nsresult ProfileStruct::ExternalizeLocation(nsIRegistry *aRegistry, nsRegistryKe
return rv;
}
nsresult ProfileStruct::InternalizeMigratedFromLocation(nsIRegistry *aRegistry, nsRegistryKey profKey)
{
nsresult rv;
nsXPIDLCString regData;
nsCOMPtr<nsILocalFile> tempLocal;
rv = aRegistry->GetStringUTF8(profKey,
kRegistryMigratedFromString.get(),
getter_Copies(regData));
if (NS_SUCCEEDED(rv))
{
#ifdef XP_MAC
rv = NS_NewLocalFile(nsnull, PR_TRUE, getter_AddRefs(tempLocal));
if (NS_SUCCEEDED(rv))
{
// The persistent desc on Mac is base64 encoded so plain ASCII
rv = tempLocal->SetPersistentDescriptor(regData.get());
if (NS_SUCCEEDED(rv))
migratedFrom = tempLocal;
}
#else
rv = NS_NewUnicodeLocalFile(NS_ConvertUTF8toUCS2(regData).get(), PR_TRUE, getter_AddRefs(tempLocal));
if (NS_SUCCEEDED(rv))
migratedFrom = tempLocal;
#endif
}
return rv;
}
nsresult ProfileStruct::ExternalizeMigratedFromLocation(nsIRegistry *aRegistry, nsRegistryKey profKey)
{
nsresult rv = NS_OK;
nsXPIDLCString regData;
if (migratedFrom)
{
#if XP_MAC
rv = migratedFrom->GetPersistentDescriptor(getter_Copies(regData));
#else
nsXPIDLString ucPath;
rv = resolvedLocation->GetUnicodePath(getter_Copies(ucPath));
if (NS_SUCCEEDED(rv))
regData = NS_ConvertUCS2toUTF8(ucPath);
#endif
if (NS_SUCCEEDED(rv))
rv = aRegistry->SetStringUTF8(profKey,
kRegistryMigratedFromString.get(),
regData.get());
}
return rv;
}
nsresult ProfileStruct::EnsureDirPathExists(nsILocalFile *aDir, PRBool *wasCreated)
{
NS_ENSURE_ARG(aDir);

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

@ -33,11 +33,13 @@
class ProfileStruct
{
public:
explicit ProfileStruct() { }
ProfileStruct();
ProfileStruct(const ProfileStruct& src);
~ProfileStruct() { }
ProfileStruct& operator=(const ProfileStruct& rhs);
/*
* GetResolvedProfileDir returns the directory specified in the
* registry. It will return NULL if the spec in the registry
@ -63,12 +65,19 @@ public:
* Methods used by routines which internalize
* and externalize profile info.
*/
nsresult InternalizeLocation(nsIRegistry *aRegistry, nsRegistryKey profKey, PRBool is4x, PRBool isOld50);
nsresult InternalizeLocation(nsIRegistry *aRegistry, nsRegistryKey profKey, PRBool is4x);
nsresult ExternalizeLocation(nsIRegistry *aRegistry, nsRegistryKey profKey);
nsresult InternalizeMigratedFromLocation(nsIRegistry *aRegistry, nsRegistryKey profKey);
nsresult ExternalizeMigratedFromLocation(nsIRegistry *aRegistry, nsRegistryKey profKey);
public:
nsString profileName;
PRBool isMigrated;
// The directory from which this profile was migrated from (if any)
// Added in mozilla1.0.1 and maintained in the registry
nsCOMPtr<nsILocalFile> migratedFrom;
nsString NCProfileName;
nsString NCDeniedService;
nsString NCEmailAddress;
@ -76,6 +85,11 @@ public:
PRBool updateProfileEntry;
// this flag detemines if we added this profile to the list for the import module.
PRBool isImportType;
// These fields were added in mozilla1.0.1 and maintained in the registry.
// Values are in milliseconds since midnight Jan 1, 1970 GMT (same as nsIFile)
// Their values will be LL_ZERO if undefined.
PRInt64 creationTime;
PRInt64 lastModTime;
private:
nsresult EnsureDirPathExists(nsILocalFile *aFile, PRBool *wasCreated);
@ -115,6 +129,8 @@ public:
void GetFirstProfile(PRUnichar **firstProfile);
nsresult GetProfileList(PRInt32 whichKind, PRUint32 *length, PRUnichar ***result);
nsresult GetOriginalProfileDir(const PRUnichar *profileName, nsILocalFile **orginalDir);
nsresult SetMigratedFromDir(const PRUnichar *profileName, nsILocalFile *orginalDir);
nsresult SetProfileLastModTime(const PRUnichar *profileName, PRInt64 lastModTime);
// if fromImport is true all the 4.x profiles will be added to mProfiles with the isImportType flag set.
// pass fromImport as True only if you are calling from the Import Module.

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

@ -80,6 +80,12 @@ PRBool OnMacOSX();
#include "nsIScriptContext.h"
#include "jsapi.h"
/* for the "remigration" stuff */
#include "nsIPrefService.h"
#include "nsIPrefBranch.h"
#include "nsIPromptService.h"
#include "nsIStringBundle.h"
#include "nsAppShellService.h"
#include "nsIProfileInternal.h"
@ -234,8 +240,7 @@ nsAppShellService::DoProfileStartup(nsICmdLineService *aCmdLineService, PRBool c
nsresult rv;
nsCOMPtr<nsIProfileInternal> profileMgr(do_GetService(NS_PROFILE_CONTRACTID, &rv));
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to get profile manager");
if (NS_FAILED(rv)) return rv;
NS_ENSURE_SUCCESS(rv,rv);
PRBool saveQuitOnLastWindowClosing = mQuitOnLastWindowClosing;
mQuitOnLastWindowClosing = PR_FALSE;
@ -247,11 +252,148 @@ nsAppShellService::DoProfileStartup(nsICmdLineService *aCmdLineService, PRBool c
rv = NS_OK;
}
mQuitOnLastWindowClosing = saveQuitOnLastWindowClosing;
if (NS_SUCCEEDED(rv)) {
rv = CheckAndRemigrateDefunctProfile();
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to check and remigrate profile");
rv = NS_OK;
}
mQuitOnLastWindowClosing = saveQuitOnLastWindowClosing;
return rv;
}
nsresult
nsAppShellService::CheckAndRemigrateDefunctProfile()
{
nsresult rv;
nsCOMPtr<nsIPrefBranch> prefBranch;
nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv,rv);
rv = prefs->GetBranch(nsnull, getter_AddRefs(prefBranch));
NS_ENSURE_SUCCESS(rv,rv);
PRInt32 secondsBeforeDefunct;
rv = prefBranch->GetIntPref("profile.seconds_until_defunct", &secondsBeforeDefunct);
NS_ENSURE_SUCCESS(rv,rv);
// -1 is the value for "never go defunct"
// if the pref is set to -1, we'll never prompt the user to remigrate
// see all.js (and all-ns.js)
if (secondsBeforeDefunct == -1)
return NS_OK;
// used for converting
// seconds -> millisecs
// and microsecs -> millisecs
PRInt64 oneThousand = LL_INIT(0, 1000);
PRInt64 defunctInterval;
// Init as seconds
LL_I2L(defunctInterval, secondsBeforeDefunct);
// Convert secs to millisecs
LL_MUL(defunctInterval, defunctInterval, oneThousand);
nsCOMPtr<nsIProfileInternal> profileMgr(do_GetService(NS_PROFILE_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv,rv);
nsXPIDLString profileName;
PRInt64 lastModTime;
profileMgr->GetCurrentProfile(getter_Copies(profileName));
rv = profileMgr->GetProfileLastModTime(profileName.get(), &lastModTime);
NS_ENSURE_SUCCESS(rv,rv);
// convert "now" from microsecs to millisecs
PRInt64 nowInMilliSecs = PR_Now();
LL_DIV(nowInMilliSecs, nowInMilliSecs, oneThousand);
// determine (using the pref value) when the profile would be considered defunct
PRInt64 defunctIntervalAgo;
LL_SUB(defunctIntervalAgo, nowInMilliSecs, defunctInterval);
// if we've used our current 6.x / mozilla profile more recently than
// when we'd consider it defunct, don't remigrate
if (LL_CMP(lastModTime, >, defunctIntervalAgo))
return NS_OK;
nsCOMPtr<nsILocalFile> origProfileDir;
rv = profileMgr->GetOriginalProfileDir(profileName, getter_AddRefs(origProfileDir));
// if this fails
// then the current profile is a new one (not from 4.x)
// so we are done.
if (NS_FAILED(rv))
return NS_OK;
// Now, we know that a matching 4.x profile exists
// See if it has any newer files in it than our defunct profile.
nsCOMPtr<nsISimpleEnumerator> dirEnum;
rv = origProfileDir->GetDirectoryEntries(getter_AddRefs(dirEnum));
NS_ENSURE_SUCCESS(rv,rv);
PRBool promptForRemigration = PR_FALSE;
PRBool hasMore;
while (NS_SUCCEEDED(dirEnum->HasMoreElements(&hasMore)) && hasMore) {
nsCOMPtr<nsILocalFile> currElem;
rv = dirEnum->GetNext(getter_AddRefs(currElem));
NS_ENSURE_SUCCESS(rv,rv);
PRInt64 currElemModTime;
rv = currElem->GetLastModifiedTime(&currElemModTime);
NS_ENSURE_SUCCESS(rv,rv);
// if this file in our 4.x profile is more recent than when we last used our mozilla / 6.x profile
// we should prompt for re-migration
if (LL_CMP(currElemModTime, >, lastModTime)) {
promptForRemigration = PR_TRUE;
break;
}
}
// If nothing in the 4.x dir is newer than our defunct profile, return.
if (!promptForRemigration)
return NS_OK;
nsCOMPtr<nsIStringBundleService> stringBundleService(do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv,rv);
nsCOMPtr<nsIStringBundle> migrationBundle, brandBundle;
rv = stringBundleService->CreateBundle("chrome://communicator/locale/profile/migration.properties", getter_AddRefs(migrationBundle));
NS_ENSURE_SUCCESS(rv,rv);
rv = stringBundleService->CreateBundle("chrome://global/locale/brand.properties", getter_AddRefs(brandBundle));
NS_ENSURE_SUCCESS(rv,rv);
nsXPIDLString brandName;
rv = brandBundle->GetStringFromName(NS_LITERAL_STRING("brandShortName").get(), getter_Copies(brandName));
NS_ENSURE_SUCCESS(rv,rv);
nsXPIDLString dialogText;
rv = migrationBundle->GetStringFromName(NS_LITERAL_STRING("confirmRemigration").get(), getter_Copies(dialogText));
NS_ENSURE_SUCCESS(rv,rv);
nsCOMPtr<nsIPromptService> promptService(do_GetService("@mozilla.org/embedcomp/prompt-service;1", &rv));
NS_ENSURE_SUCCESS(rv,rv);
PRInt32 buttonPressed;
rv = promptService->ConfirmEx(nsnull, brandName.get(),
dialogText.get(),
(nsIPromptService::BUTTON_POS_0 *
nsIPromptService::BUTTON_TITLE_YES) +
(nsIPromptService::BUTTON_POS_1 *
nsIPromptService::BUTTON_TITLE_NO),
nsnull, nsnull, nsnull, nsnull, nsnull, &buttonPressed);
NS_ENSURE_SUCCESS(rv,rv);
if (buttonPressed == 0) {
// Need to shut down the current profile before remigrating it
profileMgr->ShutDownCurrentProfile(nsIProfile::SHUTDOWN_PERSIST);
// If this fails, it will restore what was there.
rv = profileMgr->RemigrateProfile(profileName.get());
NS_ASSERTION(NS_SUCCEEDED(rv), "Remigration of profile failed.");
// Whether or not we succeeded or failed, need to reset this.
profileMgr->SetCurrentProfile(profileName.get());
}
return NS_OK;
}
NS_IMETHODIMP
nsAppShellService::CreateHiddenWindow()
{

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

@ -96,6 +96,9 @@ protected:
static void* PR_CALLBACK HandleExitEvent(PLEvent* aEvent);
static void PR_CALLBACK DestroyExitEvent(PLEvent* aEvent);
private:
nsresult CheckAndRemigrateDefunctProfile();
};
#endif

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

@ -52,6 +52,7 @@ REQUIRES = xpcom \
uconv \
locale \
xremoteservice \
profile \
$(NULL)
# for jprof
REQUIRES += jprof

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

@ -96,6 +96,9 @@
#include "nsIXRemoteService.h"
#endif
// see DoOnShutdown()
#include "nsIProfile.h"
#ifdef NS_TRACE_MALLOC
#include "nsTraceMalloc.h"
#endif
@ -106,7 +109,7 @@
#include "nsITimelineService.h"
#if defined(DEBUG_sspitzer) || defined(DEBUG_seth) || defined(DEBUG_pra)
#if defined(DEBUG_pra)
#define DEBUG_CMD_LINE
#endif
@ -773,6 +776,17 @@ static nsresult DoOnShutdown()
{
nsresult rv;
// call ShutDownCurrentProfile() so we update the last modified time of the profile
{
// scoping this in a block to force release
nsCOMPtr<nsIProfile> profileMgr(do_GetService(NS_PROFILE_CONTRACTID, &rv));
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to get profile manager, so unable to update last modified time");
if (NS_SUCCEEDED(rv)) {
// 0 is undefined, we use this secret value so that we don't notify
profileMgr->ShutDownCurrentProfile(0);
}
}
// save the prefs, in case they weren't saved
{
// scoping this in a block to force release