From ca7c6cfe6b49db472093f301f2247a4aadf9f501 Mon Sep 17 00:00:00 2001 From: "bnesse%netscape.com" Date: Tue, 19 Feb 2002 05:55:08 +0000 Subject: [PATCH] Fix for bug 98476. Add safe save and redundant backup support for preferences. r=sfraser, sr=alecf. git-svn-id: svn://10.0.0.236/trunk@114895 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/modules/libpref/macbuild/libpref.xml | 30 ++++ mozilla/modules/libpref/src/Makefile.in | 1 + mozilla/modules/libpref/src/init/all.js | 2 + mozilla/modules/libpref/src/makefile.win | 1 + mozilla/modules/libpref/src/nsPrefService.cpp | 165 +++++++++--------- mozilla/modules/libpref/src/nsPrefService.h | 7 +- .../modules/libpref/src/nsSafeSaveFile.cpp | 22 +-- mozilla/modules/libpref/src/nsSafeSaveFile.h | 1 - mozilla/modules/libpref/src/prefapi.cpp | 5 +- .../libpref/src/prefapi_private_data.h | 11 -- 10 files changed, 130 insertions(+), 115 deletions(-) diff --git a/mozilla/modules/libpref/macbuild/libpref.xml b/mozilla/modules/libpref/macbuild/libpref.xml index a83c873806b..c3397385a67 100644 --- a/mozilla/modules/libpref/macbuild/libpref.xml +++ b/mozilla/modules/libpref/macbuild/libpref.xml @@ -994,6 +994,13 @@ Text Debug + + Name + nsSafeSaveFile.cpp + MacOS + Text + Debug + @@ -1056,6 +1063,11 @@ prefapi.cpp MacOS + + Name + nsSafeSaveFile.cpp + MacOS + @@ -1999,6 +2011,13 @@ Text + + Name + nsSafeSaveFile.cpp + MacOS + Text + Debug + @@ -2061,6 +2080,11 @@ prefapi.cpp MacOS + + Name + nsSafeSaveFile.cpp + MacOS + @@ -2096,6 +2120,12 @@ nsPrefsFactory.cpp MacOS + + libprefDebug.shlb + Name + nsSafeSaveFile.cpp + MacOS + libprefDebug.shlb Name diff --git a/mozilla/modules/libpref/src/Makefile.in b/mozilla/modules/libpref/src/Makefile.in index 0df8b887a65..2092e3bd691 100644 --- a/mozilla/modules/libpref/src/Makefile.in +++ b/mozilla/modules/libpref/src/Makefile.in @@ -50,6 +50,7 @@ CPPSRCS = nsPref.cpp \ nsPrefBranch.cpp \ nsPrefService.cpp \ nsPrefsFactory.cpp \ + nsSafeSaveFile.cpp \ prefapi.cpp \ $(NULL) diff --git a/mozilla/modules/libpref/src/init/all.js b/mozilla/modules/libpref/src/init/all.js index 46a57ba2d82..e8fc9e308b6 100644 --- a/mozilla/modules/libpref/src/init/all.js +++ b/mozilla/modules/libpref/src/init/all.js @@ -55,6 +55,8 @@ pref("general.startup.addressbook", false); pref("general.open_location.last_url", ""); pref("general.open_location.last_window_choice", 0); +pref("backups.number_of_prefs_copies", 1); + // 0 = blank, 1 = home (browser.startup.homepage), 2 = last pref("browser.startup.page", 1); pref("browser.startup.homepage", "chrome://navigator-region/locale/region.properties"); diff --git a/mozilla/modules/libpref/src/makefile.win b/mozilla/modules/libpref/src/makefile.win index 2195c3edb43..4c7d93741dc 100644 --- a/mozilla/modules/libpref/src/makefile.win +++ b/mozilla/modules/libpref/src/makefile.win @@ -69,6 +69,7 @@ OBJS = \ .\$(OBJDIR)\nsPrefBranch.obj \ .\$(OBJDIR)\nsPrefService.obj \ .\$(OBJDIR)\nsPrefsFactory.obj \ + .\$(OBJDIR)\nsSafeSaveFile.obj \ $(NULL) #//------------------------------------------------------------------------ diff --git a/mozilla/modules/libpref/src/nsPrefService.cpp b/mozilla/modules/libpref/src/nsPrefService.cpp index eefb019be86..a096b6ec459 100644 --- a/mozilla/modules/libpref/src/nsPrefService.cpp +++ b/mozilla/modules/libpref/src/nsPrefService.cpp @@ -37,10 +37,12 @@ * ***** END LICENSE BLOCK ***** */ #include "nsPrefService.h" +#include "nsSafeSaveFile.h" #include "jsapi.h" #include "nsAppDirectoryServiceDefs.h" #include "nsDirectoryServiceDefs.h" #include "nsICategoryManager.h" +#include "nsIFile.h" #include "nsIFileStreams.h" #include "nsIObserverService.h" #include "nsPrefBranch.h" @@ -51,29 +53,20 @@ #include "pldhash.h" #include "prefapi.h" -class nsIFileSpec; // needed for prefapi_private_data.h inclusion #include "prefapi_private_data.h" // supporting PREF_Init() #include "nsIJSRuntimeService.h" -// lose these if possible (supporting nsIFileToFileSpec) -#include "nsIFileSpec.h" -#include "nsFileStream.h" - #include "nsITimelineService.h" // Definitions -#define PREFS_HEADER_LINE_1 "# Mozilla User Preferences" -#define PREFS_HEADER_LINE_2 "// This is a generated file!" #define INITIAL_MAX_DEFAULT_PREF_FILES 10 // Prototypes -static nsresult nsIFileToFileSpec(nsIFile* inFile, nsIFileSpec **aFileSpec); static nsresult openPrefFile(nsIFile* aFile, PRBool aIsErrorFatal, PRBool aIsGlobalContext, PRBool aSkipFirstLine); -static nsresult savePrefFile(nsIFile* aFile); // needed so we can still get the JS Runtime Service during XPCOM shutdown @@ -184,11 +177,11 @@ NS_IMETHODIMP nsPrefService::ReadUserPrefs(nsIFile *aFile) nsresult rv; if (nsnull == aFile) { - rv = useDefaultPrefFile(); // really should return a value... + rv = UseDefaultPrefFile(); // really should return a value... if (NS_SUCCEEDED(rv)) - useUserPrefFile(); + UseUserPrefFile(); - notifyObservers(NS_PREFSERVICE_READ_TOPIC_ID); + InformObservers(NS_PREFSERVICE_READ_TOPIC_ID); JS_MaybeGC(gMochaContext); } else { @@ -208,7 +201,7 @@ NS_IMETHODIMP nsPrefService::ReadUserPrefs(nsIFile *aFile) NS_IMETHODIMP nsPrefService::ResetPrefs() { - notifyObservers(NS_PREFSERVICE_RESET_TOPIC_ID); + InformObservers(NS_PREFSERVICE_RESET_TOPIC_ID); PREF_CleanupPrefs(); if (!PREF_Init(nsnull)) @@ -223,14 +216,13 @@ NS_IMETHODIMP nsPrefService::ResetUserPrefs() return NS_OK; } -/* void savePrefFile (in nsIFile filename); */ NS_IMETHODIMP nsPrefService::SavePrefFile(nsIFile *aFile) { if (nsnull == aFile) { // It's possible that we never got a prefs file. - return mCurrentFile ? savePrefFile(mCurrentFile) : NS_OK; + return mCurrentFile ? SafeSavePrefFile(mCurrentFile) : NS_OK; } else { - return savePrefFile(aFile); + return SafeSavePrefFile(aFile); } } @@ -289,7 +281,7 @@ NS_IMETHODIMP nsPrefService::RemoveObserver(const char *aDomain, nsIObserver *aO } -nsresult nsPrefService::notifyObservers(const char *aTopic) +nsresult nsPrefService::InformObservers(const char *aTopic) { nsresult rv; nsCOMPtr observerService = @@ -304,8 +296,75 @@ nsresult nsPrefService::notifyObservers(const char *aTopic) return NS_OK; } +nsresult nsPrefService::SafeSavePrefFile(nsIFile* aFile) +{ + const char outHeader[] = "# Mozilla User Preferences" + NS_LINEBREAK + "// This is a generated file!" + NS_LINEBREAK + NS_LINEBREAK; + nsCOMPtr outStream; + nsCOMPtr tempFile; + PRUint32 writeAmount; + nsresult rv; -nsresult nsPrefService::useDefaultPrefFile() + if (!gHashTable.ops) + return NS_ERROR_NOT_INITIALIZED; + + /* ?! Don't save (blank) user prefs if there was an error reading them */ + if (gErrorOpeningUserPrefs) + return NS_OK; + + // execute a "safe" save by saving through a tempfile + PRInt32 numCopies = 1; + mRootBranch->GetIntPref("backups.number_of_prefs_copies", &numCopies); + + nsSafeSaveFile safeSave(aFile, numCopies); + rv = safeSave.GetSaveFile(getter_AddRefs(tempFile)); + if (NS_FAILED(rv)) + return NS_ERROR_OUT_OF_MEMORY; + + char** valueArray = (char**) PR_Calloc(sizeof(char*), gHashTable.entryCount); + if (!valueArray) + return NS_ERROR_OUT_OF_MEMORY; + + rv = NS_NewLocalFileOutputStream(getter_AddRefs(outStream), tempFile); + if (NS_FAILED(rv)) + return rv; + + // write out the file header + rv = outStream->Write(outHeader, sizeof(outHeader) - 1, &writeAmount); + + // get the lines that we're supposed to be writing to the file + PL_DHashTableEnumerate(&gHashTable, pref_savePref, valueArray); + + /* Sort the preferences to make a readable file on disk */ + NS_QuickSort(valueArray, gHashTable.entryCount, sizeof(char*), pref_CompareStrings, NULL); + char** walker = valueArray; + for (PRUint32 valueIdx = 0; valueIdx < gHashTable.entryCount; valueIdx++, walker++) { + if (*walker) { + // skip writing if an has error occurred + if (NS_SUCCEEDED(rv)) { + rv = outStream->Write(*walker, strlen(*walker), &writeAmount); + if (NS_SUCCEEDED(rv)) + rv = outStream->Write(NS_LINEBREAK, NS_LINEBREAK_LEN, &writeAmount); + } + // always free though... + PR_Free(*walker); + } + } + PR_Free(valueArray); + outStream->Close(); + + // if save was successful replace the original file and perform backup(s) if desired + if (NS_SUCCEEDED(rv)) + rv = safeSave.PostProcessSave(); + else + safeSave.CleanupFailedSave(); + return rv; +} + +nsresult nsPrefService::UseDefaultPrefFile() { nsresult rv; nsCOMPtr aFile; @@ -333,7 +392,7 @@ nsresult nsPrefService::useDefaultPrefFile() return rv; } -nsresult nsPrefService::useUserPrefFile() +nsresult nsPrefService::UseUserPrefFile() { nsresult rv = NS_OK; nsCOMPtr aFile; @@ -402,74 +461,6 @@ static nsresult openPrefFile(nsIFile* aFile, PRBool aIsErrorFatal, return rv; } -static nsresult savePrefFile(nsIFile* aFile) -{ - nsresult rv; - nsCOMPtr fileSpec; - - if (!gHashTable.ops) - return NS_ERROR_NOT_INITIALIZED; - - /* ?! Don't save (blank) user prefs if there was an error reading them */ - if (gErrorOpeningUserPrefs) - return NS_OK; - - // TODO: Convert the rest of this code to nsIFile and avoid this conversion to nsIFileSpec - rv = nsIFileToFileSpec(aFile, getter_AddRefs(fileSpec)); - if (NS_FAILED(rv)) - return rv; - - char** valueArray = (char**) PR_Calloc(sizeof(char*), gHashTable.entryCount); - if (!valueArray) - return NS_ERROR_OUT_OF_MEMORY; - - nsOutputFileStream stream(fileSpec); - if (!stream.is_open()) - return NS_BASE_STREAM_OSERROR; - - stream << PREFS_HEADER_LINE_1 << nsEndl << PREFS_HEADER_LINE_2 << nsEndl << nsEndl; - - // get the lines that we're supposed to be writing to the file - PL_DHashTableEnumerate(&gHashTable, pref_savePref, valueArray); - - /* Sort the preferences to make a readable file on disk */ - NS_QuickSort(valueArray, gHashTable.entryCount, sizeof(char*), pref_CompareStrings, NULL); - char** walker = valueArray; - for (PRUint32 valueIdx = 0; valueIdx < gHashTable.entryCount; valueIdx++, walker++) { - if (*walker) { - stream << *walker << nsEndl; - PR_Free(*walker); - } - } - PR_Free(valueArray); - fileSpec->CloseStream(); - return NS_OK; -} - - -//---------------------------------------------------------------------------------------- -// So discouraged is the use of nsIFileSpec, nobody wanted to have this routine be -// public - It might lead to continued use of nsIFileSpec. Right now, this code has -// such a need for it, here it is. Let's stop having to use it though. -static nsresult nsIFileToFileSpec(nsIFile* inFile, nsIFileSpec **aFileSpec) -//---------------------------------------------------------------------------------------- -{ - nsresult rv; - nsCOMPtr newFileSpec; - nsXPIDLCString pathBuf; - - rv = inFile->GetPath(getter_Copies(pathBuf)); - if (NS_FAILED(rv)) return rv; - rv = NS_NewFileSpec(getter_AddRefs(newFileSpec)); - if (NS_FAILED(rv)) return rv; - rv = newFileSpec->SetNativePath((const char *)pathBuf); - if (NS_FAILED(rv)) return rv; - - *aFileSpec = newFileSpec; - NS_ADDREF(*aFileSpec); - - return NS_OK; -} /* * some stuff that gets called from Pref_Init() diff --git a/mozilla/modules/libpref/src/nsPrefService.h b/mozilla/modules/libpref/src/nsPrefService.h index 6870d1e67fc..1164856a2ca 100644 --- a/mozilla/modules/libpref/src/nsPrefService.h +++ b/mozilla/modules/libpref/src/nsPrefService.h @@ -64,9 +64,10 @@ public: nsresult Init(); protected: - nsresult notifyObservers(const char *aSubject); - nsresult useDefaultPrefFile(); - nsresult useUserPrefFile(); + nsresult InformObservers(const char *aSubject); + nsresult SafeSavePrefFile(nsIFile* aFile); + nsresult UseDefaultPrefFile(); + nsresult UseUserPrefFile(); private: nsCOMPtr mRootBranch; diff --git a/mozilla/modules/libpref/src/nsSafeSaveFile.cpp b/mozilla/modules/libpref/src/nsSafeSaveFile.cpp index d6e64be28bc..2e8fa8f4bf1 100644 --- a/mozilla/modules/libpref/src/nsSafeSaveFile.cpp +++ b/mozilla/modules/libpref/src/nsSafeSaveFile.cpp @@ -48,7 +48,7 @@ nsSafeSaveFile::nsSafeSaveFile(nsIFile *aTargetFile, PRInt32 aNumBackupCopies) mBackupCount(aNumBackupCopies) { nsCAutoString tempFileName; - char * temp; + const char * temp; nsresult rv; // determine the actual filename (less the extension) @@ -56,14 +56,14 @@ nsSafeSaveFile::nsSafeSaveFile(nsIFile *aTargetFile, PRInt32 aNumBackupCopies) if (NS_FAILED(rv)) // yikes! out of memory return; - temp = strrchr(mTargetFileName, '.'); + temp = strrchr(mTargetFileName.get(), '.'); if (temp) - mTargetNameLen = temp - mTargetFileName; + mTargetNameLen = temp - mTargetFileName.get(); else - mTargetNameLen = strlen(mTargetFileName); + mTargetNameLen = strlen(mTargetFileName.get()); // create a new file object that points to the temp file - tempFileName.Assign(mTargetFileName, mTargetNameLen); + tempFileName.Assign(mTargetFileName.get(), mTargetNameLen); tempFileName += ".tmp"; rv = aTargetFile->Clone(getter_AddRefs(mTempFile)); if (NS_SUCCEEDED(rv)) @@ -104,14 +104,14 @@ nsresult nsSafeSaveFile::PostProcessSave(void) if (mBackupCount > 0) { // kill the (oldest) backup copy, if necessary - fileName.Assign(mTargetFileName, mTargetNameLen); + fileName.Assign(mTargetFileName.get(), mTargetNameLen); fileName += BACKUP_FILE_EXTENSION; if (mBackupCount > 1) fileName.AppendInt(mBackupCount - 1); backupFile->SetLeafName(fileName.get()); } else { // no backups desired, delete the previous save - backupFile->SetLeafName(mTargetFileName); + backupFile->SetLeafName(mTargetFileName.get()); } // remove the file as determined by the logic above @@ -120,7 +120,7 @@ nsresult nsSafeSaveFile::PostProcessSave(void) // now manage the backup copies if (mBackupCount > 0) { PRInt32 backupCount = mBackupCount; - fileName.Assign(mTargetFileName, mTargetNameLen); + fileName.Assign(mTargetFileName.get(), mTargetNameLen); fileName += BACKUP_FILE_EXTENSION; while (--backupCount > 0) { // bump all of the redundant backups up one (i.e. bak -> bak1, bak1 -> bak2, etc.) @@ -138,14 +138,14 @@ nsresult nsSafeSaveFile::PostProcessSave(void) }; // rename the previous save to .bak (i.e. to ) - backupFile->SetLeafName(mTargetFileName); + backupFile->SetLeafName(mTargetFileName.get()); rv = backupFile->MoveTo(0, fileName.get()); if (NS_FAILED(rv)) return rv; } // finally rename the temp file to the original name (i.e. to ) - rv = mTempFile->MoveTo(0, mTargetFileName); + rv = mTempFile->MoveTo(0, mTargetFileName.get()); return rv; } @@ -166,7 +166,7 @@ nsresult nsSafeSaveFile::PurgeOldestBackup(void) return NS_ERROR_FILE_NOT_FOUND; PRInt32 backupCount = mBackupCount; - fileName.Assign(mTargetFileName, mTargetNameLen); + fileName.Assign(mTargetFileName.get(), mTargetNameLen); fileName += BACKUP_FILE_EXTENSION; while (--backupCount >= 0) { if (backupCount) diff --git a/mozilla/modules/libpref/src/nsSafeSaveFile.h b/mozilla/modules/libpref/src/nsSafeSaveFile.h index 4927b238e4c..3cfb01633e4 100644 --- a/mozilla/modules/libpref/src/nsSafeSaveFile.h +++ b/mozilla/modules/libpref/src/nsSafeSaveFile.h @@ -55,7 +55,6 @@ class nsSafeSaveFile { private: nsCOMPtr mTempFile; - nsCAutoString fileName; nsXPIDLCString mTargetFileName; PRInt32 mTargetNameLen; PRInt32 mBackupCount; diff --git a/mozilla/modules/libpref/src/prefapi.cpp b/mozilla/modules/libpref/src/prefapi.cpp index 371f5b39e9d..865304830b1 100644 --- a/mozilla/modules/libpref/src/prefapi.cpp +++ b/mozilla/modules/libpref/src/prefapi.cpp @@ -36,6 +36,8 @@ * ***** END LICENSE BLOCK ***** */ #include "prefapi.h" +#include "prefapi_private_data.h" +#include "nsReadableUtils.h" #include "jsapi.h" #include "xp_core.h" /* Needed for XP_ defines */ @@ -108,7 +110,6 @@ PR_STATIC_CALLBACK(JSBool) pref_NativeUserPref(JSContext *cx, JSObject *obj, uns PR_STATIC_CALLBACK(JSBool) pref_NativeSetConfig(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval); PR_STATIC_CALLBACK(JSBool) pref_NativeGetPref(JSContext *cx, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval); /*----------------------------------------------------------------------------------------*/ -#include "prefapi_private_data.h" JS_STATIC_DLL_CALLBACK(JSBool) global_enumerate(JSContext *cx, JSObject *obj) @@ -1382,7 +1383,7 @@ pref_ErrorReporter(JSContext *cx, const char *message, /* StandardAlert doesn't handle linefeeds. Use spaces to avoid garbage characters. */ last = PR_sprintf_append(last, " "); #else - last = PR_sprintf_append(last, LINEBREAK LINEBREAK); + last = PR_sprintf_append(last, NS_LINEBREAK NS_LINEBREAK); #endif if (!report) last = PR_sprintf_append(last, "%s\n", message); diff --git a/mozilla/modules/libpref/src/prefapi_private_data.h b/mozilla/modules/libpref/src/prefapi_private_data.h index a7a13e1d53b..4889e2f7e22 100644 --- a/mozilla/modules/libpref/src/prefapi_private_data.h +++ b/mozilla/modules/libpref/src/prefapi_private_data.h @@ -44,14 +44,3 @@ PLDHashOperator PR_CALLBACK pref_savePref(PLDHashTable*, PLDHashEntryHdr *, PRUi int PR_CALLBACK pref_CompareStrings(const void *v1, const void *v2, void* unused); extern JSBool pref_InitInitialObjects(void); - -#include "nsIFileSpec.h" - -#ifdef XP_MAC -# define LINEBREAK "\012" -#elif defined(XP_WIN) || defined(XP_OS2) -# define LINEBREAK "\015\012" -#elif defined(XP_UNIX) || defined(XP_BEOS) -# define LINEBREAK "\012" -#endif /* XP_MAC */ -