Bug 1056939 - indexedDB.open fails for certain database names - part 2; r=bent

This commit is contained in:
Jan Varga 2014-10-13 21:12:25 +02:00
parent 2276516709
commit eb5e098231
7 changed files with 196 additions and 49 deletions

View File

@ -9156,18 +9156,18 @@ QuotaClient::GetType()
return QuotaClient::IDB;
}
struct FileManagerInitInfo
{
nsCOMPtr<nsIFile> mDirectory;
nsCOMPtr<nsIFile> mDatabaseFile;
};
nsresult
QuotaClient::InitOrigin(PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin,
UsageInfo* aUsageInfo)
{
struct FileManagerInitInfo
{
nsCOMPtr<nsIFile> mDirectory;
nsCOMPtr<nsIFile> mDatabaseFile;
};
AssertIsOnIOThread();
nsCOMPtr<nsIFile> directory;
@ -9213,13 +9213,6 @@ QuotaClient::InitOrigin(PersistenceType aPersistenceType,
return rv;
}
if (StringEndsWith(leafName, NS_LITERAL_STRING(".sqlite-journal"))) {
continue;
}
if (leafName.EqualsLiteral(DSSTORE_FILE_NAME)) {
continue;
}
bool isDirectory;
rv = file->IsDirectory(&isDirectory);
@ -9235,6 +9228,15 @@ QuotaClient::InitOrigin(PersistenceType aPersistenceType,
continue;
}
// Skip SQLite and Desktop Service Store (.DS_Store) files.
// Desktop Service Store file is only used on Mac OS X, but the profile
// can be shared across different operating systems, so we check it on
// all platforms.
if (StringEndsWith(leafName, NS_LITERAL_STRING(".sqlite-journal")) ||
leafName.EqualsLiteral(DSSTORE_FILE_NAME)) {
continue;
}
nsDependentSubstring dbBaseFilename;
if (!GetDatabaseBaseFilename(leafName, dbBaseFilename)) {
unknownFiles.AppendElement(file);
@ -9282,16 +9284,14 @@ QuotaClient::InitOrigin(PersistenceType aPersistenceType,
// it. Check to see if we have a database that references this directory.
nsString subdirNameWithSuffix = subdirName + filesSuffix;
if (!validSubdirs.GetEntry(subdirNameWithSuffix)) {
#ifdef XP_WIN
// Windows doesn't allow a directory to end with a dot ('.'), so we have
// to check that possibility here too.
// We do this on all platforms, because the origin directory may have
// been created on Windows and now accessed on different OS.
subdirNameWithSuffix = subdirName + NS_LITERAL_STRING(".") + filesSuffix;
if (NS_WARN_IF(!validSubdirs.GetEntry(subdirNameWithSuffix))) {
return NS_ERROR_UNEXPECTED;
}
#else
return NS_ERROR_UNEXPECTED;
#endif
}
// We do have a database that uses this directory so we should rename it
@ -9339,29 +9339,6 @@ QuotaClient::InitOrigin(PersistenceType aPersistenceType,
}
}
for (uint32_t count = unknownFiles.Length(), i = 0; i < count; i++) {
nsCOMPtr<nsIFile>& unknownFile = unknownFiles[i];
// Some temporary SQLite files could disappear, so we have to check if the
// unknown file still exists.
bool exists;
rv = unknownFile->Exists(&exists);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (exists) {
nsString leafName;
unknownFile->GetLeafName(leafName);
// The journal file may exists even after db has been correctly opened.
if (NS_WARN_IF(!StringEndsWith(leafName,
NS_LITERAL_STRING(".sqlite-journal")))) {
return NS_ERROR_UNEXPECTED;
}
}
}
for (uint32_t count = initInfos.Length(), i = 0; i < count; i++) {
FileManagerInitInfo& initInfo = initInfos[i];
MOZ_ASSERT(initInfo.mDirectory);
@ -9397,6 +9374,23 @@ QuotaClient::InitOrigin(PersistenceType aPersistenceType,
}
}
// We have to do this after file manager initialization.
for (uint32_t count = unknownFiles.Length(), i = 0; i < count; i++) {
nsCOMPtr<nsIFile>& unknownFile = unknownFiles[i];
// Some temporary SQLite files could disappear during file manager
// initialization, so we have to check if the unknown file still exists.
bool exists;
rv = unknownFile->Exists(&exists);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (exists) {
return NS_ERROR_UNEXPECTED;
}
}
return NS_OK;
}

Binary file not shown.

View File

@ -0,0 +1,131 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
var testGenerator = testSteps();
function testSteps()
{
const dbName1 = "upgrade_test";
const dbName2 = "testing.foobar";
const dbName3 = "xxxxxxx.xxxxxx";
clearAllDatabases(continueToNextStepSync);
yield undefined;
installPackagedProfile("bug1056939");
let request = indexedDB.open(dbName1, 1);
request.onerror = errorHandler;
request.onupgradeneeded = unexpectedSuccessHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield undefined;
is(event.type, "success", "Correct event type");
request = indexedDB.open(dbName2, 1);
request.onerror = errorHandler;
request.onupgradeneeded = unexpectedSuccessHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield undefined;
is(event.type, "success", "Got correct event type");
request = indexedDB.open(dbName3, 1);
request.onerror = errorHandler;
request.onupgradeneeded = unexpectedSuccessHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield undefined;
is(event.type, "success", "Got correct event type");
clearAllDatabases(continueToNextStepSync);
yield undefined;
request = indexedDB.open(dbName3, 1);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = unexpectedSuccessHandler;
event = yield undefined;
is(event.type, "upgradeneeded", "Got correct event type");
request.onupgradeneeded = unexpectedSuccessHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield undefined;
is(event.type, "success", "Got correct event type");
resetAllDatabases(continueToNextStepSync);
yield undefined;
request = indexedDB.open(dbName3, 1);
request.onerror = errorHandler;
request.onupgradeneeded = unexpectedSuccessHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield undefined;
is(event.type, "success", "Got correct event type");
finishTest();
yield undefined;
}
function installPackagedProfile(packageName)
{
let directoryService = Cc["@mozilla.org/file/directory_service;1"]
.getService(Ci.nsIProperties);
let profileDir = directoryService.get("ProfD", Ci.nsIFile);
let currentDir = directoryService.get("CurWorkD", Ci.nsIFile);
let packageFile = currentDir.clone();
packageFile.append(packageName + ".zip");
let zipReader = Cc["@mozilla.org/libjar/zip-reader;1"]
.createInstance(Ci.nsIZipReader);
zipReader.open(packageFile);
let entryNames = [];
let entries = zipReader.findEntries(null);
while (entries.hasMore()) {
let entry = entries.getNext();
if (entry != "create_db.html") {
entryNames.push(entry);
}
}
entryNames.sort();
for (let entryName of entryNames) {
let zipentry = zipReader.getEntry(entryName);
let file = profileDir.clone();
let split = entryName.split("/");
for(let i = 0; i < split.length; i++) {
file.append(split[i]);
}
if (zipentry.isDirectory) {
file.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt("0755", 8));
} else {
let istream = zipReader.getInputStream(entryName);
var ostream = Cc["@mozilla.org/network/file-output-stream;1"]
.createInstance(Ci.nsIFileOutputStream);
ostream.init(file, -1, parseInt("0644", 8), 0);
let bostream = Cc['@mozilla.org/network/buffered-output-stream;1']
.createInstance(Ci.nsIBufferedOutputStream);
bostream.init(ostream, 32768);
bostream.writeFrom(istream, istream.available());
istream.close();
bostream.close();
}
}
zipReader.close();
}

View File

@ -230,7 +230,7 @@ function setTimeout(fun, timeout) {
return timer;
}
function clearAllDatabases(callback) {
function resetOrClearAllDatabases(callback, clear) {
if (!SpecialPowers.isMainProcess()) {
throw new Error("clearAllDatabases not implemented for child processes!");
}
@ -248,7 +248,11 @@ function clearAllDatabases(callback) {
SpecialPowers.setBoolPref(quotaPref, true);
try {
quotaManager.clear();
if (clear) {
quotaManager.clear();
} else {
quotaManager.reset();
}
} catch(e) {
if (oldPrefValue !== undefined) {
SpecialPowers.setBoolPref(quotaPref, oldPrefValue);
@ -266,6 +270,14 @@ function clearAllDatabases(callback) {
});
}
function resetAllDatabases(callback) {
resetOrClearAllDatabases(callback, false);
}
function clearAllDatabases(callback) {
resetOrClearAllDatabases(callback, true);
}
var SpecialPowers = {
isMainProcess: function() {
return Components.classes["@mozilla.org/xre/app-info;1"]

View File

@ -8,6 +8,7 @@ head = xpcshell-head-parent-process.js
tail =
skip-if = toolkit == 'android' || toolkit == 'gonk'
support-files =
bug1056939.zip
GlobalObjectsChild.js
GlobalObjectsComponent.js
GlobalObjectsComponent.manifest
@ -17,6 +18,7 @@ support-files =
[include:xpcshell-shared.ini]
[test_bug1056939.js]
[test_globalObjects_ipc.js]
[test_invalidate.js]
# disabled for the moment.

View File

@ -382,8 +382,7 @@ public:
void* aClosure);
void
DeleteFiles(QuotaManager* aQuotaManager,
PersistenceType aPersistenceType);
DeleteFiles(QuotaManager* aQuotaManager);
private:
~ResetOrClearRunnable() {}
@ -993,6 +992,9 @@ QuotaManager::Init()
rv = baseDir->Append(NS_LITERAL_STRING("storage"));
NS_ENSURE_SUCCESS(rv, rv);
rv = baseDir->GetPath(mStoragePath);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIFile> persistentStorageDir;
rv = baseDir->Clone(getter_AddRefs(persistentStorageDir));
NS_ENSURE_SUCCESS(rv, rv);
@ -1977,6 +1979,7 @@ QuotaManager::ResetOrClearCompleted()
mInitializedOrigins.Clear();
mTemporaryStorageInitialized = false;
mStorageAreaInitialized = false;
ReleaseIOThreadObjects();
}
@ -3928,8 +3931,7 @@ ResetOrClearRunnable::InvalidateOpenedStorages(
}
void
ResetOrClearRunnable::DeleteFiles(QuotaManager* aQuotaManager,
PersistenceType aPersistenceType)
ResetOrClearRunnable::DeleteFiles(QuotaManager* aQuotaManager)
{
AssertIsOnIOThread();
NS_ASSERTION(aQuotaManager, "Don't pass me null!");
@ -3940,7 +3942,7 @@ ResetOrClearRunnable::DeleteFiles(QuotaManager* aQuotaManager,
do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS_VOID(rv);
rv = directory->InitWithPath(aQuotaManager->GetStoragePath(aPersistenceType));
rv = directory->InitWithPath(aQuotaManager->GetStoragePath());
NS_ENSURE_SUCCESS_VOID(rv);
rv = directory->Remove(true);
@ -3988,8 +3990,7 @@ ResetOrClearRunnable::Run()
AdvanceState();
if (mClear) {
DeleteFiles(quotaManager, PERSISTENCE_TYPE_PERSISTENT);
DeleteFiles(quotaManager, PERSISTENCE_TYPE_TEMPORARY);
DeleteFiles(quotaManager);
}
quotaManager->RemoveQuota();

View File

@ -279,6 +279,12 @@ public:
already_AddRefed<Client>
GetClient(Client::Type aClientType);
const nsString&
GetStoragePath() const
{
return mStoragePath;
}
const nsString&
GetStoragePath(PersistenceType aPersistenceType) const
{
@ -520,6 +526,7 @@ private:
nsAutoTArray<nsRefPtr<Client>, Client::TYPE_MAX> mClients;
nsString mIndexedDBPath;
nsString mStoragePath;
nsString mPersistentStoragePath;
nsString mTemporaryStoragePath;