Bug 1869060 - Move old backupDatabaseFile utility out from mozIStorageService to a Places helper. r=mak,places-reviewers

This utility copies an SQLite database, but does so just by performing a file
copy on the database itself. It assumes that there are no open connections on
the underlying database file.

Given that this is only used by Places, and that a later patch in this stack
adds a database backup utility that works even if there are open connections,
means we can move this old utility out form the mozIStorageService and into
a dedicated Places helper instead.

Differential Revision: https://phabricator.services.mozilla.com/D198309
This commit is contained in:
Mike Conley 2024-01-22 14:26:52 +00:00
parent 935e67eb9f
commit f893e12aea
6 changed files with 53 additions and 101 deletions

View File

@ -281,27 +281,6 @@ interface mozIStorageService : nsISupports {
mozIStorageConnection openDatabaseWithFileURL(
in nsIFileURL aFileURL, [optional] in ACString aTelemetryFilename,
[optional] in unsigned long aConnectionFlags);
/*
* Utilities
*/
/**
* Copies the specified database file to the specified parent directory with
* the specified file name. If the parent directory is not specified, it
* places the backup in the same directory as the current file. This
* function ensures that the file being created is unique.
*
* @param aDBFile
* The database file that will be backed up.
* @param aBackupFileName
* The name of the new backup file to create.
* @param [optional] aBackupParentDirectory
* The directory you'd like the backup file to be placed.
* @return The nsIFile representing the backup file.
*/
nsIFile backupDatabaseFile(in nsIFile aDBFile, in AString aBackupFileName,
[optional] in nsIFile aBackupParentDirectory);
};
%{C++

View File

@ -685,40 +685,6 @@ Service::OpenDatabaseWithFileURL(nsIFileURL* aFileURL,
return NS_OK;
}
NS_IMETHODIMP
Service::BackupDatabaseFile(nsIFile* aDBFile, const nsAString& aBackupFileName,
nsIFile* aBackupParentDirectory, nsIFile** backup) {
nsresult rv;
nsCOMPtr<nsIFile> parentDir = aBackupParentDirectory;
if (!parentDir) {
// This argument is optional, and defaults to the same parent directory
// as the current file.
rv = aDBFile->GetParent(getter_AddRefs(parentDir));
NS_ENSURE_SUCCESS(rv, rv);
}
nsCOMPtr<nsIFile> backupDB;
rv = parentDir->Clone(getter_AddRefs(backupDB));
NS_ENSURE_SUCCESS(rv, rv);
rv = backupDB->Append(aBackupFileName);
NS_ENSURE_SUCCESS(rv, rv);
rv = backupDB->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString fileName;
rv = backupDB->GetLeafName(fileName);
NS_ENSURE_SUCCESS(rv, rv);
rv = backupDB->Remove(false);
NS_ENSURE_SUCCESS(rv, rv);
backupDB.forget(backup);
return aDBFile->CopyTo(parentDir, fileName);
}
////////////////////////////////////////////////////////////////////////////////
//// nsIObserver

View File

@ -6,8 +6,6 @@
// openSpecialDatabase, which is tested by test_storage_service_special.js and
// openUnsharedDatabase, which is tested by test_storage_service_unshared.js.
const BACKUP_FILE_NAME = "test_storage.sqlite.backup";
function test_openDatabase_null_file() {
try {
Services.storage.openDatabase(null);
@ -95,45 +93,6 @@ function test_fake_db_throws_with_openDatabase() {
);
}
function test_backup_not_new_filename() {
const fname = getTestDB().leafName;
var backup = Services.storage.backupDatabaseFile(getTestDB(), fname);
Assert.notEqual(fname, backup.leafName);
backup.remove(false);
}
function test_backup_new_filename() {
var backup = Services.storage.backupDatabaseFile(
getTestDB(),
BACKUP_FILE_NAME
);
Assert.equal(BACKUP_FILE_NAME, backup.leafName);
backup.remove(false);
}
function test_backup_new_folder() {
var parentDir = getTestDB().parent;
parentDir.append("test_storage_temp");
if (parentDir.exists()) {
parentDir.remove(true);
}
parentDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
Assert.ok(parentDir.exists());
var backup = Services.storage.backupDatabaseFile(
getTestDB(),
BACKUP_FILE_NAME,
parentDir
);
Assert.equal(BACKUP_FILE_NAME, backup.leafName);
Assert.ok(parentDir.equals(backup.parent));
parentDir.remove(true);
}
function test_openDatabase_directory() {
let dir = getTestDB().parent;
dir.append("test_storage_temp");
@ -286,9 +245,6 @@ var tests = [
test_openDatabase_file_exists,
test_corrupt_db_throws_with_openDatabase,
test_fake_db_throws_with_openDatabase,
test_backup_not_new_filename,
test_backup_new_filename,
test_backup_new_folder,
test_openDatabase_directory,
test_read_gooddb,
test_read_baddb,

View File

@ -797,8 +797,8 @@ nsresult Database::BackupAndReplaceDatabaseFile(
}
nsCOMPtr<nsIFile> backup;
Unused << aStorage->BackupDatabaseFile(databaseFile, corruptFilename,
profDir, getter_AddRefs(backup));
Unused << BackupDatabaseFile(databaseFile, corruptFilename, profDir,
getter_AddRefs(backup));
}
// If anything fails from this point on, we have a stale connection or

View File

@ -6,6 +6,7 @@
#include "Helpers.h"
#include "mozIStorageError.h"
#include "prio.h"
#include "nsIFile.h"
#include "nsReadableUtils.h"
#include "nsString.h"
#include "nsNavHistory.h"
@ -349,5 +350,33 @@ void TokensToQueryString(const nsTArray<QueryKeyValuePair>& aTokens,
});
}
nsresult BackupDatabaseFile(nsIFile* aDBFile, const nsAString& aBackupFileName,
nsIFile* aBackupParentDirectory, nsIFile** backup) {
nsresult rv;
nsCOMPtr<nsIFile> parentDir = aBackupParentDirectory;
if (!parentDir) {
// This argument is optional, and defaults to the same parent directory
// as the current file.
rv = aDBFile->GetParent(getter_AddRefs(parentDir));
NS_ENSURE_SUCCESS(rv, rv);
}
nsCOMPtr<nsIFile> backupDB;
rv = parentDir->Clone(getter_AddRefs(backupDB));
NS_ENSURE_SUCCESS(rv, rv);
rv = backupDB->Append(aBackupFileName);
NS_ENSURE_SUCCESS(rv, rv);
rv = backupDB->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString fileName;
rv = backupDB->GetLeafName(fileName);
NS_ENSURE_SUCCESS(rv, rv);
rv = backupDB->Remove(false);
NS_ENSURE_SUCCESS(rv, rv);
backupDB.forget(backup);
return aDBFile->CopyTo(parentDir, fileName);
}
} // namespace places
} // namespace mozilla

View File

@ -18,6 +18,8 @@
#include "mozilla/Telemetry.h"
#include "mozIStorageStatementCallback.h"
class nsIFile;
namespace mozilla {
namespace places {
@ -209,6 +211,26 @@ nsresult TokenizeQueryString(const nsACString& aQuery,
void TokensToQueryString(const nsTArray<QueryKeyValuePair>& aTokens,
nsACString& aQuery);
/**
* Copies the specified database file to the specified parent directory with
* the specified file name. If the parent directory is not specified, it
* places the backup in the same directory as the current file. This
* function ensures that the file being created is unique. This utility is meant
* to be used on database files with no open connections. Using this on database
* files with open connections may result in a corrupt backup file.
*
* @param aDBFile
* The database file that will be backed up.
* @param aBackupFileName
* The name of the new backup file to create.
* @param [optional] aBackupParentDirectory
* The directory you'd like the backup file to be placed.
* @param backup
* An outparam for the nsIFile pointing to the backup copy.
*/
nsresult BackupDatabaseFile(nsIFile* aDBFile, const nsAString& aBackupFileName,
nsIFile* aBackupParentDirectory, nsIFile** backup);
/**
* Used to finalize a statementCache on a specified thread.
*/