mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-12 04:45:45 +00:00
Bug 1339081 - Part 7: Implement safe metadata writting using temp files; r=asuth
This commit is contained in:
parent
f0b8133f92
commit
a2571e9f2b
@ -179,7 +179,9 @@ enum AppId {
|
||||
// origin.
|
||||
// XXX We should get rid of old metadata files at some point, bug 1343576.
|
||||
#define METADATA_FILE_NAME ".metadata"
|
||||
#define METADATA_TMP_FILE_NAME ".metadata-tmp"
|
||||
#define METADATA_V2_FILE_NAME ".metadata-v2"
|
||||
#define METADATA_V2_TMP_FILE_NAME ".metadata-v2-tmp"
|
||||
|
||||
/******************************************************************************
|
||||
* SQLite functions
|
||||
@ -1287,6 +1289,27 @@ AssertNoUnderflow(T aDest, U aArg)
|
||||
MOZ_ASSERT(uint64_t(aDest) >= uint64_t(aArg));
|
||||
}
|
||||
|
||||
bool
|
||||
IsOSMetadata(const nsAString& aFileName)
|
||||
{
|
||||
return aFileName.EqualsLiteral(DSSTORE_FILE_NAME);
|
||||
}
|
||||
|
||||
bool
|
||||
IsOriginMetadata(const nsAString& aFileName)
|
||||
{
|
||||
return aFileName.EqualsLiteral(METADATA_FILE_NAME) ||
|
||||
aFileName.EqualsLiteral(METADATA_V2_FILE_NAME) ||
|
||||
IsOSMetadata(aFileName);
|
||||
}
|
||||
|
||||
bool
|
||||
IsTempMetadata(const nsAString& aFileName)
|
||||
{
|
||||
return aFileName.EqualsLiteral(METADATA_TMP_FILE_NAME) ||
|
||||
aFileName.EqualsLiteral(METADATA_V2_TMP_FILE_NAME);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
BackgroundThreadObject::BackgroundThreadObject()
|
||||
@ -1688,9 +1711,8 @@ GetLastModifiedTime(nsIFile* aFile, int64_t* aTimestamp)
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (leafName.EqualsLiteral(METADATA_FILE_NAME) ||
|
||||
leafName.EqualsLiteral(METADATA_V2_FILE_NAME) ||
|
||||
leafName.EqualsLiteral(DSSTORE_FILE_NAME)) {
|
||||
if (IsOriginMetadata(leafName) ||
|
||||
IsTempMetadata(leafName)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1780,29 +1802,19 @@ enum FileFlag {
|
||||
};
|
||||
|
||||
nsresult
|
||||
GetOutputStream(nsIFile* aDirectory,
|
||||
const nsAString& aFilename,
|
||||
GetOutputStream(nsIFile* aFile,
|
||||
FileFlag aFileFlag,
|
||||
nsIOutputStream** aStream)
|
||||
{
|
||||
AssertIsOnIOThread();
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
nsresult rv = aDirectory->Clone(getter_AddRefs(file));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = file->Append(aFilename);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIOutputStream> outputStream;
|
||||
switch (aFileFlag) {
|
||||
case kTruncateFileFlag: {
|
||||
rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream),
|
||||
file);
|
||||
aFile);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
@ -1812,7 +1824,7 @@ GetOutputStream(nsIFile* aDirectory,
|
||||
|
||||
case kUpdateFileFlag: {
|
||||
bool exists;
|
||||
rv = file->Exists(&exists);
|
||||
rv = aFile->Exists(&exists);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
@ -1823,7 +1835,7 @@ GetOutputStream(nsIFile* aDirectory,
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFileStream> stream;
|
||||
rv = NS_NewLocalFileStream(getter_AddRefs(stream), file);
|
||||
rv = NS_NewLocalFileStream(getter_AddRefs(stream), aFile);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
@ -1838,7 +1850,7 @@ GetOutputStream(nsIFile* aDirectory,
|
||||
|
||||
case kAppendFileFlag: {
|
||||
rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream),
|
||||
file,
|
||||
aFile,
|
||||
PR_WRONLY | PR_CREATE_FILE | PR_APPEND);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
@ -1856,21 +1868,18 @@ GetOutputStream(nsIFile* aDirectory,
|
||||
}
|
||||
|
||||
nsresult
|
||||
GetBinaryOutputStream(nsIFile* aDirectory,
|
||||
const nsAString& aFilename,
|
||||
GetBinaryOutputStream(nsIFile* aFile,
|
||||
FileFlag aFileFlag,
|
||||
nsIBinaryOutputStream** aStream)
|
||||
{
|
||||
nsCOMPtr<nsIOutputStream> outputStream;
|
||||
nsresult rv = GetOutputStream(aDirectory,
|
||||
aFilename,
|
||||
nsresult rv = GetOutputStream(aFile,
|
||||
aFileFlag,
|
||||
getter_AddRefs(outputStream));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
nsCOMPtr<nsIBinaryOutputStream> binaryStream =
|
||||
do_CreateInstance("@mozilla.org/binaryoutputstream;1");
|
||||
if (NS_WARN_IF(!binaryStream)) {
|
||||
@ -1950,11 +1959,19 @@ CreateDirectoryMetadata(nsIFile* aDirectory, int64_t aTimestamp,
|
||||
|
||||
MOZ_ASSERT(groupPrefix == originPrefix);
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
nsresult rv = aDirectory->Clone(getter_AddRefs(file));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = file->Append(NS_LITERAL_STRING(METADATA_TMP_FILE_NAME));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIBinaryOutputStream> stream;
|
||||
nsresult rv = GetBinaryOutputStream(aDirectory,
|
||||
NS_LITERAL_STRING(METADATA_FILE_NAME),
|
||||
kTruncateFileFlag,
|
||||
getter_AddRefs(stream));
|
||||
rv = GetBinaryOutputStream(file, kTruncateFileFlag, getter_AddRefs(stream));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
@ -1982,21 +1999,47 @@ CreateDirectoryMetadata(nsIFile* aDirectory, int64_t aTimestamp,
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = stream->Flush();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = stream->Close();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = file->RenameTo(nullptr, NS_LITERAL_STRING(METADATA_FILE_NAME));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CreateDirectoryMetadata2(nsIFile* aDirectory, int64_t aTimestamp,
|
||||
const nsACString& aSuffix, const nsACString& aGroup,
|
||||
CreateDirectoryMetadata2(nsIFile* aDirectory,
|
||||
int64_t aTimestamp,
|
||||
const nsACString& aSuffix,
|
||||
const nsACString& aGroup,
|
||||
const nsACString& aOrigin)
|
||||
{
|
||||
AssertIsOnIOThread();
|
||||
MOZ_ASSERT(aDirectory);
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
nsresult rv = aDirectory->Clone(getter_AddRefs(file));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = file->Append(NS_LITERAL_STRING(METADATA_V2_TMP_FILE_NAME));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIBinaryOutputStream> stream;
|
||||
nsresult rv = GetBinaryOutputStream(aDirectory,
|
||||
NS_LITERAL_STRING(METADATA_V2_FILE_NAME),
|
||||
kTruncateFileFlag,
|
||||
getter_AddRefs(stream));
|
||||
rv = GetBinaryOutputStream(file, kTruncateFileFlag, getter_AddRefs(stream));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
@ -2047,6 +2090,21 @@ CreateDirectoryMetadata2(nsIFile* aDirectory, int64_t aTimestamp,
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = stream->Flush();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = stream->Close();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = file->RenameTo(nullptr, NS_LITERAL_STRING(METADATA_V2_FILE_NAME));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -3753,7 +3811,7 @@ QuotaManager::InitializeRepository(PersistenceType aPersistenceType)
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (leafName.EqualsLiteral(DSSTORE_FILE_NAME)) {
|
||||
if (IsOSMetadata(leafName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -3865,9 +3923,16 @@ QuotaManager::InitializeOrigin(PersistenceType aPersistenceType,
|
||||
}
|
||||
|
||||
if (!isDirectory) {
|
||||
if (leafName.EqualsLiteral(METADATA_FILE_NAME) ||
|
||||
leafName.EqualsLiteral(METADATA_V2_FILE_NAME) ||
|
||||
leafName.EqualsLiteral(DSSTORE_FILE_NAME)) {
|
||||
if (IsOriginMetadata(leafName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsTempMetadata(leafName)) {
|
||||
rv = file->Remove(/* recursive */ false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -5708,20 +5773,22 @@ SaveOriginAccessTimeOp::DoDirectoryWork(QuotaManager* aQuotaManager)
|
||||
PROFILER_LABEL("Quota", "SaveOriginAccessTimeOp::DoDirectoryWork",
|
||||
js::ProfileEntry::Category::OTHER);
|
||||
|
||||
nsCOMPtr<nsIFile> directory;
|
||||
nsCOMPtr<nsIFile> file;
|
||||
nsresult rv =
|
||||
aQuotaManager->GetDirectoryForOrigin(mPersistenceType.Value(),
|
||||
mOriginScope.GetOrigin(),
|
||||
getter_AddRefs(directory));
|
||||
getter_AddRefs(file));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = file->Append(NS_LITERAL_STRING(METADATA_V2_FILE_NAME));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIBinaryOutputStream> stream;
|
||||
rv = GetBinaryOutputStream(directory,
|
||||
NS_LITERAL_STRING(METADATA_V2_FILE_NAME),
|
||||
kUpdateFileFlag,
|
||||
getter_AddRefs(stream));
|
||||
rv = GetBinaryOutputStream(file, kUpdateFileFlag, getter_AddRefs(stream));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
@ -6075,9 +6142,18 @@ GetUsageOp::AddToUsage(QuotaManager* aQuotaManager,
|
||||
// not yet initialized or just continuing otherwise).
|
||||
// This can possibly be used by developers to add temporary backups into
|
||||
// origin directories without losing get usage functionality.
|
||||
if (leafName.EqualsLiteral(METADATA_FILE_NAME) ||
|
||||
leafName.EqualsLiteral(METADATA_V2_FILE_NAME) ||
|
||||
leafName.EqualsLiteral(DSSTORE_FILE_NAME)) {
|
||||
if (IsOriginMetadata(leafName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsTempMetadata(leafName)) {
|
||||
if (!initialized) {
|
||||
rv = file->Remove(/* recursive */ false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -6526,7 +6602,7 @@ ClearRequestBase::DeleteFiles(QuotaManager* aQuotaManager,
|
||||
|
||||
if (!isDirectory) {
|
||||
// Unknown files during clearing are allowed. Just warn if we find them.
|
||||
if (!leafName.EqualsLiteral(DSSTORE_FILE_NAME)) {
|
||||
if (!IsOSMetadata(leafName)) {
|
||||
UNKNOWN_FILE_WARNING(leafName);
|
||||
}
|
||||
continue;
|
||||
@ -7305,7 +7381,7 @@ CreateOrUpgradeDirectoryMetadataHelper::CreateOrUpgradeMetadataFiles()
|
||||
}
|
||||
} else {
|
||||
// Unknown files during upgrade are allowed. Just warn if we find them.
|
||||
if (!leafName.EqualsLiteral(DSSTORE_FILE_NAME)) {
|
||||
if (!IsOSMetadata(leafName)) {
|
||||
UNKNOWN_FILE_WARNING(leafName);
|
||||
}
|
||||
continue;
|
||||
@ -7619,11 +7695,19 @@ CreateOrUpgradeDirectoryMetadataHelper::DoProcessOriginDirectories()
|
||||
return rv;
|
||||
}
|
||||
} else if (!originProps.mIgnore) {
|
||||
nsCOMPtr<nsIFile> file;
|
||||
rv = originProps.mDirectory->Clone(getter_AddRefs(file));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = file->Append(NS_LITERAL_STRING(METADATA_FILE_NAME));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIBinaryOutputStream> stream;
|
||||
rv = GetBinaryOutputStream(originProps.mDirectory,
|
||||
NS_LITERAL_STRING(METADATA_FILE_NAME),
|
||||
kAppendFileFlag,
|
||||
getter_AddRefs(stream));
|
||||
rv = GetBinaryOutputStream(file, kAppendFileFlag, getter_AddRefs(stream));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
@ -7687,7 +7771,7 @@ UpgradeDirectoryMetadataFrom1To2Helper::UpgradeMetadataFiles()
|
||||
}
|
||||
|
||||
// Unknown files during upgrade are allowed. Just warn if we find them.
|
||||
if (!leafName.EqualsLiteral(DSSTORE_FILE_NAME)) {
|
||||
if (!IsOSMetadata(leafName)) {
|
||||
UNKNOWN_FILE_WARNING(leafName);
|
||||
}
|
||||
continue;
|
||||
|
BIN
dom/quota/test/unit/tempMetadataCleanup_profile.zip
Normal file
BIN
dom/quota/test/unit/tempMetadataCleanup_profile.zip
Normal file
Binary file not shown.
@ -8,8 +8,28 @@ var testGenerator = testSteps();
|
||||
function* testSteps()
|
||||
{
|
||||
const storageFile = "storage.sqlite";
|
||||
const metadataFile = "storage/permanent/chrome/.metadata";
|
||||
const metadata2File = "storage/permanent/chrome/.metadata-v2";
|
||||
|
||||
const metadataFiles = [
|
||||
{
|
||||
path: "storage/permanent/chrome/.metadata",
|
||||
tmp: false
|
||||
},
|
||||
|
||||
{
|
||||
path: "storage/permanent/chrome/.metadata-tmp",
|
||||
tmp: true
|
||||
},
|
||||
|
||||
{
|
||||
path: "storage/permanent/chrome/.metadata-v2",
|
||||
tmp: false
|
||||
},
|
||||
|
||||
{
|
||||
path: "storage/permanent/chrome/.metadata-v2-tmp",
|
||||
tmp: true
|
||||
}
|
||||
]
|
||||
|
||||
info("Clearing");
|
||||
|
||||
@ -69,15 +89,17 @@ function* testSteps()
|
||||
|
||||
ok(request.result, "Origin directory was created");
|
||||
|
||||
file = getRelativeFile(metadataFile);
|
||||
for (let metadataFile of metadataFiles) {
|
||||
file = getRelativeFile(metadataFile.path);
|
||||
|
||||
exists = file.exists();
|
||||
ok(exists, "Metadata file does exist");
|
||||
exists = file.exists();
|
||||
|
||||
file = getRelativeFile(metadata2File);
|
||||
|
||||
exists = file.exists();
|
||||
ok(exists, "Metadata v2 file does exist");
|
||||
if (metadataFile.tmp) {
|
||||
ok(!exists, "Metadata file doesn't exist");
|
||||
} else {
|
||||
ok(exists, "Metadata file does exist");
|
||||
}
|
||||
}
|
||||
|
||||
finishTest();
|
||||
}
|
||||
|
43
dom/quota/test/unit/test_tempMetadataCleanup.js
Normal file
43
dom/quota/test/unit/test_tempMetadataCleanup.js
Normal file
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
var testGenerator = testSteps();
|
||||
|
||||
function* testSteps()
|
||||
{
|
||||
const tempMetadataFiles = [
|
||||
"storage/permanent/chrome/.metadata-tmp",
|
||||
"storage/permanent/chrome/.metadata-v2-tmp",
|
||||
];
|
||||
|
||||
info("Clearing");
|
||||
|
||||
clear(continueToNextStepSync);
|
||||
yield undefined;
|
||||
|
||||
info("Installing package");
|
||||
|
||||
installPackage("tempMetadataCleanup_profile");
|
||||
|
||||
info("Initializing origin");
|
||||
|
||||
let request = initChromeOrigin("persistent", continueToNextStepSync);
|
||||
yield undefined;
|
||||
|
||||
ok(request.resultCode == NS_OK, "Initialization succeeded");
|
||||
|
||||
ok(!request.result, "Origin directory wasn't created");
|
||||
|
||||
for (let tempMetadataFile of tempMetadataFiles) {
|
||||
info("Checking temp metadata file");
|
||||
|
||||
let file = getRelativeFile(tempMetadataFile);
|
||||
|
||||
let exists = file.exists();
|
||||
ok(!exists, "Temp metadata file doesn't exist");
|
||||
}
|
||||
|
||||
finishTest();
|
||||
}
|
@ -6,6 +6,8 @@
|
||||
head = head.js
|
||||
support-files =
|
||||
basics_profile.zip
|
||||
tempMetadataCleanup_profile.zip
|
||||
|
||||
[test_basics.js]
|
||||
[test_tempMetadataCleanup.js]
|
||||
[test_unknownFiles.js]
|
||||
|
Loading…
Reference in New Issue
Block a user