mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 787804 - Rewrite quota handling (eliminate test_quota.c). r=bent,asuth,vladan
This commit is contained in:
parent
5eddaa4414
commit
812af47d24
@ -9,8 +9,8 @@ Makefile.in there) that we use to build.
|
||||
|
||||
To move to a new version:
|
||||
|
||||
Copy the sqlite3.h and sqlite3.c files from the amalgamation of sqlite. Also,
|
||||
copy test_quota.h and test_quota.c from the full source package.
|
||||
Copy the sqlite3.h and sqlite3.c files from the amalgamation of sqlite.
|
||||
(We no longer use test_quota.h and test_quota.c)
|
||||
|
||||
Be sure to update SQLITE_VERSION accordingly in $(topsrcdir)/configure.in as
|
||||
well as the version number at the top of this file.
|
||||
|
@ -132,6 +132,7 @@ EXPORTS
|
||||
sqlite3_transfer_bindings
|
||||
sqlite3_unlock_notify
|
||||
sqlite3_update_hook
|
||||
sqlite3_uri_parameter
|
||||
sqlite3_user_data
|
||||
sqlite3_value_blob
|
||||
sqlite3_value_bytes
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,274 +0,0 @@
|
||||
/*
|
||||
** 2011 December 1
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** This file contains the interface definition for the quota a VFS shim.
|
||||
**
|
||||
** This particular shim enforces a quota system on files. One or more
|
||||
** database files are in a "quota group" that is defined by a GLOB
|
||||
** pattern. A quota is set for the combined size of all files in the
|
||||
** the group. A quota of zero means "no limit". If the total size
|
||||
** of all files in the quota group is greater than the limit, then
|
||||
** write requests that attempt to enlarge a file fail with SQLITE_FULL.
|
||||
**
|
||||
** However, before returning SQLITE_FULL, the write requests invoke
|
||||
** a callback function that is configurable for each quota group.
|
||||
** This callback has the opportunity to enlarge the quota. If the
|
||||
** callback does enlarge the quota such that the total size of all
|
||||
** files within the group is less than the new quota, then the write
|
||||
** continues as if nothing had happened.
|
||||
*/
|
||||
#ifndef _QUOTA_H_
|
||||
#include "sqlite3.h"
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#if SQLITE_OS_UNIX
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#if SQLITE_OS_WIN
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
/* Make this callable from C++ */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Initialize the quota VFS shim. Use the VFS named zOrigVfsName
|
||||
** as the VFS that does the actual work. Use the default if
|
||||
** zOrigVfsName==NULL.
|
||||
**
|
||||
** The quota VFS shim is named "quota". It will become the default
|
||||
** VFS if makeDefault is non-zero.
|
||||
**
|
||||
** THIS ROUTINE IS NOT THREADSAFE. Call this routine exactly once
|
||||
** during start-up.
|
||||
*/
|
||||
int sqlite3_quota_initialize(const char *zOrigVfsName, int makeDefault);
|
||||
|
||||
/*
|
||||
** Shutdown the quota system.
|
||||
**
|
||||
** All SQLite database connections must be closed before calling this
|
||||
** routine.
|
||||
**
|
||||
** THIS ROUTINE IS NOT THREADSAFE. Call this routine exactly once while
|
||||
** shutting down in order to free all remaining quota groups.
|
||||
*/
|
||||
int sqlite3_quota_shutdown(void);
|
||||
|
||||
/*
|
||||
** Create or destroy a quota group.
|
||||
**
|
||||
** The quota group is defined by the zPattern. When calling this routine
|
||||
** with a zPattern for a quota group that already exists, this routine
|
||||
** merely updates the iLimit, xCallback, and pArg values for that quota
|
||||
** group. If zPattern is new, then a new quota group is created.
|
||||
**
|
||||
** The zPattern is always compared against the full pathname of the file.
|
||||
** Even if APIs are called with relative pathnames, SQLite converts the
|
||||
** name to a full pathname before comparing it against zPattern. zPattern
|
||||
** is a glob pattern with the following matching rules:
|
||||
**
|
||||
** '*' Matches any sequence of zero or more characters.
|
||||
**
|
||||
** '?' Matches exactly one character.
|
||||
**
|
||||
** [...] Matches one character from the enclosed list of
|
||||
** characters. "]" can be part of the list if it is
|
||||
** the first character. Within the list "X-Y" matches
|
||||
** characters X or Y or any character in between the
|
||||
** two. Ex: "[0-9]" matches any digit.
|
||||
**
|
||||
** [^...] Matches one character not in the enclosed list.
|
||||
**
|
||||
** / Matches either / or \. This allows glob patterns
|
||||
** containing / to work on both unix and windows.
|
||||
**
|
||||
** Note that, unlike unix shell globbing, the directory separator "/"
|
||||
** can match a wildcard. So, for example, the pattern "/abc/xyz/" "*"
|
||||
** matches any files anywhere in the directory hierarchy beneath
|
||||
** /abc/xyz.
|
||||
**
|
||||
** The glob algorithm works on bytes. Multi-byte UTF8 characters are
|
||||
** matched as if each byte were a separate character.
|
||||
**
|
||||
** If the iLimit for a quota group is set to zero, then the quota group
|
||||
** is disabled and will be deleted when the last database connection using
|
||||
** the quota group is closed.
|
||||
**
|
||||
** Calling this routine on a zPattern that does not exist and with a
|
||||
** zero iLimit is a no-op.
|
||||
**
|
||||
** A quota group must exist with a non-zero iLimit prior to opening
|
||||
** database connections if those connections are to participate in the
|
||||
** quota group. Creating a quota group does not affect database connections
|
||||
** that are already open.
|
||||
**
|
||||
** The patterns that define the various quota groups should be distinct.
|
||||
** If the same filename matches more than one quota group pattern, then
|
||||
** the behavior of this package is undefined.
|
||||
*/
|
||||
int sqlite3_quota_set(
|
||||
const char *zPattern, /* The filename pattern */
|
||||
sqlite3_int64 iLimit, /* New quota to set for this quota group */
|
||||
void (*xCallback)( /* Callback invoked when going over quota */
|
||||
const char *zFilename, /* Name of file whose size increases */
|
||||
sqlite3_int64 *piLimit, /* IN/OUT: The current limit */
|
||||
sqlite3_int64 iSize, /* Total size of all files in the group */
|
||||
void *pArg /* Client data */
|
||||
),
|
||||
void *pArg, /* client data passed thru to callback */
|
||||
void (*xDestroy)(void*) /* Optional destructor for pArg */
|
||||
);
|
||||
|
||||
/*
|
||||
** Bring the named file under quota management, assuming its name matches
|
||||
** the glob pattern of some quota group. Or if it is already under
|
||||
** management, update its size. If zFilename does not match the glob
|
||||
** pattern of any quota group, this routine is a no-op.
|
||||
*/
|
||||
int sqlite3_quota_file(const char *zFilename);
|
||||
|
||||
/*
|
||||
** The following object serves the same role as FILE in the standard C
|
||||
** library. It represents an open connection to a file on disk for I/O.
|
||||
**
|
||||
** A single quota_FILE should not be used by two or more threads at the
|
||||
** same time. Multiple threads can be using different quota_FILE objects
|
||||
** simultaneously, but not the same quota_FILE object.
|
||||
*/
|
||||
typedef struct quota_FILE quota_FILE;
|
||||
|
||||
/*
|
||||
** Create a new quota_FILE object used to read and/or write to the
|
||||
** file zFilename. The zMode parameter is as with standard library zMode.
|
||||
*/
|
||||
quota_FILE *sqlite3_quota_fopen(const char *zFilename, const char *zMode);
|
||||
|
||||
/*
|
||||
** Perform I/O against a quota_FILE object. When doing writes, the
|
||||
** quota mechanism may result in a short write, in order to prevent
|
||||
** the sum of sizes of all files from going over quota.
|
||||
*/
|
||||
size_t sqlite3_quota_fread(void*, size_t, size_t, quota_FILE*);
|
||||
size_t sqlite3_quota_fwrite(const void*, size_t, size_t, quota_FILE*);
|
||||
|
||||
/*
|
||||
** Flush all written content held in memory buffers out to disk.
|
||||
** This is the equivalent of fflush() in the standard library.
|
||||
**
|
||||
** If the hardSync parameter is true (non-zero) then this routine
|
||||
** also forces OS buffers to disk - the equivalent of fsync().
|
||||
**
|
||||
** This routine return zero on success and non-zero if something goes
|
||||
** wrong.
|
||||
*/
|
||||
int sqlite3_quota_fflush(quota_FILE*, int hardSync);
|
||||
|
||||
/*
|
||||
** Close a quota_FILE object and free all associated resources. The
|
||||
** file remains under quota management.
|
||||
*/
|
||||
int sqlite3_quota_fclose(quota_FILE*);
|
||||
|
||||
/*
|
||||
** Move the read/write pointer for a quota_FILE object. Or tell the
|
||||
** current location of the read/write pointer.
|
||||
*/
|
||||
int sqlite3_quota_fseek(quota_FILE*, long, int);
|
||||
void sqlite3_quota_rewind(quota_FILE*);
|
||||
long sqlite3_quota_ftell(quota_FILE*);
|
||||
|
||||
/*
|
||||
** Test the error indicator for the given file.
|
||||
**
|
||||
** Return non-zero if the error indicator is set.
|
||||
*/
|
||||
int sqlite3_quota_ferror(quota_FILE*);
|
||||
|
||||
/*
|
||||
** Truncate a file previously opened by sqlite3_quota_fopen(). Return
|
||||
** zero on success and non-zero on any kind of failure.
|
||||
**
|
||||
** The newSize argument must be less than or equal to the current file size.
|
||||
** Any attempt to "truncate" a file to a larger size results in
|
||||
** undefined behavior.
|
||||
*/
|
||||
int sqlite3_quota_ftruncate(quota_FILE*, sqlite3_int64 newSize);
|
||||
|
||||
/*
|
||||
** Return the last modification time of the opened file, in seconds
|
||||
** since 1970.
|
||||
*/
|
||||
int sqlite3_quota_file_mtime(quota_FILE*, time_t *pTime);
|
||||
|
||||
/*
|
||||
** Return the size of the file as it is known to the quota system.
|
||||
**
|
||||
** This size might be different from the true size of the file on
|
||||
** disk if some outside process has modified the file without using the
|
||||
** quota mechanism, or if calls to sqlite3_quota_fwrite() have occurred
|
||||
** which have increased the file size, but those writes have not yet been
|
||||
** forced to disk using sqlite3_quota_fflush().
|
||||
**
|
||||
** Return -1 if the file is not participating in quota management.
|
||||
*/
|
||||
sqlite3_int64 sqlite3_quota_file_size(quota_FILE*);
|
||||
|
||||
/*
|
||||
** Return the true size of the file.
|
||||
**
|
||||
** The true size should be the same as the size of the file as known
|
||||
** to the quota system, however the sizes might be different if the
|
||||
** file has been extended or truncated via some outside process or if
|
||||
** pending writes have not yet been flushed to disk.
|
||||
**
|
||||
** Return -1 if the file does not exist or if the size of the file
|
||||
** cannot be determined for some reason.
|
||||
*/
|
||||
sqlite3_int64 sqlite3_quota_file_truesize(quota_FILE*);
|
||||
|
||||
/*
|
||||
** Determine the amount of data in bytes available for reading
|
||||
** in the given file.
|
||||
**
|
||||
** Return -1 if the amount cannot be determined for some reason.
|
||||
*/
|
||||
long sqlite3_quota_file_available(quota_FILE*);
|
||||
|
||||
/*
|
||||
** Delete a file from the disk, if that file is under quota management.
|
||||
** Adjust quotas accordingly.
|
||||
**
|
||||
** If zFilename is the name of a directory that matches one of the
|
||||
** quota glob patterns, then all files under quota management that
|
||||
** are contained within that directory are deleted.
|
||||
**
|
||||
** A standard SQLite result code is returned (SQLITE_OK, SQLITE_NOMEM, etc.)
|
||||
** When deleting a directory of files, if the deletion of any one
|
||||
** file fails (for example due to an I/O error), then this routine
|
||||
** returns immediately, with the error code, and does not try to
|
||||
** delete any of the other files in the specified directory.
|
||||
**
|
||||
** All files are removed from quota management and deleted from disk.
|
||||
** However, no attempt is made to remove empty directories.
|
||||
**
|
||||
** This routine is a no-op for files that are not under quota management.
|
||||
*/
|
||||
int sqlite3_quota_remove(const char *zFilename);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of the 'extern "C"' block */
|
||||
#endif
|
||||
#endif /* _QUOTA_H_ */
|
@ -58,6 +58,7 @@ PARALLEL_DIRS += \
|
||||
media \
|
||||
messages \
|
||||
power \
|
||||
quota \
|
||||
settings \
|
||||
sms \
|
||||
mms \
|
||||
|
@ -8,6 +8,7 @@ DOM_SRCDIRS = \
|
||||
dom/encoding \
|
||||
dom/file \
|
||||
dom/power \
|
||||
dom/quota \
|
||||
dom/media \
|
||||
dom/network/src \
|
||||
dom/settings \
|
||||
|
@ -8,7 +8,6 @@
|
||||
|
||||
#include "nsIFileStorage.h"
|
||||
#include "nsISeekableStream.h"
|
||||
#include "nsIStandardFileStream.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#include "FileHelper.h"
|
||||
@ -246,16 +245,6 @@ FileOutputStreamWrapper::Close()
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (!mFirstTime) {
|
||||
// We must flush buffers of the stream on the same thread on which we wrote
|
||||
// some data.
|
||||
nsCOMPtr<nsIStandardFileStream> sstream = do_QueryInterface(mFileStream);
|
||||
if (sstream) {
|
||||
rv = sstream->FlushBuffers();
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to flush buffers of the stream!");
|
||||
}
|
||||
}
|
||||
|
||||
NS_ASSERTION(PR_GetCurrentThread() == mWriteThread,
|
||||
"Unsetting thread locals on wrong thread!");
|
||||
mFileHelper->mFileStorage->UnsetThreadLocals();
|
||||
|
@ -953,10 +953,10 @@ FinishHelper::Run()
|
||||
}
|
||||
|
||||
for (uint32_t index = 0; index < mParallelStreams.Length(); index++) {
|
||||
nsCOMPtr<nsIOutputStream> ostream =
|
||||
nsCOMPtr<nsIInputStream> stream =
|
||||
do_QueryInterface(mParallelStreams[index]);
|
||||
|
||||
if (NS_FAILED(ostream->Close())) {
|
||||
if (NS_FAILED(stream->Close())) {
|
||||
NS_WARNING("Failed to close stream!");
|
||||
}
|
||||
|
||||
@ -964,9 +964,9 @@ FinishHelper::Run()
|
||||
}
|
||||
|
||||
if (mStream) {
|
||||
nsCOMPtr<nsIOutputStream> ostream = do_QueryInterface(mStream);
|
||||
nsCOMPtr<nsIInputStream> stream = do_QueryInterface(mStream);
|
||||
|
||||
if (NS_FAILED(ostream->Close())) {
|
||||
if (NS_FAILED(stream->Close())) {
|
||||
NS_WARNING("Failed to close stream!");
|
||||
}
|
||||
|
||||
|
@ -10,14 +10,17 @@
|
||||
#include "nsISupports.h"
|
||||
|
||||
#define NS_FILESTORAGE_IID \
|
||||
{0xbba9c2ff, 0x85c9, 0x47c1, \
|
||||
{ 0xaf, 0xce, 0x0a, 0x7e, 0x6f, 0x21, 0x50, 0x95 } }
|
||||
{0xa0801944, 0x2f1c, 0x4203, \
|
||||
{ 0x9c, 0xaa, 0xaa, 0x47, 0xe0, 0x0c, 0x67, 0x92 } }
|
||||
|
||||
class nsIFileStorage : public nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_FILESTORAGE_IID)
|
||||
|
||||
virtual const nsACString&
|
||||
StorageOrigin() = 0;
|
||||
|
||||
virtual nsISupports*
|
||||
StorageId() = 0;
|
||||
|
||||
@ -36,20 +39,23 @@ public:
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIFileStorage, NS_FILESTORAGE_IID)
|
||||
|
||||
#define NS_DECL_NSIFILESTORAGE \
|
||||
virtual nsISupports* \
|
||||
StorageId(); \
|
||||
\
|
||||
virtual bool \
|
||||
IsStorageInvalidated(); \
|
||||
\
|
||||
virtual bool \
|
||||
IsStorageShuttingDown(); \
|
||||
\
|
||||
virtual void \
|
||||
SetThreadLocals(); \
|
||||
\
|
||||
virtual void \
|
||||
UnsetThreadLocals();
|
||||
#define NS_DECL_NSIFILESTORAGE \
|
||||
virtual const nsACString& \
|
||||
StorageOrigin() MOZ_OVERRIDE; \
|
||||
\
|
||||
virtual nsISupports* \
|
||||
StorageId() MOZ_OVERRIDE; \
|
||||
\
|
||||
virtual bool \
|
||||
IsStorageInvalidated() MOZ_OVERRIDE; \
|
||||
\
|
||||
virtual bool \
|
||||
IsStorageShuttingDown() MOZ_OVERRIDE; \
|
||||
\
|
||||
virtual void \
|
||||
SetThreadLocals() MOZ_OVERRIDE; \
|
||||
\
|
||||
virtual void \
|
||||
UnsetThreadLocals() MOZ_OVERRIDE;
|
||||
|
||||
#endif // nsIFileStorage_h__
|
||||
|
@ -7,8 +7,8 @@
|
||||
#include "FileManager.h"
|
||||
|
||||
#include "mozIStorageConnection.h"
|
||||
#include "mozIStorageServiceQuotaManagement.h"
|
||||
#include "mozIStorageStatement.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
|
||||
#include "mozStorageCID.h"
|
||||
@ -18,6 +18,8 @@
|
||||
#include "IndexedDatabaseManager.h"
|
||||
#include "OpenDatabaseHelper.h"
|
||||
|
||||
#include "IndexedDatabaseInlines.h"
|
||||
|
||||
#define JOURNAL_DIRECTORY_NAME "journals"
|
||||
|
||||
USING_INDEXEDDB_NAMESPACE
|
||||
@ -262,13 +264,11 @@ FileManager::GetFileForId(nsIFile* aDirectory, int64_t aId)
|
||||
|
||||
// static
|
||||
nsresult
|
||||
FileManager::InitDirectory(mozIStorageServiceQuotaManagement* aService,
|
||||
nsIFile* aDirectory,
|
||||
FileManager::InitDirectory(nsIFile* aDirectory,
|
||||
nsIFile* aDatabaseFile,
|
||||
FactoryPrivilege aPrivilege)
|
||||
const nsACString& aOrigin)
|
||||
{
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(aService, "Null service!");
|
||||
NS_ASSERTION(aDirectory, "Null directory!");
|
||||
NS_ASSERTION(aDatabaseFile, "Null database file!");
|
||||
|
||||
@ -310,8 +310,8 @@ FileManager::InitDirectory(mozIStorageServiceQuotaManagement* aService,
|
||||
|
||||
if (hasElements) {
|
||||
nsCOMPtr<mozIStorageConnection> connection;
|
||||
rv = OpenDatabaseHelper::CreateDatabaseConnection(
|
||||
NullString(), aDatabaseFile, aDirectory, getter_AddRefs(connection));
|
||||
rv = OpenDatabaseHelper::CreateDatabaseConnection(aDatabaseFile,
|
||||
aDirectory, NullString(), aOrigin, getter_AddRefs(connection));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mozStorageTransaction transaction(connection, false);
|
||||
@ -377,12 +377,17 @@ FileManager::InitDirectory(mozIStorageServiceQuotaManagement* aService,
|
||||
}
|
||||
}
|
||||
|
||||
if (aPrivilege == Chrome) {
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
FileManager::GetUsage(nsIFile* aDirectory, uint64_t* aUsage)
|
||||
{
|
||||
uint64_t usage = 0;
|
||||
|
||||
nsCOMPtr<nsISimpleEnumerator> entries;
|
||||
rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries));
|
||||
nsresult rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool hasMore;
|
||||
@ -402,9 +407,13 @@ FileManager::InitDirectory(mozIStorageServiceQuotaManagement* aService,
|
||||
continue;
|
||||
}
|
||||
|
||||
rv = aService->UpdateQuotaInformationForFile(file);
|
||||
int64_t fileSize;
|
||||
rv = file->GetFileSize(&fileSize);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
IncrementUsage(&usage, uint64_t(fileSize));
|
||||
}
|
||||
|
||||
*aUsage = usage;
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -24,10 +24,10 @@ class FileManager
|
||||
friend class FileInfo;
|
||||
|
||||
public:
|
||||
FileManager(const nsACString& aOrigin,
|
||||
FileManager(const nsACString& aOrigin, FactoryPrivilege aPrivilege,
|
||||
const nsAString& aDatabaseName)
|
||||
: mOrigin(aOrigin), mDatabaseName(aDatabaseName), mLastFileId(0),
|
||||
mInvalidated(false)
|
||||
: mOrigin(aOrigin), mPrivilege(aPrivilege), mDatabaseName(aDatabaseName),
|
||||
mLastFileId(0), mInvalidated(false)
|
||||
{ }
|
||||
|
||||
~FileManager()
|
||||
@ -40,6 +40,11 @@ public:
|
||||
return mOrigin;
|
||||
}
|
||||
|
||||
const FactoryPrivilege& Privilege() const
|
||||
{
|
||||
return mPrivilege;
|
||||
}
|
||||
|
||||
const nsAString& DatabaseName() const
|
||||
{
|
||||
return mDatabaseName;
|
||||
@ -68,12 +73,15 @@ public:
|
||||
static already_AddRefed<nsIFile> GetFileForId(nsIFile* aDirectory,
|
||||
int64_t aId);
|
||||
|
||||
static nsresult InitDirectory(mozIStorageServiceQuotaManagement* aService,
|
||||
nsIFile* aDirectory, nsIFile* aDatabaseFile,
|
||||
FactoryPrivilege aPrivilege);
|
||||
static nsresult InitDirectory(nsIFile* aDirectory,
|
||||
nsIFile* aDatabaseFile,
|
||||
const nsACString& aOrigin);
|
||||
|
||||
static nsresult GetUsage(nsIFile* aDirectory, uint64_t* aUsage);
|
||||
|
||||
private:
|
||||
nsCString mOrigin;
|
||||
FactoryPrivilege mPrivilege;
|
||||
nsString mDatabaseName;
|
||||
|
||||
nsString mDirectoryPath;
|
||||
|
@ -1,321 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "FileStream.h"
|
||||
|
||||
#include "nsIFile.h"
|
||||
|
||||
#include "nsThreadUtils.h"
|
||||
#include "test_quota.h"
|
||||
|
||||
USING_INDEXEDDB_NAMESPACE
|
||||
|
||||
NS_IMPL_THREADSAFE_ADDREF(FileStream)
|
||||
NS_IMPL_THREADSAFE_RELEASE(FileStream)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(FileStream)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStandardFileStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISeekableStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIInputStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIOutputStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIStandardFileStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIFileMetadata)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileStream::Seek(int32_t aWhence, int64_t aOffset)
|
||||
{
|
||||
// TODO: Add support for 64 bit file sizes, bug 752431
|
||||
NS_ENSURE_TRUE(aOffset <= INT32_MAX, NS_ERROR_INVALID_ARG);
|
||||
|
||||
nsresult rv = DoPendingOpen();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!mQuotaFile) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
int whence;
|
||||
switch (aWhence) {
|
||||
case nsISeekableStream::NS_SEEK_SET:
|
||||
whence = SEEK_SET;
|
||||
break;
|
||||
case nsISeekableStream::NS_SEEK_CUR:
|
||||
whence = SEEK_CUR;
|
||||
break;
|
||||
case nsISeekableStream::NS_SEEK_END:
|
||||
whence = SEEK_END;
|
||||
break;
|
||||
default:
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!");
|
||||
|
||||
int rc = sqlite3_quota_fseek(mQuotaFile, aOffset, whence);
|
||||
NS_ENSURE_TRUE(rc == 0, NS_BASE_STREAM_OSERROR);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileStream::Tell(int64_t* aResult)
|
||||
{
|
||||
nsresult rv = DoPendingOpen();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!mQuotaFile) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!");
|
||||
|
||||
long rc = sqlite3_quota_ftell(mQuotaFile);
|
||||
NS_ENSURE_TRUE(rc >= 0, NS_BASE_STREAM_OSERROR);
|
||||
|
||||
*aResult = rc;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileStream::SetEOF()
|
||||
{
|
||||
int64_t pos;
|
||||
nsresult rv = Tell(&pos);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!");
|
||||
|
||||
int rc = sqlite3_quota_ftruncate(mQuotaFile, pos);
|
||||
NS_ENSURE_TRUE(rc == 0, NS_BASE_STREAM_OSERROR);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileStream::Close()
|
||||
{
|
||||
CleanUpOpen();
|
||||
|
||||
if (mQuotaFile) {
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!");
|
||||
|
||||
int rc = sqlite3_quota_fclose(mQuotaFile);
|
||||
mQuotaFile = nullptr;
|
||||
|
||||
NS_ENSURE_TRUE(rc == 0, NS_BASE_STREAM_OSERROR);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileStream::Available(uint64_t* aResult)
|
||||
{
|
||||
nsresult rv = DoPendingOpen();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!mQuotaFile) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!");
|
||||
|
||||
long rc = sqlite3_quota_file_available(mQuotaFile);
|
||||
NS_ENSURE_TRUE(rc >= 0, NS_BASE_STREAM_OSERROR);
|
||||
|
||||
*aResult = rc;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileStream::Read(char* aBuf, uint32_t aCount, uint32_t* aResult)
|
||||
{
|
||||
nsresult rv = DoPendingOpen();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!mQuotaFile) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!");
|
||||
|
||||
size_t bytesRead = sqlite3_quota_fread(aBuf, 1, aCount, mQuotaFile);
|
||||
if (bytesRead < aCount && sqlite3_quota_ferror(mQuotaFile)) {
|
||||
return NS_BASE_STREAM_OSERROR;
|
||||
}
|
||||
|
||||
*aResult = bytesRead;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
|
||||
uint32_t aCount, uint32_t* aResult)
|
||||
{
|
||||
NS_NOTREACHED("Don't call me!");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileStream::IsNonBlocking(bool *aNonBlocking)
|
||||
{
|
||||
*aNonBlocking = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileStream::Write(const char* aBuf, uint32_t aCount, uint32_t *aResult)
|
||||
{
|
||||
nsresult rv = DoPendingOpen();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!mQuotaFile) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!");
|
||||
|
||||
size_t bytesWritten = sqlite3_quota_fwrite(aBuf, 1, aCount, mQuotaFile);
|
||||
if (bytesWritten < aCount) {
|
||||
return NS_BASE_STREAM_OSERROR;
|
||||
}
|
||||
|
||||
*aResult = bytesWritten;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileStream::Flush()
|
||||
{
|
||||
nsresult rv = DoPendingOpen();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!mQuotaFile) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!");
|
||||
|
||||
int rc = sqlite3_quota_fflush(mQuotaFile, 1);
|
||||
NS_ENSURE_TRUE(rc == 0, NS_BASE_STREAM_OSERROR);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileStream::WriteFrom(nsIInputStream *inStr, uint32_t count, uint32_t *_retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileStream::WriteSegments(nsReadSegmentFun reader, void * closure, uint32_t count, uint32_t *_retval)
|
||||
{
|
||||
NS_NOTREACHED("Don't call me!");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileStream::Init(nsIFile* aFile, const nsAString& aMode, int32_t aFlags)
|
||||
{
|
||||
NS_ASSERTION(!mQuotaFile && !mDeferredOpen, "Already initialized!");
|
||||
|
||||
nsresult rv = aFile->GetPath(mFilePath);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mMode = aMode;
|
||||
mFlags = aFlags;
|
||||
|
||||
if (mFlags & nsIStandardFileStream::FLAGS_DEFER_OPEN) {
|
||||
mDeferredOpen = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return DoOpen();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileStream::GetSize(int64_t* _retval)
|
||||
{
|
||||
nsresult rv = DoPendingOpen();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!mQuotaFile) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!");
|
||||
|
||||
// TODO: Use sqlite3_quota_file_size() here, bug 760783
|
||||
int64_t rc = sqlite3_quota_file_truesize(mQuotaFile);
|
||||
|
||||
NS_ASSERTION(rc >= 0, "The file is not under quota management!");
|
||||
|
||||
*_retval = rc;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileStream::GetLastModified(int64_t* _retval)
|
||||
{
|
||||
nsresult rv = DoPendingOpen();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!mQuotaFile) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!");
|
||||
|
||||
time_t mtime;
|
||||
int rc = sqlite3_quota_file_mtime(mQuotaFile, &mtime);
|
||||
NS_ENSURE_TRUE(rc == 0, NS_BASE_STREAM_OSERROR);
|
||||
|
||||
*_retval = mtime * PR_MSEC_PER_SEC;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileStream::FlushBuffers()
|
||||
{
|
||||
nsresult rv = DoPendingOpen();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!mQuotaFile) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!");
|
||||
|
||||
int rc = sqlite3_quota_fflush(mQuotaFile, 0);
|
||||
NS_ENSURE_TRUE(rc == 0, NS_BASE_STREAM_OSERROR);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
FileStream::DoOpen()
|
||||
{
|
||||
NS_ASSERTION(!mFilePath.IsEmpty(), "Must have a file path");
|
||||
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!");
|
||||
|
||||
quota_FILE* quotaFile =
|
||||
sqlite3_quota_fopen(NS_ConvertUTF16toUTF8(mFilePath).get(),
|
||||
NS_ConvertUTF16toUTF8(mMode).get());
|
||||
|
||||
CleanUpOpen();
|
||||
|
||||
if (!quotaFile) {
|
||||
return NS_BASE_STREAM_OSERROR;
|
||||
}
|
||||
|
||||
mQuotaFile = quotaFile;
|
||||
|
||||
return NS_OK;
|
||||
}
|
@ -1,140 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_indexeddb_filestream_h__
|
||||
#define mozilla_dom_indexeddb_filestream_h__
|
||||
|
||||
#include "IndexedDatabase.h"
|
||||
|
||||
#include "nsIFileStreams.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsISeekableStream.h"
|
||||
#include "nsIStandardFileStream.h"
|
||||
|
||||
class nsIFile;
|
||||
struct quota_FILE;
|
||||
|
||||
BEGIN_INDEXEDDB_NAMESPACE
|
||||
|
||||
class FileStream : public nsISeekableStream,
|
||||
public nsIInputStream,
|
||||
public nsIOutputStream,
|
||||
public nsIStandardFileStream,
|
||||
public nsIFileMetadata
|
||||
{
|
||||
public:
|
||||
FileStream()
|
||||
: mFlags(0),
|
||||
mDeferredOpen(false),
|
||||
mQuotaFile(nullptr)
|
||||
{ }
|
||||
|
||||
virtual ~FileStream()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISEEKABLESTREAM
|
||||
NS_DECL_NSISTANDARDFILESTREAM
|
||||
NS_DECL_NSIFILEMETADATA
|
||||
|
||||
// nsIInputStream
|
||||
NS_IMETHOD
|
||||
Close();
|
||||
|
||||
NS_IMETHOD
|
||||
Available(uint64_t* _retval);
|
||||
|
||||
NS_IMETHOD
|
||||
Read(char* aBuf, uint32_t aCount, uint32_t* _retval);
|
||||
|
||||
NS_IMETHOD
|
||||
ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, uint32_t aCount,
|
||||
uint32_t* _retval);
|
||||
|
||||
NS_IMETHOD
|
||||
IsNonBlocking(bool* _retval);
|
||||
|
||||
// nsIOutputStream
|
||||
|
||||
// Close() already declared
|
||||
|
||||
NS_IMETHOD
|
||||
Flush();
|
||||
|
||||
NS_IMETHOD
|
||||
Write(const char* aBuf, uint32_t aCount, uint32_t* _retval);
|
||||
|
||||
NS_IMETHOD
|
||||
WriteFrom(nsIInputStream* aFromStream, uint32_t aCount, uint32_t* _retval);
|
||||
|
||||
NS_IMETHOD
|
||||
WriteSegments(nsReadSegmentFun aReader, void* aClosure, uint32_t aCount,
|
||||
uint32_t* _retval);
|
||||
|
||||
// IsNonBlocking() already declared
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Cleans up data prepared in Init.
|
||||
*/
|
||||
void
|
||||
CleanUpOpen()
|
||||
{
|
||||
mFilePath.Truncate();
|
||||
mDeferredOpen = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the file. This is called either from Init
|
||||
* or from DoPendingOpen (if FLAGS_DEFER_OPEN is used when initializing this
|
||||
* stream). The default behavior of DoOpen is to open the file and save the
|
||||
* file descriptor.
|
||||
*/
|
||||
virtual nsresult
|
||||
DoOpen();
|
||||
|
||||
/**
|
||||
* If there is a pending open, do it now. It's important for this to be
|
||||
* inlined since we do it in almost every stream API call.
|
||||
*/
|
||||
nsresult
|
||||
DoPendingOpen()
|
||||
{
|
||||
if (!mDeferredOpen) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return DoOpen();
|
||||
}
|
||||
|
||||
/**
|
||||
* Data we need to do an open.
|
||||
*/
|
||||
nsString mFilePath;
|
||||
nsString mMode;
|
||||
|
||||
/**
|
||||
* Flags describing our behavior. See the IDL file for possible values.
|
||||
*/
|
||||
int32_t mFlags;
|
||||
|
||||
/**
|
||||
* Whether we have a pending open (see FLAGS_DEFER_OPEN in the IDL file).
|
||||
*/
|
||||
bool mDeferredOpen;
|
||||
|
||||
/**
|
||||
* File descriptor for opened file.
|
||||
*/
|
||||
quota_FILE* mQuotaFile;
|
||||
};
|
||||
|
||||
END_INDEXEDDB_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_indexeddb_filestream_h__
|
@ -779,6 +779,12 @@ IDBDatabase::Close()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
const nsACString&
|
||||
IDBDatabase::StorageOrigin()
|
||||
{
|
||||
return Origin();
|
||||
}
|
||||
|
||||
nsISupports*
|
||||
IDBDatabase::StorageId()
|
||||
{
|
||||
|
@ -252,9 +252,27 @@ IDBFactory::Create(ContentParent* aContentParent,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<nsIFileURL>
|
||||
IDBFactory::GetDatabaseFileURL(nsIFile* aDatabaseFile, const nsACString& aOrigin)
|
||||
{
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = NS_NewFileURI(getter_AddRefs(uri), aDatabaseFile);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
nsCOMPtr<nsIFileURL> fileUrl = do_QueryInterface(uri);
|
||||
NS_ASSERTION(fileUrl, "This should always succeed!");
|
||||
|
||||
rv = fileUrl->SetQuery(NS_LITERAL_CSTRING("origin=") + aOrigin);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
return fileUrl.forget();
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<mozIStorageConnection>
|
||||
IDBFactory::GetConnection(const nsAString& aDatabaseFilePath)
|
||||
IDBFactory::GetConnection(const nsAString& aDatabaseFilePath,
|
||||
const nsACString& aOrigin)
|
||||
{
|
||||
NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
|
||||
NS_ASSERTION(StringEndsWith(aDatabaseFilePath, NS_LITERAL_STRING(".sqlite")),
|
||||
@ -271,13 +289,15 @@ IDBFactory::GetConnection(const nsAString& aDatabaseFilePath)
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
NS_ENSURE_TRUE(exists, nullptr);
|
||||
|
||||
nsCOMPtr<mozIStorageServiceQuotaManagement> ss =
|
||||
nsCOMPtr<nsIFileURL> dbFileUrl = GetDatabaseFileURL(dbFile, aOrigin);
|
||||
NS_ENSURE_TRUE(dbFileUrl, nullptr);
|
||||
|
||||
nsCOMPtr<mozIStorageService> ss =
|
||||
do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
|
||||
NS_ENSURE_TRUE(ss, nullptr);
|
||||
|
||||
nsCOMPtr<mozIStorageConnection> connection;
|
||||
rv = ss->OpenDatabaseWithVFS(dbFile, NS_LITERAL_CSTRING("quota"),
|
||||
getter_AddRefs(connection));
|
||||
rv = ss->OpenDatabaseWithFileURL(dbFileUrl, getter_AddRefs(connection));
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
// Turn on foreign key constraints and recursive triggers.
|
||||
|
@ -15,6 +15,8 @@
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
|
||||
class nsIAtom;
|
||||
class nsIFile;
|
||||
class nsIFileURL;
|
||||
class nsPIDOMWindow;
|
||||
|
||||
namespace mozilla {
|
||||
@ -75,8 +77,12 @@ public:
|
||||
static nsresult Create(ContentParent* aContentParent,
|
||||
IDBFactory** aFactory);
|
||||
|
||||
static already_AddRefed<nsIFileURL>
|
||||
GetDatabaseFileURL(nsIFile* aDatabaseFile, const nsACString& aOrigin);
|
||||
|
||||
static already_AddRefed<mozIStorageConnection>
|
||||
GetConnection(const nsAString& aDatabaseFilePath);
|
||||
GetConnection(const nsAString& aDatabaseFilePath,
|
||||
const nsACString& aOrigin);
|
||||
|
||||
static nsresult
|
||||
LoadDatabaseInformation(mozIStorageConnection* aConnection,
|
||||
|
@ -6,15 +6,14 @@
|
||||
|
||||
#include "IDBFileHandle.h"
|
||||
|
||||
#include "nsIStandardFileStream.h"
|
||||
|
||||
#include "mozilla/dom/file/File.h"
|
||||
#include "mozilla/dom/quota/FileStreams.h"
|
||||
#include "nsDOMClassInfoID.h"
|
||||
|
||||
#include "FileStream.h"
|
||||
#include "IDBDatabase.h"
|
||||
|
||||
USING_INDEXEDDB_NAMESPACE
|
||||
USING_QUOTA_NAMESPACE
|
||||
|
||||
namespace {
|
||||
|
||||
@ -68,22 +67,22 @@ IDBFileHandle::Create(IDBDatabase* aDatabase,
|
||||
already_AddRefed<nsISupports>
|
||||
IDBFileHandle::CreateStream(nsIFile* aFile, bool aReadOnly)
|
||||
{
|
||||
nsRefPtr<FileStream> stream = new FileStream();
|
||||
const nsACString& origin = mFileStorage->StorageOrigin();
|
||||
|
||||
nsCOMPtr<nsISupports> result;
|
||||
|
||||
nsString streamMode;
|
||||
if (aReadOnly) {
|
||||
streamMode.AssignLiteral("rb");
|
||||
nsRefPtr<FileInputStream> stream = FileInputStream::Create(
|
||||
origin, aFile, -1, -1, nsIFileInputStream::DEFER_OPEN);
|
||||
result = NS_ISUPPORTS_CAST(nsIFileInputStream*, stream);
|
||||
}
|
||||
else {
|
||||
streamMode.AssignLiteral("r+b");
|
||||
nsRefPtr<FileStream> stream = FileStream::Create(
|
||||
origin, aFile, -1, -1, nsIFileStream::DEFER_OPEN);
|
||||
result = NS_ISUPPORTS_CAST(nsIFileStream*, stream);
|
||||
}
|
||||
NS_ENSURE_TRUE(result, nullptr);
|
||||
|
||||
nsresult rv = stream->Init(aFile, streamMode,
|
||||
nsIStandardFileStream::FLAGS_DEFER_OPEN);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
nsCOMPtr<nsISupports> result =
|
||||
NS_ISUPPORTS_CAST(nsIStandardFileStream*, stream);
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/StructuredCloneTags.h"
|
||||
#include "mozilla/dom/ipc/Blob.h"
|
||||
#include "mozilla/dom/quota/FileStreams.h"
|
||||
#include "mozilla/storage.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
@ -27,10 +28,8 @@
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "snappy/snappy.h"
|
||||
#include "test_quota.h"
|
||||
|
||||
#include "AsyncConnectionHelper.h"
|
||||
#include "FileStream.h"
|
||||
#include "IDBCursor.h"
|
||||
#include "IDBEvents.h"
|
||||
#include "IDBFileHandle.h"
|
||||
@ -51,6 +50,7 @@
|
||||
USING_INDEXEDDB_NAMESPACE
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::dom::indexedDB::ipc;
|
||||
using mozilla::dom::quota::FileOutputStream;
|
||||
|
||||
namespace {
|
||||
|
||||
@ -2734,9 +2734,9 @@ AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
|
||||
nativeFile = fileManager->GetFileForId(directory, id);
|
||||
NS_ENSURE_TRUE(nativeFile, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
nsRefPtr<FileStream> outputStream = new FileStream();
|
||||
rv = outputStream->Init(nativeFile, NS_LITERAL_STRING("wb"), 0);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
nsRefPtr<FileOutputStream> outputStream = FileOutputStream::Create(
|
||||
mObjectStore->Transaction()->Database()->Origin(), nativeFile);
|
||||
NS_ENSURE_TRUE(outputStream, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
rv = CopyData(inputStream, outputStream);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
@ -352,7 +352,8 @@ IDBTransaction::GetOrCreateConnection(mozIStorageConnection** aResult)
|
||||
|
||||
if (!mConnection) {
|
||||
nsCOMPtr<mozIStorageConnection> connection =
|
||||
IDBFactory::GetConnection(mDatabase->FilePath());
|
||||
IDBFactory::GetConnection(mDatabase->FilePath(),
|
||||
mDatabase->Origin());
|
||||
NS_ENSURE_TRUE(connection, NS_ERROR_FAILURE);
|
||||
|
||||
nsresult rv;
|
||||
|
@ -79,4 +79,17 @@ AppendConditionClause(const nsACString& aColumnName,
|
||||
aResult += NS_LITERAL_CSTRING(" :") + aArgName;
|
||||
}
|
||||
|
||||
inline void
|
||||
IncrementUsage(uint64_t* aUsage, uint64_t aDelta)
|
||||
{
|
||||
// Watch for overflow!
|
||||
if ((UINT64_MAX - *aUsage) < aDelta) {
|
||||
NS_WARNING("Usage exceeds the maximum!");
|
||||
*aUsage = UINT64_MAX;
|
||||
}
|
||||
else {
|
||||
*aUsage += aDelta;
|
||||
}
|
||||
}
|
||||
|
||||
END_INDEXEDDB_NAMESPACE
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "nsITimer.h"
|
||||
|
||||
#include "mozilla/dom/file/FileService.h"
|
||||
#include "mozilla/dom/quota/QuotaManager.h"
|
||||
#include "mozilla/dom/TabContext.h"
|
||||
#include "mozilla/LazyIdleThread.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
@ -36,7 +37,6 @@
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsXPCOM.h"
|
||||
#include "nsXPCOMPrivate.h"
|
||||
#include "test_quota.h"
|
||||
#include "xpcpublic.h"
|
||||
|
||||
#include "AsyncConnectionHelper.h"
|
||||
@ -48,6 +48,8 @@
|
||||
#include "OpenDatabaseHelper.h"
|
||||
#include "TransactionThreadPool.h"
|
||||
|
||||
#include "IndexedDatabaseInlines.h"
|
||||
|
||||
// The amount of time, in milliseconds, that our IO thread will stay alive
|
||||
// after the last event it processes.
|
||||
#define DEFAULT_THREAD_TIMEOUT_MS 30000
|
||||
@ -70,6 +72,7 @@ using namespace mozilla::services;
|
||||
using namespace mozilla::dom;
|
||||
using mozilla::Preferences;
|
||||
using mozilla::dom::file::FileService;
|
||||
using mozilla::dom::quota::QuotaManager;
|
||||
|
||||
static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
|
||||
|
||||
@ -103,29 +106,6 @@ GetDatabaseBaseFilename(const nsAString& aFilename,
|
||||
return true;
|
||||
}
|
||||
|
||||
class QuotaCallback MOZ_FINAL : public mozIStorageQuotaCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD
|
||||
QuotaExceeded(const nsACString& aFilename,
|
||||
int64_t aCurrentSizeLimit,
|
||||
int64_t aCurrentTotalSize,
|
||||
nsISupports* aUserData,
|
||||
int64_t* _retval)
|
||||
{
|
||||
if (IndexedDatabaseManager::QuotaIsLifted()) {
|
||||
*_retval = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(QuotaCallback, mozIStorageQuotaCallback)
|
||||
|
||||
// Adds all databases in the hash to the given array.
|
||||
template <class T>
|
||||
PLDHashOperator
|
||||
@ -440,8 +420,8 @@ IndexedDatabaseManager::GetOrCreate()
|
||||
NS_LITERAL_CSTRING("IndexedDB I/O"),
|
||||
LazyIdleThread::ManualShutdown);
|
||||
|
||||
// We need one quota callback object to hand to SQLite.
|
||||
instance->mQuotaCallbackSingleton = new QuotaCallback();
|
||||
// Make sure that the quota manager is up.
|
||||
NS_ENSURE_TRUE(QuotaManager::GetOrCreate(), nullptr);
|
||||
|
||||
// Make a timer here to avoid potential failures later. We don't actually
|
||||
// initialize the timer until shutdown.
|
||||
@ -996,37 +976,15 @@ IndexedDatabaseManager::EnsureOriginIsInitialized(const nsACString& aOrigin,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// First figure out the filename pattern we'll use.
|
||||
nsCOMPtr<nsIFile> patternFile;
|
||||
rv = directory->Clone(getter_AddRefs(patternFile));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = patternFile->Append(NS_LITERAL_STRING("*"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsString pattern;
|
||||
rv = patternFile->GetPath(pattern);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Now tell SQLite to start tracking this pattern for content.
|
||||
nsCOMPtr<mozIStorageServiceQuotaManagement> ss =
|
||||
do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
|
||||
NS_ENSURE_TRUE(ss, NS_ERROR_FAILURE);
|
||||
|
||||
if (aPrivilege != Chrome) {
|
||||
rv = ss->SetQuotaForFilenamePattern(NS_ConvertUTF16toUTF8(pattern),
|
||||
GetIndexedDBQuotaMB() * 1024 * 1024,
|
||||
mQuotaCallbackSingleton, nullptr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// We need to see if there are any files in the directory already. If they
|
||||
// are database files then we need to cleanup stored files (if it's needed)
|
||||
// and also tell SQLite about all of them.
|
||||
// and also initialize the quota.
|
||||
|
||||
nsAutoTArray<nsString, 20> subdirsToProcess;
|
||||
nsAutoTArray<nsCOMPtr<nsIFile> , 20> unknownFiles;
|
||||
|
||||
uint64_t usage = 0;
|
||||
|
||||
nsTHashtable<nsStringHashKey> validSubdirs;
|
||||
validSubdirs.Init(20);
|
||||
|
||||
@ -1068,20 +1026,28 @@ IndexedDatabaseManager::EnsureOriginIsInitialized(const nsACString& aOrigin,
|
||||
continue;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> fileManagerDirectory;
|
||||
rv = directory->Clone(getter_AddRefs(fileManagerDirectory));
|
||||
nsCOMPtr<nsIFile> fmDirectory;
|
||||
rv = directory->Clone(getter_AddRefs(fmDirectory));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = fileManagerDirectory->Append(dbBaseFilename);
|
||||
rv = fmDirectory->Append(dbBaseFilename);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = FileManager::InitDirectory(ss, fileManagerDirectory, file,
|
||||
aPrivilege);
|
||||
rv = FileManager::InitDirectory(fmDirectory, file, aOrigin);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aPrivilege != Chrome) {
|
||||
rv = ss->UpdateQuotaInformationForFile(file);
|
||||
uint64_t fileUsage;
|
||||
rv = FileManager::GetUsage(fmDirectory, &fileUsage);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
IncrementUsage(&usage, fileUsage);
|
||||
|
||||
int64_t fileSize;
|
||||
rv = file->GetFileSize(&fileSize);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
IncrementUsage(&usage, uint64_t(fileSize));
|
||||
}
|
||||
|
||||
validSubdirs.PutEntry(dbBaseFilename);
|
||||
@ -1117,12 +1083,39 @@ IndexedDatabaseManager::EnsureOriginIsInitialized(const nsACString& aOrigin,
|
||||
}
|
||||
}
|
||||
|
||||
if (aPrivilege != Chrome) {
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
NS_ASSERTION(quotaManager, "Shouldn't be null!");
|
||||
|
||||
quotaManager->InitQuotaForOrigin(aOrigin, GetIndexedDBQuotaMB(), usage);
|
||||
}
|
||||
|
||||
mInitializedOrigins.AppendElement(aOrigin);
|
||||
|
||||
NS_ADDREF(*aDirectory = directory);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
IndexedDatabaseManager::UninitializeOriginsByPattern(
|
||||
const nsACString& aPattern)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
{
|
||||
bool correctThread;
|
||||
NS_ASSERTION(NS_SUCCEEDED(mIOThread->IsOnCurrentThread(&correctThread)) &&
|
||||
correctThread,
|
||||
"Running on the wrong thread!");
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int32_t i = mInitializedOrigins.Length() - 1; i >= 0; i--) {
|
||||
if (PatternMatchesOrigin(aPattern, mInitializedOrigins[i])) {
|
||||
mInitializedOrigins.RemoveElementAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
IndexedDatabaseManager::QuotaIsLiftedInternal()
|
||||
{
|
||||
@ -1250,16 +1243,14 @@ IndexedDatabaseManager::GetFileManager(const nsACString& aOrigin,
|
||||
}
|
||||
|
||||
void
|
||||
IndexedDatabaseManager::AddFileManager(const nsACString& aOrigin,
|
||||
const nsAString& aDatabaseName,
|
||||
FileManager* aFileManager)
|
||||
IndexedDatabaseManager::AddFileManager(FileManager* aFileManager)
|
||||
{
|
||||
NS_ASSERTION(aFileManager, "Null file manager!");
|
||||
|
||||
nsTArray<nsRefPtr<FileManager> >* array;
|
||||
if (!mFileManagers.Get(aOrigin, &array)) {
|
||||
if (!mFileManagers.Get(aFileManager->Origin(), &array)) {
|
||||
array = new nsTArray<nsRefPtr<FileManager> >();
|
||||
mFileManagers.Put(aOrigin, array);
|
||||
mFileManagers.Put(aFileManager->Origin(), array);
|
||||
}
|
||||
|
||||
array->AppendElement(aFileManager);
|
||||
@ -1783,6 +1774,13 @@ OriginClearRunnable::DeleteFiles(IndexedDatabaseManager* aManager)
|
||||
// correctly...
|
||||
NS_ERROR("Failed to remove directory!");
|
||||
}
|
||||
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
NS_ASSERTION(quotaManager, "Shouldn't be null!");
|
||||
|
||||
quotaManager->RemoveQuotaForPattern(mOriginOrPattern);
|
||||
|
||||
aManager->UninitializeOriginsByPattern(mOriginOrPattern);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1880,19 +1878,6 @@ IndexedDatabaseManager::AsyncUsageRunnable::Cancel()
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
IncrementUsage(uint64_t* aUsage, uint64_t aDelta)
|
||||
{
|
||||
// Watch for overflow!
|
||||
if ((INT64_MAX - *aUsage) <= aDelta) {
|
||||
NS_WARNING("Database sizes exceed max we can report!");
|
||||
*aUsage = INT64_MAX;
|
||||
}
|
||||
else {
|
||||
*aUsage += aDelta;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
IndexedDatabaseManager::AsyncUsageRunnable::TakeShortcut()
|
||||
{
|
||||
@ -2295,25 +2280,22 @@ IndexedDatabaseManager::AsyncDeleteFileRunnable::Run()
|
||||
nsCOMPtr<nsIFile> file = mFileManager->GetFileForId(directory, mFileId);
|
||||
NS_ENSURE_TRUE(file, NS_ERROR_FAILURE);
|
||||
|
||||
nsString filePath;
|
||||
nsresult rv = file->GetPath(filePath);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsresult rv;
|
||||
int64_t fileSize;
|
||||
|
||||
int rc = sqlite3_quota_remove(NS_ConvertUTF16toUTF8(filePath).get());
|
||||
if (rc != SQLITE_OK) {
|
||||
NS_WARNING("Failed to delete stored file!");
|
||||
return NS_ERROR_FAILURE;
|
||||
if (mFileManager->Privilege() != Chrome) {
|
||||
rv = file->GetFileSize(&fileSize);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
// sqlite3_quota_remove won't actually remove anything if we're not tracking
|
||||
// the quota here. Manually remove the file if it exists.
|
||||
bool exists;
|
||||
rv = file->Exists(&exists);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = file->Remove(false);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
|
||||
|
||||
if (exists) {
|
||||
rv = file->Remove(false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (mFileManager->Privilege() != Chrome) {
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
NS_ASSERTION(quotaManager, "Shouldn't be null!");
|
||||
|
||||
quotaManager->DecreaseUsageForOrigin(mFileManager->Origin(), fileSize);
|
||||
}
|
||||
|
||||
directory = mFileManager->GetJournalDirectory();
|
||||
|
@ -23,7 +23,6 @@
|
||||
|
||||
#define INDEXEDDB_MANAGER_CONTRACTID "@mozilla.org/dom/indexeddb/manager;1"
|
||||
|
||||
class mozIStorageQuotaCallback;
|
||||
class nsIAtom;
|
||||
class nsIFile;
|
||||
class nsITimer;
|
||||
@ -134,6 +133,8 @@ public:
|
||||
FactoryPrivilege aPrivilege,
|
||||
nsIFile** aDirectory);
|
||||
|
||||
void UninitializeOriginsByPattern(const nsACString& aPattern);
|
||||
|
||||
// Determine if the quota is lifted for the Window the current thread is
|
||||
// using.
|
||||
static inline bool
|
||||
@ -172,9 +173,7 @@ public:
|
||||
const nsAString& aDatabaseName);
|
||||
|
||||
void
|
||||
AddFileManager(const nsACString& aOrigin,
|
||||
const nsAString& aDatabaseName,
|
||||
FileManager* aFileManager);
|
||||
AddFileManager(FileManager* aFileManager);
|
||||
|
||||
void InvalidateFileManagersForPattern(const nsACString& aPattern);
|
||||
|
||||
@ -502,10 +501,6 @@ private:
|
||||
// A timer that gets activated at shutdown to ensure we close all databases.
|
||||
nsCOMPtr<nsITimer> mShutdownTimer;
|
||||
|
||||
// A single threadsafe instance of our quota callback. Created on the main
|
||||
// thread during GetOrCreate().
|
||||
nsCOMPtr<mozIStorageQuotaCallback> mQuotaCallbackSingleton;
|
||||
|
||||
// A list of all successfully initialized origins. This list isn't protected
|
||||
// by any mutex but it is only ever touched on the IO thread.
|
||||
nsTArray<nsCString> mInitializedOrigins;
|
||||
|
@ -25,7 +25,6 @@ CPPSRCS = \
|
||||
DatabaseInfo.cpp \
|
||||
FileInfo.cpp \
|
||||
FileManager.cpp \
|
||||
FileStream.cpp \
|
||||
IDBCursor.cpp \
|
||||
IDBDatabase.cpp \
|
||||
IDBEvents.cpp \
|
||||
@ -93,7 +92,6 @@ XPIDLSRCS = \
|
||||
nsIIDBVersionChangeEvent.idl \
|
||||
nsIIDBOpenDBRequest.idl \
|
||||
nsIIndexedDatabaseManager.idl \
|
||||
nsIStandardFileStream.idl \
|
||||
$(NULL)
|
||||
|
||||
DIRS += ipc
|
||||
|
@ -8,11 +8,12 @@
|
||||
|
||||
#include "nsIFile.h"
|
||||
|
||||
#include "mozilla/dom/quota/QuotaManager.h"
|
||||
#include "mozilla/storage.h"
|
||||
#include "nsEscape.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "snappy/snappy.h"
|
||||
#include "test_quota.h"
|
||||
|
||||
#include "nsIBFCacheEntry.h"
|
||||
#include "IDBEvents.h"
|
||||
@ -21,6 +22,7 @@
|
||||
|
||||
using namespace mozilla;
|
||||
USING_INDEXEDDB_NAMESPACE
|
||||
USING_QUOTA_NAMESPACE
|
||||
|
||||
namespace {
|
||||
|
||||
@ -1632,15 +1634,15 @@ OpenDatabaseHelper::DoDatabaseWork()
|
||||
rv = dbFile->GetPath(mDatabaseFilePath);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
nsCOMPtr<nsIFile> fileManagerDirectory;
|
||||
rv = dbDirectory->Clone(getter_AddRefs(fileManagerDirectory));
|
||||
nsCOMPtr<nsIFile> fmDirectory;
|
||||
rv = dbDirectory->Clone(getter_AddRefs(fmDirectory));
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
rv = fileManagerDirectory->Append(filename);
|
||||
rv = fmDirectory->Append(filename);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
nsCOMPtr<mozIStorageConnection> connection;
|
||||
rv = CreateDatabaseConnection(mName, dbFile, fileManagerDirectory,
|
||||
rv = CreateDatabaseConnection(dbFile, fmDirectory, mName, mASCIIOrigin,
|
||||
getter_AddRefs(connection));
|
||||
if (NS_FAILED(rv) &&
|
||||
NS_ERROR_GET_MODULE(rv) != NS_ERROR_MODULE_DOM_INDEXEDDB) {
|
||||
@ -1691,12 +1693,12 @@ OpenDatabaseHelper::DoDatabaseWork()
|
||||
|
||||
nsRefPtr<FileManager> fileManager = mgr->GetFileManager(mASCIIOrigin, mName);
|
||||
if (!fileManager) {
|
||||
fileManager = new FileManager(mASCIIOrigin, mName);
|
||||
fileManager = new FileManager(mASCIIOrigin, mPrivilege, mName);
|
||||
|
||||
rv = fileManager->Init(fileManagerDirectory, connection);
|
||||
rv = fileManager->Init(fmDirectory, connection);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
mgr->AddFileManager(mASCIIOrigin, mName, fileManager);
|
||||
mgr->AddFileManager(fileManager);
|
||||
}
|
||||
|
||||
mFileManager = fileManager.forget();
|
||||
@ -1707,23 +1709,26 @@ OpenDatabaseHelper::DoDatabaseWork()
|
||||
// static
|
||||
nsresult
|
||||
OpenDatabaseHelper::CreateDatabaseConnection(
|
||||
const nsAString& aName,
|
||||
nsIFile* aDBFile,
|
||||
nsIFile* aFileManagerDirectory,
|
||||
nsIFile* aFMDirectory,
|
||||
const nsAString& aName,
|
||||
const nsACString& aOrigin,
|
||||
mozIStorageConnection** aConnection)
|
||||
{
|
||||
NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
NS_NAMED_LITERAL_CSTRING(quotaVFSName, "quota");
|
||||
nsCOMPtr<nsIFileURL> dbFileUrl =
|
||||
IDBFactory::GetDatabaseFileURL(aDBFile, aOrigin);
|
||||
NS_ENSURE_TRUE(dbFileUrl, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<mozIStorageServiceQuotaManagement> ss =
|
||||
nsCOMPtr<mozIStorageService> ss =
|
||||
do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
|
||||
NS_ENSURE_TRUE(ss, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<mozIStorageConnection> connection;
|
||||
nsresult rv = ss->OpenDatabaseWithVFS(aDBFile, quotaVFSName,
|
||||
getter_AddRefs(connection));
|
||||
nsresult rv =
|
||||
ss->OpenDatabaseWithFileURL(dbFileUrl, getter_AddRefs(connection));
|
||||
if (rv == NS_ERROR_FILE_CORRUPTED) {
|
||||
// If we're just opening the database during origin initialization, then
|
||||
// we don't want to erase any files. The failure here will fail origin
|
||||
@ -1737,21 +1742,20 @@ OpenDatabaseHelper::CreateDatabaseConnection(
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool exists;
|
||||
rv = aFileManagerDirectory->Exists(&exists);
|
||||
rv = aFMDirectory->Exists(&exists);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (exists) {
|
||||
bool isDirectory;
|
||||
rv = aFileManagerDirectory->IsDirectory(&isDirectory);
|
||||
rv = aFMDirectory->IsDirectory(&isDirectory);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(isDirectory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
rv = aFileManagerDirectory->Remove(true);
|
||||
rv = aFMDirectory->Remove(true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
rv = ss->OpenDatabaseWithVFS(aDBFile, quotaVFSName,
|
||||
getter_AddRefs(connection));
|
||||
rv = ss->OpenDatabaseWithFileURL(dbFileUrl, getter_AddRefs(connection));
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
@ -2347,6 +2351,8 @@ DeleteDatabaseHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
|
||||
{
|
||||
NS_ASSERTION(!aConnection, "How did we get a connection here?");
|
||||
|
||||
const FactoryPrivilege& privilege = mOpenHelper->Privilege();
|
||||
|
||||
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
|
||||
NS_ASSERTION(mgr, "This should never fail!");
|
||||
|
||||
@ -2372,59 +2378,57 @@ DeleteDatabaseHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
|
||||
rv = dbFile->Exists(&exists);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
int rc;
|
||||
|
||||
if (exists) {
|
||||
nsString dbFilePath;
|
||||
rv = dbFile->GetPath(dbFilePath);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
int64_t fileSize;
|
||||
|
||||
rc = sqlite3_quota_remove(NS_ConvertUTF16toUTF8(dbFilePath).get());
|
||||
if (rc != SQLITE_OK) {
|
||||
NS_WARNING("Failed to delete db file!");
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
if (privilege != Chrome) {
|
||||
rv = dbFile->GetFileSize(&fileSize);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
}
|
||||
|
||||
// sqlite3_quota_remove won't actually remove anything if we're not tracking
|
||||
// the quota here. Manually remove the file if it exists.
|
||||
rv = dbFile->Exists(&exists);
|
||||
rv = dbFile->Remove(false);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
if (exists) {
|
||||
rv = dbFile->Remove(false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (privilege != Chrome) {
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
NS_ASSERTION(quotaManager, "Shouldn't be null!");
|
||||
|
||||
quotaManager->DecreaseUsageForOrigin(mASCIIOrigin, fileSize);
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> fileManagerDirectory;
|
||||
rv = directory->Clone(getter_AddRefs(fileManagerDirectory));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = fileManagerDirectory->Append(filename);
|
||||
nsCOMPtr<nsIFile> fmDirectory;
|
||||
rv = directory->Clone(getter_AddRefs(fmDirectory));
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
rv = fileManagerDirectory->Exists(&exists);
|
||||
rv = fmDirectory->Append(filename);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
rv = fmDirectory->Exists(&exists);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
if (exists) {
|
||||
bool isDirectory;
|
||||
rv = fileManagerDirectory->IsDirectory(&isDirectory);
|
||||
rv = fmDirectory->IsDirectory(&isDirectory);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(isDirectory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
nsString fileManagerDirectoryPath;
|
||||
rv = fileManagerDirectory->GetPath(fileManagerDirectoryPath);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
uint64_t usage = 0;
|
||||
|
||||
rc = sqlite3_quota_remove(
|
||||
NS_ConvertUTF16toUTF8(fileManagerDirectoryPath).get());
|
||||
if (rc != SQLITE_OK) {
|
||||
NS_WARNING("Failed to delete file directory!");
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
if (privilege != Chrome) {
|
||||
rv = FileManager::GetUsage(fmDirectory, &usage);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
}
|
||||
|
||||
rv = fileManagerDirectory->Remove(true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = fmDirectory->Remove(true);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
if (privilege != Chrome) {
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
NS_ASSERTION(quotaManager, "Shouldn't be null!");
|
||||
|
||||
quotaManager->DecreaseUsageForOrigin(mASCIIOrigin, usage);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -77,10 +77,16 @@ public:
|
||||
return mDatabase;
|
||||
}
|
||||
|
||||
const FactoryPrivilege& Privilege() const
|
||||
{
|
||||
return mPrivilege;
|
||||
}
|
||||
|
||||
static
|
||||
nsresult CreateDatabaseConnection(const nsAString& aName,
|
||||
nsIFile* aDBFile,
|
||||
nsIFile* aFileManagerDirectory,
|
||||
nsresult CreateDatabaseConnection(nsIFile* aDBFile,
|
||||
nsIFile* aFMDirectory,
|
||||
const nsAString& aName,
|
||||
const nsACString& aOrigin,
|
||||
mozIStorageConnection** aConnection);
|
||||
|
||||
protected:
|
||||
|
@ -1,60 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIFile;
|
||||
|
||||
/**
|
||||
* A stream that allows you to read from a file or stream to a file
|
||||
* using standard file APIs.
|
||||
*/
|
||||
[scriptable, uuid(ebbbb779-92a3-4b2a-b7cf-6efbe904c453)]
|
||||
interface nsIStandardFileStream : nsISupports
|
||||
{
|
||||
/**
|
||||
* If this is set, the file will be opened (i.e., a call to
|
||||
* fopen done) only when we do an actual operation on the stream,
|
||||
* or more specifically, when one of the following is called:
|
||||
* - Seek
|
||||
* - Tell
|
||||
* - SetEOF
|
||||
* - Available
|
||||
* - Read
|
||||
* - Write
|
||||
* - Flush
|
||||
* - GetSize
|
||||
* - GetLastModified
|
||||
* - Sync
|
||||
*
|
||||
* FLAGS_DEFER_OPEN is useful if we use the stream on a background
|
||||
* thread, so that the opening and possible |stat|ing of the file
|
||||
* happens there as well.
|
||||
*
|
||||
* @note Using this flag results in the file not being opened
|
||||
* during the call to Init. This means that any errors that might
|
||||
* happen when this flag is not set would happen during the
|
||||
* first read. Also, the file is not locked when Init is called,
|
||||
* so it might be deleted before we try to read from it.
|
||||
*/
|
||||
const long FLAGS_DEFER_OPEN = 1 << 0;
|
||||
|
||||
/**
|
||||
* @param file file to read from or stream to
|
||||
* @param mode file open mode (see fopen documentation)
|
||||
* @param flags flags specifying various behaviors of the class
|
||||
* (see enumerations in the class)
|
||||
*/
|
||||
void init(in nsIFile file,
|
||||
in AString mode,
|
||||
in long flags);
|
||||
|
||||
/**
|
||||
* Flush all written content held in memory buffers out to disk.
|
||||
* This is the equivalent of fflush()
|
||||
*/
|
||||
void flushBuffers();
|
||||
};
|
@ -54,11 +54,13 @@ MOCHITEST_FILES = \
|
||||
test_file_os_delete.html \
|
||||
test_file_put_get_object.html \
|
||||
test_file_put_get_values.html \
|
||||
test_file_quota.html \
|
||||
test_file_replace.html \
|
||||
test_file_resurrection_delete.html \
|
||||
test_file_resurrection_transaction_abort.html \
|
||||
test_file_sharing.html \
|
||||
test_file_transaction_abort.html \
|
||||
test_filehandle_quota.html \
|
||||
test_filehandle_serialization.html \
|
||||
test_filehandle_store_snapshot.html \
|
||||
test_getAll.html \
|
||||
|
@ -3,6 +3,8 @@
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
const DEFAULT_QUOTA = 50 * 1024 * 1024;
|
||||
|
||||
var bufferCache = [];
|
||||
var utils = SpecialPowers.getDOMWindowUtils(window);
|
||||
|
||||
@ -184,25 +186,6 @@ function getUsage(usageHandler)
|
||||
idbManager.getUsageForURI(uri, callback);
|
||||
}
|
||||
|
||||
function getUsageSync()
|
||||
{
|
||||
let usage;
|
||||
|
||||
getUsage(function(aUsage, aFileUsage) {
|
||||
usage = aUsage;
|
||||
});
|
||||
|
||||
let comp = SpecialPowers.wrap(Components);
|
||||
let thread = comp.classes["@mozilla.org/thread-manager;1"]
|
||||
.getService(comp.interfaces.nsIThreadManager)
|
||||
.currentThread;
|
||||
while (!usage) {
|
||||
thread.processNextEvent(true);
|
||||
}
|
||||
|
||||
return usage;
|
||||
}
|
||||
|
||||
function scheduleGC()
|
||||
{
|
||||
SpecialPowers.exactGC(window, continueToNextStep);
|
||||
|
@ -13,14 +13,12 @@
|
||||
function testSteps()
|
||||
{
|
||||
const READ_WRITE = IDBTransaction.READ_WRITE;
|
||||
const DEFAULT_QUOTA_MB = 50;
|
||||
|
||||
const name = window.location.pathname;
|
||||
|
||||
const objectStoreName = "Blobs";
|
||||
|
||||
const testData = { key: 0, value: {} };
|
||||
const fileData = { key: 1, file: null };
|
||||
const fileData = { key: 1, file: getNullFile("random.bin", DEFAULT_QUOTA) };
|
||||
|
||||
let request = indexedDB.open(name, 1);
|
||||
request.onerror = errorHandler;
|
||||
@ -32,21 +30,17 @@
|
||||
|
||||
let db = event.target.result;
|
||||
|
||||
let objectStore = db.createObjectStore(objectStoreName, { });
|
||||
objectStore.add(testData.value, testData.key);
|
||||
|
||||
let size = (DEFAULT_QUOTA_MB + 1) * 1024 * 1024 - getUsageSync();
|
||||
fileData.file = getNullFile("random.bin", size);
|
||||
db.createObjectStore(objectStoreName, { });
|
||||
|
||||
event = yield;
|
||||
|
||||
is(event.type, "success", "Got correct event type");
|
||||
|
||||
trans = db.transaction([objectStoreName], READ_WRITE);
|
||||
objectStore = trans.objectStore(objectStoreName);
|
||||
let objectStore = trans.objectStore(objectStoreName);
|
||||
|
||||
request = objectStore.add(fileData.file, fileData.key);
|
||||
request.addEventListener("error", new ExpectError("UnknownError"));
|
||||
request.addEventListener("error", new ExpectError("UnknownError", true));
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
event = yield;
|
||||
|
||||
|
@ -13,7 +13,6 @@
|
||||
function testSteps()
|
||||
{
|
||||
const READ_WRITE = IDBTransaction.READ_WRITE;
|
||||
const DEFAULT_QUOTA_MB = 50;
|
||||
|
||||
const name = window.location.pathname;
|
||||
|
||||
@ -39,10 +38,10 @@
|
||||
|
||||
let lockedFile = fileHandle.open("readwrite");
|
||||
|
||||
let blob = getNullBlob((50 + 1) * 1024 * 1024 - getUsageSync());
|
||||
let blob = getNullBlob(DEFAULT_QUOTA);
|
||||
|
||||
request = lockedFile.write(blob);
|
||||
request.addEventListener("error", new ExpectError("UnknownError"));
|
||||
request.addEventListener("error", new ExpectError("UnknownError", true));
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
event = yield;
|
||||
|
||||
|
123
dom/quota/FileStreams.cpp
Normal file
123
dom/quota/FileStreams.cpp
Normal file
@ -0,0 +1,123 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "FileStreams.h"
|
||||
|
||||
USING_QUOTA_NAMESPACE
|
||||
|
||||
template <class FileStreamBase>
|
||||
NS_IMETHODIMP
|
||||
FileQuotaStream<FileStreamBase>::SetEOF()
|
||||
{
|
||||
nsresult rv = FileStreamBase::SetEOF();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (mQuotaObject) {
|
||||
int64_t offset;
|
||||
nsresult rv = FileStreamBase::Tell(&offset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mQuotaObject->UpdateSize(offset);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
template <class FileStreamBase>
|
||||
NS_IMETHODIMP
|
||||
FileQuotaStream<FileStreamBase>::Close()
|
||||
{
|
||||
nsresult rv = FileStreamBase::Close();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mQuotaObject = nullptr;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
template <class FileStreamBase>
|
||||
nsresult
|
||||
FileQuotaStream<FileStreamBase>::DoOpen()
|
||||
{
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
NS_ASSERTION(quotaManager, "Shouldn't be null!");
|
||||
|
||||
NS_ASSERTION(!mQuotaObject, "Creating quota object more than once?");
|
||||
mQuotaObject = quotaManager->GetQuotaObject(mOrigin,
|
||||
FileStreamBase::mOpenParams.localFile);
|
||||
|
||||
nsresult rv = FileStreamBase::DoOpen();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (mQuotaObject && (FileStreamBase::mOpenParams.ioFlags & PR_TRUNCATE)) {
|
||||
mQuotaObject->UpdateSize(0);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
template <class FileStreamBase>
|
||||
NS_IMETHODIMP
|
||||
FileQuotaStreamWithWrite<FileStreamBase>::Write(const char* aBuf,
|
||||
uint32_t aCount,
|
||||
uint32_t* _retval)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (FileQuotaStreamWithWrite::mQuotaObject) {
|
||||
int64_t offset;
|
||||
rv = FileStreamBase::Tell(&offset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!FileQuotaStreamWithWrite::
|
||||
mQuotaObject->MaybeAllocateMoreSpace(offset, aCount)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
rv = FileStreamBase::Write(aBuf, aCount, _retval);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(FileInputStream, nsFileInputStream)
|
||||
|
||||
already_AddRefed<FileInputStream>
|
||||
FileInputStream::Create(const nsACString& aOrigin, nsIFile* aFile,
|
||||
int32_t aIOFlags, int32_t aPerm,
|
||||
int32_t aBehaviorFlags)
|
||||
{
|
||||
nsRefPtr<FileInputStream> stream = new FileInputStream(aOrigin);
|
||||
nsresult rv = stream->Init(aFile, aIOFlags, aPerm, aBehaviorFlags);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
return stream.forget();
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(FileOutputStream, nsFileOutputStream)
|
||||
|
||||
already_AddRefed<FileOutputStream>
|
||||
FileOutputStream::Create(const nsACString& aOrigin, nsIFile* aFile,
|
||||
int32_t aIOFlags, int32_t aPerm,
|
||||
int32_t aBehaviorFlags)
|
||||
{
|
||||
nsRefPtr<FileOutputStream> stream = new FileOutputStream(aOrigin);
|
||||
nsresult rv = stream->Init(aFile, aIOFlags, aPerm, aBehaviorFlags);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
return stream.forget();
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(FileStream, nsFileStream)
|
||||
|
||||
already_AddRefed<FileStream>
|
||||
FileStream::Create(const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags,
|
||||
int32_t aPerm, int32_t aBehaviorFlags)
|
||||
{
|
||||
nsRefPtr<FileStream> stream = new FileStream(aOrigin);
|
||||
nsresult rv = stream->Init(aFile, aIOFlags, aPerm, aBehaviorFlags);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
return stream.forget();
|
||||
}
|
115
dom/quota/FileStreams.h
Normal file
115
dom/quota/FileStreams.h
Normal file
@ -0,0 +1,115 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_quota_filestreams_h__
|
||||
#define mozilla_dom_quota_filestreams_h__
|
||||
|
||||
#include "QuotaCommon.h"
|
||||
|
||||
#include "nsFileStreams.h"
|
||||
|
||||
#include "QuotaManager.h"
|
||||
|
||||
BEGIN_QUOTA_NAMESPACE
|
||||
|
||||
template <class FileStreamBase>
|
||||
class FileQuotaStream : public FileStreamBase
|
||||
{
|
||||
public:
|
||||
// nsFileStreamBase override
|
||||
NS_IMETHOD
|
||||
SetEOF() MOZ_OVERRIDE;
|
||||
|
||||
NS_IMETHOD
|
||||
Close() MOZ_OVERRIDE;
|
||||
|
||||
protected:
|
||||
FileQuotaStream(const nsACString& aOrigin)
|
||||
: mOrigin(aOrigin)
|
||||
{ }
|
||||
|
||||
// nsFileStreamBase override
|
||||
virtual nsresult
|
||||
DoOpen() MOZ_OVERRIDE;
|
||||
|
||||
nsCString mOrigin;
|
||||
nsRefPtr<QuotaObject> mQuotaObject;
|
||||
};
|
||||
|
||||
template <class FileStreamBase>
|
||||
class FileQuotaStreamWithWrite : public FileQuotaStream<FileStreamBase>
|
||||
{
|
||||
public:
|
||||
// nsFileStreamBase override
|
||||
NS_IMETHOD
|
||||
Write(const char* aBuf, uint32_t aCount, uint32_t* _retval) MOZ_OVERRIDE;
|
||||
|
||||
protected:
|
||||
FileQuotaStreamWithWrite(const nsACString& aOrigin)
|
||||
: FileQuotaStream<FileStreamBase>(aOrigin)
|
||||
{ }
|
||||
};
|
||||
|
||||
class FileInputStream : public FileQuotaStream<nsFileInputStream>
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
static already_AddRefed<FileInputStream>
|
||||
Create(const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags = -1,
|
||||
int32_t aPerm = -1, int32_t aBehaviorFlags = 0);
|
||||
|
||||
private:
|
||||
FileInputStream(const nsACString& aOrigin)
|
||||
: FileQuotaStream<nsFileInputStream>(aOrigin)
|
||||
{ }
|
||||
|
||||
virtual ~FileInputStream() {
|
||||
Close();
|
||||
}
|
||||
};
|
||||
|
||||
class FileOutputStream : public FileQuotaStreamWithWrite<nsFileOutputStream>
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
static already_AddRefed<FileOutputStream>
|
||||
Create(const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags = -1,
|
||||
int32_t aPerm = -1, int32_t aBehaviorFlags = 0);
|
||||
|
||||
private:
|
||||
FileOutputStream(const nsACString& aOrigin)
|
||||
: FileQuotaStreamWithWrite<nsFileOutputStream>(aOrigin)
|
||||
{ }
|
||||
|
||||
virtual ~FileOutputStream() {
|
||||
Close();
|
||||
}
|
||||
};
|
||||
|
||||
class FileStream : public FileQuotaStreamWithWrite<nsFileStream>
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
static already_AddRefed<FileStream>
|
||||
Create(const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags = -1,
|
||||
int32_t aPerm = -1, int32_t aBehaviorFlags = 0);
|
||||
|
||||
private:
|
||||
FileStream(const nsACString& aOrigin)
|
||||
: FileQuotaStreamWithWrite<nsFileStream>(aOrigin)
|
||||
{ }
|
||||
|
||||
virtual ~FileStream() {
|
||||
Close();
|
||||
}
|
||||
};
|
||||
|
||||
END_QUOTA_NAMESPACE
|
||||
|
||||
#endif /* mozilla_dom_quota_filestreams_h__ */
|
33
dom/quota/Makefile.in
Normal file
33
dom/quota/Makefile.in
Normal file
@ -0,0 +1,33 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DEPTH = ../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = dom
|
||||
LIBRARY_NAME = domquota_s
|
||||
XPIDL_MODULE = dom_quota
|
||||
LIBXUL_LIBRARY = 1
|
||||
FORCE_STATIC_LIB = 1
|
||||
|
||||
include $(topsrcdir)/dom/dom-config.mk
|
||||
|
||||
EXPORTS_NAMESPACES = mozilla/dom/quota
|
||||
|
||||
CPPSRCS = \
|
||||
FileStreams.cpp \
|
||||
QuotaManager.cpp \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS_mozilla/dom/quota = \
|
||||
FileStreams.h \
|
||||
QuotaCommon.h \
|
||||
QuotaManager.h \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
23
dom/quota/QuotaCommon.h
Normal file
23
dom/quota/QuotaCommon.h
Normal file
@ -0,0 +1,23 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_quota_quotacommon_h__
|
||||
#define mozilla_dom_quota_quotacommon_h__
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsDebug.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
#define BEGIN_QUOTA_NAMESPACE \
|
||||
namespace mozilla { namespace dom { namespace quota {
|
||||
#define END_QUOTA_NAMESPACE \
|
||||
} /* namespace quota */ } /* namespace dom */ } /* namespace mozilla */
|
||||
#define USING_QUOTA_NAMESPACE \
|
||||
using namespace mozilla::dom::quota;
|
||||
|
||||
#endif // mozilla_dom_quota_quotacommon_h__
|
294
dom/quota/QuotaManager.cpp
Normal file
294
dom/quota/QuotaManager.cpp
Normal file
@ -0,0 +1,294 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "QuotaManager.h"
|
||||
|
||||
#include "nsIFile.h"
|
||||
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
|
||||
#include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
|
||||
|
||||
USING_QUOTA_NAMESPACE
|
||||
|
||||
namespace {
|
||||
|
||||
nsAutoPtr<QuotaManager> gInstance;
|
||||
|
||||
PLDHashOperator
|
||||
RemoveQuotaForPatternCallback(const nsACString& aKey,
|
||||
nsRefPtr<OriginInfo>& aValue,
|
||||
void* aUserArg)
|
||||
{
|
||||
NS_ASSERTION(!aKey.IsEmpty(), "Empty key!");
|
||||
NS_ASSERTION(aValue, "Null pointer!");
|
||||
NS_ASSERTION(aUserArg, "Null pointer!");
|
||||
|
||||
const nsACString* pattern =
|
||||
static_cast<const nsACString*>(aUserArg);
|
||||
|
||||
if (StringBeginsWith(aKey, *pattern)) {
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void
|
||||
QuotaObject::AddRef()
|
||||
{
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
if (!quotaManager) {
|
||||
NS_ERROR("Null quota manager, this shouldn't happen, possible leak!");
|
||||
|
||||
NS_AtomicIncrementRefcnt(mRefCnt);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
MutexAutoLock lock(quotaManager->mQuotaMutex);
|
||||
|
||||
++mRefCnt;
|
||||
}
|
||||
|
||||
void
|
||||
QuotaObject::Release()
|
||||
{
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
if (!quotaManager) {
|
||||
NS_ERROR("Null quota manager, this shouldn't happen, possible leak!");
|
||||
|
||||
nsrefcnt count = NS_AtomicDecrementRefcnt(mRefCnt);
|
||||
if (count == 0) {
|
||||
mRefCnt = 1;
|
||||
delete this;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
MutexAutoLock lock(quotaManager->mQuotaMutex);
|
||||
|
||||
--mRefCnt;
|
||||
|
||||
if (mRefCnt > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mOriginInfo) {
|
||||
mOriginInfo->mQuotaObjects.Remove(mPath);
|
||||
}
|
||||
}
|
||||
|
||||
delete this;
|
||||
}
|
||||
|
||||
void
|
||||
QuotaObject::UpdateSize(int64_t aSize)
|
||||
{
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
NS_ASSERTION(quotaManager, "Shouldn't be null!");
|
||||
|
||||
MutexAutoLock lock(quotaManager->mQuotaMutex);
|
||||
|
||||
if (mOriginInfo) {
|
||||
mOriginInfo->mUsage -= mSize;
|
||||
mSize = aSize;
|
||||
mOriginInfo->mUsage += mSize;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
QuotaObject::MaybeAllocateMoreSpace(int64_t aOffset, int32_t aCount)
|
||||
{
|
||||
int64_t end = aOffset + aCount;
|
||||
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
NS_ASSERTION(quotaManager, "Shouldn't be null!");
|
||||
|
||||
MutexAutoLock lock(quotaManager->mQuotaMutex);
|
||||
|
||||
if (mSize >= end || !mOriginInfo) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int64_t newUsage = mOriginInfo->mUsage - mSize + end;
|
||||
if (newUsage > mOriginInfo->mLimit) {
|
||||
if (!indexedDB::IndexedDatabaseManager::QuotaIsLifted()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCString origin = mOriginInfo->mOrigin;
|
||||
|
||||
mOriginInfo->LockedClearOriginInfos();
|
||||
NS_ASSERTION(!mOriginInfo,
|
||||
"Should have cleared in LockedClearOriginInfos!");
|
||||
|
||||
quotaManager->mOriginInfos.Remove(origin);
|
||||
|
||||
mSize = end;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
mOriginInfo->mUsage = newUsage;
|
||||
mSize = end;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
OriginInfo::LockedClearOriginInfos()
|
||||
{
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
NS_ASSERTION(quotaManager, "Shouldn't be null!");
|
||||
|
||||
quotaManager->mQuotaMutex.AssertCurrentThreadOwns();
|
||||
|
||||
mQuotaObjects.EnumerateRead(ClearOriginInfoCallback, nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
// static
|
||||
PLDHashOperator
|
||||
OriginInfo::ClearOriginInfoCallback(const nsAString& aKey,
|
||||
QuotaObject* aValue,
|
||||
void* aUserArg)
|
||||
{
|
||||
NS_ASSERTION(!aKey.IsEmpty(), "Empty key!");
|
||||
NS_ASSERTION(aValue, "Null pointer!");
|
||||
|
||||
aValue->mOriginInfo = nullptr;
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
// static
|
||||
QuotaManager*
|
||||
QuotaManager::GetOrCreate()
|
||||
{
|
||||
if (!gInstance) {
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
gInstance = new QuotaManager();
|
||||
|
||||
ClearOnShutdown(&gInstance);
|
||||
}
|
||||
|
||||
return gInstance;
|
||||
}
|
||||
|
||||
// static
|
||||
QuotaManager*
|
||||
QuotaManager::Get()
|
||||
{
|
||||
// Does not return an owning reference.
|
||||
return gInstance;
|
||||
}
|
||||
|
||||
void
|
||||
QuotaManager::InitQuotaForOrigin(const nsACString& aOrigin,
|
||||
int64_t aLimit,
|
||||
int64_t aUsage)
|
||||
{
|
||||
OriginInfo* info = new OriginInfo(aOrigin, aLimit * 1024 * 1024, aUsage);
|
||||
|
||||
MutexAutoLock lock(mQuotaMutex);
|
||||
|
||||
NS_ASSERTION(!mOriginInfos.GetWeak(aOrigin), "Replacing an existing entry!");
|
||||
mOriginInfos.Put(aOrigin, info);
|
||||
}
|
||||
|
||||
void
|
||||
QuotaManager::DecreaseUsageForOrigin(const nsACString& aOrigin,
|
||||
int64_t aSize)
|
||||
{
|
||||
MutexAutoLock lock(mQuotaMutex);
|
||||
|
||||
nsRefPtr<OriginInfo> originInfo;
|
||||
mOriginInfos.Get(aOrigin, getter_AddRefs(originInfo));
|
||||
|
||||
if (originInfo) {
|
||||
originInfo->mUsage -= aSize;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
QuotaManager::RemoveQuotaForPattern(const nsACString& aPattern)
|
||||
{
|
||||
NS_ASSERTION(!aPattern.IsEmpty(), "Empty pattern!");
|
||||
|
||||
MutexAutoLock lock(mQuotaMutex);
|
||||
|
||||
mOriginInfos.Enumerate(RemoveQuotaForPatternCallback,
|
||||
const_cast<nsACString*>(&aPattern));
|
||||
}
|
||||
|
||||
already_AddRefed<QuotaObject>
|
||||
QuotaManager::GetQuotaObject(const nsACString& aOrigin,
|
||||
nsIFile* aFile)
|
||||
{
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
nsString path;
|
||||
nsresult rv = aFile->GetPath(path);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
int64_t fileSize;
|
||||
|
||||
bool exists;
|
||||
rv = aFile->Exists(&exists);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
if (exists) {
|
||||
rv = aFile->GetFileSize(&fileSize);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
}
|
||||
else {
|
||||
fileSize = 0;
|
||||
}
|
||||
|
||||
QuotaObject* info = nullptr;
|
||||
{
|
||||
MutexAutoLock lock(mQuotaMutex);
|
||||
|
||||
nsRefPtr<OriginInfo> originInfo;
|
||||
mOriginInfos.Get(aOrigin, getter_AddRefs(originInfo));
|
||||
|
||||
if (!originInfo) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
originInfo->mQuotaObjects.Get(path, &info);
|
||||
|
||||
if (!info) {
|
||||
info = new QuotaObject(originInfo, path, fileSize);
|
||||
originInfo->mQuotaObjects.Put(path, info);
|
||||
}
|
||||
}
|
||||
|
||||
nsRefPtr<QuotaObject> result = info;
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<QuotaObject>
|
||||
QuotaManager::GetQuotaObject(const nsACString& aOrigin,
|
||||
const nsAString& aPath)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIFile> file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
rv = file->InitWithPath(aPath);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
return GetQuotaObject(aOrigin, file);
|
||||
}
|
147
dom/quota/QuotaManager.h
Normal file
147
dom/quota/QuotaManager.h
Normal file
@ -0,0 +1,147 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_quota_quotamanager_h__
|
||||
#define mozilla_dom_quota_quotamanager_h__
|
||||
|
||||
#include "QuotaCommon.h"
|
||||
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
BEGIN_QUOTA_NAMESPACE
|
||||
|
||||
class OriginInfo;
|
||||
class QuotaManager;
|
||||
|
||||
class QuotaObject
|
||||
{
|
||||
friend class OriginInfo;
|
||||
friend class QuotaManager;
|
||||
|
||||
public:
|
||||
void
|
||||
AddRef();
|
||||
|
||||
void
|
||||
Release();
|
||||
|
||||
void
|
||||
UpdateSize(int64_t aSize);
|
||||
|
||||
bool
|
||||
MaybeAllocateMoreSpace(int64_t aOffset, int32_t aCount);
|
||||
|
||||
private:
|
||||
QuotaObject(OriginInfo* aOriginInfo, const nsAString& aPath, int64_t aSize)
|
||||
: mOriginInfo(aOriginInfo), mPath(aPath), mSize(aSize)
|
||||
{ }
|
||||
|
||||
virtual ~QuotaObject()
|
||||
{ }
|
||||
|
||||
nsAutoRefCnt mRefCnt;
|
||||
|
||||
OriginInfo* mOriginInfo;
|
||||
nsString mPath;
|
||||
int64_t mSize;
|
||||
};
|
||||
|
||||
class OriginInfo
|
||||
{
|
||||
friend class QuotaManager;
|
||||
friend class QuotaObject;
|
||||
|
||||
public:
|
||||
OriginInfo(const nsACString& aOrigin, int64_t aLimit, int64_t aUsage)
|
||||
: mOrigin(aOrigin), mLimit(aLimit), mUsage(aUsage)
|
||||
{
|
||||
mQuotaObjects.Init();
|
||||
}
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(OriginInfo)
|
||||
|
||||
private:
|
||||
void
|
||||
#ifdef DEBUG
|
||||
LockedClearOriginInfos();
|
||||
#else
|
||||
LockedClearOriginInfos()
|
||||
{
|
||||
mQuotaObjects.EnumerateRead(ClearOriginInfoCallback, nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
static PLDHashOperator
|
||||
ClearOriginInfoCallback(const nsAString& aKey,
|
||||
QuotaObject* aValue, void* aUserArg);
|
||||
|
||||
nsDataHashtable<nsStringHashKey, QuotaObject*> mQuotaObjects;
|
||||
|
||||
nsCString mOrigin;
|
||||
int64_t mLimit;
|
||||
int64_t mUsage;
|
||||
};
|
||||
|
||||
class QuotaManager
|
||||
{
|
||||
friend class nsAutoPtr<QuotaManager>;
|
||||
friend class OriginInfo;
|
||||
friend class QuotaObject;
|
||||
|
||||
public:
|
||||
// Returns a non-owning reference.
|
||||
static QuotaManager*
|
||||
GetOrCreate();
|
||||
|
||||
// Returns a non-owning reference.
|
||||
static QuotaManager*
|
||||
Get();
|
||||
|
||||
void
|
||||
InitQuotaForOrigin(const nsACString& aOrigin,
|
||||
int64_t aLimit,
|
||||
int64_t aUsage);
|
||||
|
||||
void
|
||||
DecreaseUsageForOrigin(const nsACString& aOrigin,
|
||||
int64_t aSize);
|
||||
|
||||
void
|
||||
RemoveQuotaForPattern(const nsACString& aPattern);
|
||||
|
||||
already_AddRefed<QuotaObject>
|
||||
GetQuotaObject(const nsACString& aOrigin,
|
||||
nsIFile* aFile);
|
||||
|
||||
already_AddRefed<QuotaObject>
|
||||
GetQuotaObject(const nsACString& aOrigin,
|
||||
const nsAString& aPath);
|
||||
|
||||
private:
|
||||
QuotaManager()
|
||||
: mQuotaMutex("QuotaManager.mQuotaMutex")
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
mOriginInfos.Init();
|
||||
}
|
||||
|
||||
virtual ~QuotaManager()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
}
|
||||
|
||||
mozilla::Mutex mQuotaMutex;
|
||||
|
||||
nsRefPtrHashtable<nsCStringHashKey, OriginInfo> mOriginInfos;
|
||||
};
|
||||
|
||||
END_QUOTA_NAMESPACE
|
||||
|
||||
#endif /* mozilla_dom_quota_quotamanager_h__ */
|
@ -69,6 +69,7 @@ SHARED_LIBRARY_LIBS = \
|
||||
$(DEPTH)/dom/encoding/$(LIB_PREFIX)domencoding_s.$(LIB_SUFFIX) \
|
||||
$(DEPTH)/dom/file/$(LIB_PREFIX)domfile_s.$(LIB_SUFFIX) \
|
||||
$(DEPTH)/dom/power/$(LIB_PREFIX)dom_power_s.$(LIB_SUFFIX) \
|
||||
$(DEPTH)/dom/quota/$(LIB_PREFIX)domquota_s.$(LIB_SUFFIX) \
|
||||
$(DEPTH)/dom/settings/$(LIB_PREFIX)jsdomsettings_s.$(LIB_SUFFIX) \
|
||||
$(DEPTH)/dom/permission/$(LIB_PREFIX)jsdompermissionsettings_s.$(LIB_SUFFIX) \
|
||||
$(DEPTH)/dom/network/src/$(LIB_PREFIX)dom_network_s.$(LIB_SUFFIX) \
|
||||
|
@ -19,6 +19,7 @@ LIBXUL_LIBRARY = 1
|
||||
EXPORTS = \
|
||||
nsMIMEInputStream.h \
|
||||
nsURLHelper.h \
|
||||
nsFileStreams.h \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS_NAMESPACES = mozilla/net
|
||||
|
@ -51,7 +51,9 @@ nsFileStreamBase::~nsFileStreamBase()
|
||||
Close();
|
||||
}
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsFileStreamBase, nsISeekableStream)
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS2(nsFileStreamBase,
|
||||
nsISeekableStream,
|
||||
nsIFileMetadata)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFileStreamBase::Seek(int32_t whence, int64_t offset)
|
||||
@ -124,6 +126,52 @@ nsFileStreamBase::SetEOF()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFileStreamBase::GetSize(int64_t* _retval)
|
||||
{
|
||||
nsresult rv = DoPendingOpen();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!mFD) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
PRFileInfo64 info;
|
||||
if (PR_GetOpenFileInfo64(mFD, &info) == PR_FAILURE) {
|
||||
return NS_BASE_STREAM_OSERROR;
|
||||
}
|
||||
|
||||
*_retval = int64_t(info.size);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFileStreamBase::GetLastModified(int64_t* _retval)
|
||||
{
|
||||
nsresult rv = DoPendingOpen();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!mFD) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
PRFileInfo64 info;
|
||||
if (PR_GetOpenFileInfo64(mFD, &info) == PR_FAILURE) {
|
||||
return NS_BASE_STREAM_OSERROR;
|
||||
}
|
||||
|
||||
int64_t modTime = int64_t(info.modifyTime);
|
||||
if (modTime == 0) {
|
||||
*_retval = 0;
|
||||
}
|
||||
else {
|
||||
*_retval = modTime / int64_t(PR_USEC_PER_MSEC);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFileStreamBase::Close()
|
||||
{
|
||||
@ -934,13 +982,12 @@ nsSafeFileOutputStream::Write(const char *buf, uint32_t count, uint32_t *result)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsFileStream
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED4(nsFileStream,
|
||||
NS_IMPL_ISUPPORTS_INHERITED3(nsFileStream,
|
||||
nsFileStreamBase,
|
||||
nsIInputStream,
|
||||
nsIOutputStream,
|
||||
nsIFileStream,
|
||||
nsIFileMetadata)
|
||||
|
||||
nsIFileStream)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFileStream::Init(nsIFile* file, int32_t ioFlags, int32_t perm,
|
||||
int32_t behaviorFlags)
|
||||
@ -959,50 +1006,4 @@ nsFileStream::Init(nsIFile* file, int32_t ioFlags, int32_t perm,
|
||||
mBehaviorFlags & nsIFileStream::DEFER_OPEN);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFileStream::GetSize(int64_t* _retval)
|
||||
{
|
||||
nsresult rv = DoPendingOpen();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!mFD) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
PRFileInfo64 info;
|
||||
if (PR_GetOpenFileInfo64(mFD, &info) == PR_FAILURE) {
|
||||
return NS_BASE_STREAM_OSERROR;
|
||||
}
|
||||
|
||||
*_retval = int64_t(info.size);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFileStream::GetLastModified(int64_t* _retval)
|
||||
{
|
||||
nsresult rv = DoPendingOpen();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!mFD) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
PRFileInfo64 info;
|
||||
if (PR_GetOpenFileInfo64(mFD, &info) == PR_FAILURE) {
|
||||
return NS_BASE_STREAM_OSERROR;
|
||||
}
|
||||
|
||||
int64_t modTime = int64_t(info.modifyTime);
|
||||
if (modTime == 0) {
|
||||
*_retval = 0;
|
||||
}
|
||||
else {
|
||||
*_retval = modTime / int64_t(PR_USEC_PER_MSEC);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -24,11 +24,13 @@
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class nsFileStreamBase : public nsISeekableStream
|
||||
class nsFileStreamBase : public nsISeekableStream,
|
||||
public nsIFileMetadata
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISEEKABLESTREAM
|
||||
NS_DECL_NSIFILEMETADATA
|
||||
|
||||
nsFileStreamBase();
|
||||
virtual ~nsFileStreamBase();
|
||||
@ -124,8 +126,8 @@ public:
|
||||
NS_IMETHOD IsNonBlocking(bool* _retval)
|
||||
{
|
||||
return nsFileStreamBase::IsNonBlocking(_retval);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Overrided from nsFileStreamBase
|
||||
NS_IMETHOD Seek(int32_t aWhence, int64_t aOffset);
|
||||
|
||||
@ -260,13 +262,11 @@ protected:
|
||||
class nsFileStream : public nsFileStreamBase,
|
||||
public nsIInputStream,
|
||||
public nsIOutputStream,
|
||||
public nsIFileStream,
|
||||
public nsIFileMetadata
|
||||
public nsIFileStream
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIFILESTREAM
|
||||
NS_DECL_NSIFILEMETADATA
|
||||
NS_FORWARD_NSIINPUTSTREAM(nsFileStreamBase::)
|
||||
|
||||
// Can't use NS_FORWARD_NSIOUTPUTSTREAM due to overlapping methods
|
||||
|
@ -36,7 +36,6 @@ XPIDLSRCS = \
|
||||
mozIStorageCompletionCallback.idl \
|
||||
mozIStorageBaseStatement.idl \
|
||||
mozIStorageAsyncStatement.idl \
|
||||
mozIStorageServiceQuotaManagement.idl \
|
||||
mozIStorageVacuumParticipant.idl \
|
||||
$(NULL)
|
||||
# SEE ABOVE NOTE!
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
interface mozIStorageConnection;
|
||||
interface nsIFile;
|
||||
interface nsIFileURL;
|
||||
|
||||
/**
|
||||
* The mozIStorageService interface is intended to be implemented by
|
||||
@ -15,7 +16,7 @@ interface nsIFile;
|
||||
*
|
||||
* This is the only way to open a database connection.
|
||||
*/
|
||||
[scriptable, uuid(fe8e95cb-b377-4c8d-bccb-d9198c67542b)]
|
||||
[scriptable, uuid(12bfad34-cca3-40fb-8736-d8bf9db61a27)]
|
||||
interface mozIStorageService : nsISupports {
|
||||
/**
|
||||
* Get a connection to a named special database storage.
|
||||
@ -106,6 +107,16 @@ interface mozIStorageService : nsISupports {
|
||||
*/
|
||||
mozIStorageConnection openUnsharedDatabase(in nsIFile aDatabaseFile);
|
||||
|
||||
/**
|
||||
* See openDatabase(). Exactly the same only initialized with a file URL.
|
||||
* Custom parameters can be passed to SQLite and VFS implementations through
|
||||
* the query part of the URL.
|
||||
*
|
||||
* @param aURL
|
||||
* A nsIFileURL that represents the database that is to be opened.
|
||||
*/
|
||||
mozIStorageConnection openDatabaseWithFileURL(in nsIFileURL aFileURL);
|
||||
|
||||
/*
|
||||
* Utilities
|
||||
*/
|
||||
|
@ -1,99 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface mozIStorageConnection;
|
||||
interface nsIFile;
|
||||
|
||||
[scriptable, function, uuid(ae94f0a5-ebdf-48f4-9959-085e13235d8d)]
|
||||
interface mozIStorageQuotaCallback : nsISupports
|
||||
{
|
||||
/**
|
||||
* Called when the file size quota for a group of databases is exceeded.
|
||||
*
|
||||
* @param aFilename
|
||||
* The filename of the database that has exceeded the quota.
|
||||
*
|
||||
* @param aCurrentSizeLimit
|
||||
* The current size (in bytes) of the quota.
|
||||
*
|
||||
* @param aCurrentTotalSize
|
||||
* The current size of all databases in the quota group.
|
||||
*
|
||||
* @param aUserData
|
||||
* Any additional data that was provided to the
|
||||
* setQuotaForFilenamePattern function.
|
||||
*
|
||||
* @returns A new quota size. A new quota of 0 will disable the quota callback
|
||||
* and any quota value less than aCurrentTotalSize will cause the
|
||||
* database operation to fail with NS_ERROR_FILE_NO_DEVICE_SPACE.
|
||||
*/
|
||||
long long quotaExceeded(in ACString aFilename,
|
||||
in long long aCurrentSizeLimit,
|
||||
in long long aCurrentTotalSize,
|
||||
in nsISupports aUserData);
|
||||
};
|
||||
|
||||
/**
|
||||
* This is a temporary interface that should eventually merge with
|
||||
* mozIStorageService.
|
||||
*/
|
||||
[scriptable, uuid(4d81faf5-fe01-428b-99b8-c94cba12fd72)]
|
||||
interface mozIStorageServiceQuotaManagement : nsISupports
|
||||
{
|
||||
/**
|
||||
* See mozIStorageService.openDatabase. Exactly the same only with a custom
|
||||
* SQLite VFS.
|
||||
*/
|
||||
mozIStorageConnection openDatabaseWithVFS(in nsIFile aDatabaseFile,
|
||||
in ACString aVFSName);
|
||||
|
||||
/**
|
||||
* Set a file size quota for a group of databases matching the given filename
|
||||
* pattern, optionally specifying a callback when the quota is exceeded.
|
||||
*
|
||||
* @param aPattern
|
||||
* A pattern to match filenames for inclusion in the quota system. May
|
||||
* contain the following special characters:
|
||||
* '*' Matches any sequence of zero or more characters.
|
||||
* '?' Matches exactly one character.
|
||||
* [...] Matches one character from the enclosed list of characters.
|
||||
* [^...] Matches one character not in the enclosed list.
|
||||
*
|
||||
* @param aSizeLimit
|
||||
* The size limit (in bytes) for the quota group.
|
||||
*
|
||||
* @param aCallback
|
||||
* A callback that will be used when the quota is exceeded.
|
||||
*
|
||||
* @param aUserData
|
||||
* Additional information to be passed to the callback.
|
||||
*/
|
||||
void setQuotaForFilenamePattern(in ACString aPattern,
|
||||
in long long aSizeLimit,
|
||||
in mozIStorageQuotaCallback aCallback,
|
||||
in nsISupports aUserData);
|
||||
|
||||
/**
|
||||
* Adds, removes, or updates the file size information maintained by the quota
|
||||
* system for files not opened through openDatabaseWithVFS().
|
||||
*
|
||||
* Use this function when you want files to be included in quota calculations
|
||||
* that are either a) not SQLite databases, or b) SQLite databases that have
|
||||
* not been opened.
|
||||
*
|
||||
* This function will have no effect on files that do not match an existing
|
||||
* quota pattern (set previously by setQuotaForFilenamePattern()).
|
||||
*
|
||||
* @param aFile
|
||||
* The file for which quota information should be updated. If the file
|
||||
* exists then its size information will be added or refreshed. If the
|
||||
* file does not exist then the file will be removed from tracking
|
||||
* under the quota system.
|
||||
*/
|
||||
void updateQuotaInformationForFile(in nsIFile aFile);
|
||||
};
|
@ -24,7 +24,6 @@
|
||||
#include "mozIStorageStatementCallback.h"
|
||||
#include "mozIStorageBindingParamsArray.h"
|
||||
#include "mozIStorageBindingParams.h"
|
||||
#include "mozIStorageServiceQuotaManagement.h"
|
||||
#include "mozIStorageVacuumParticipant.h"
|
||||
#include "mozIStorageCompletionCallback.h"
|
||||
#include "mozIStorageAsyncStatement.h"
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "sqlite3.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/Util.h"
|
||||
#include "mozilla/dom/quota/QuotaManager.h"
|
||||
|
||||
/**
|
||||
* This preference is a workaround to allow users/sysadmins to identify
|
||||
@ -24,6 +25,7 @@
|
||||
namespace {
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom::quota;
|
||||
|
||||
struct Histograms {
|
||||
const char *name;
|
||||
@ -82,9 +84,17 @@ private:
|
||||
};
|
||||
|
||||
struct telemetry_file {
|
||||
sqlite3_file base; // Base class. Must be first
|
||||
Histograms *histograms; // histograms pertaining to this file
|
||||
sqlite3_file pReal[1]; // This contains the vfs that actually does work
|
||||
// Base class. Must be first
|
||||
sqlite3_file base;
|
||||
|
||||
// histograms pertaining to this file
|
||||
Histograms *histograms;
|
||||
|
||||
// quota object for this file
|
||||
nsRefPtr<QuotaObject> quotaObject;
|
||||
|
||||
// This contains the vfs that actually does work
|
||||
sqlite3_file pReal[1];
|
||||
};
|
||||
|
||||
/*
|
||||
@ -99,6 +109,7 @@ xClose(sqlite3_file *pFile)
|
||||
if( rc==SQLITE_OK ){
|
||||
delete p->base.pMethods;
|
||||
p->base.pMethods = NULL;
|
||||
p->quotaObject = nullptr;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@ -126,6 +137,9 @@ int
|
||||
xWrite(sqlite3_file *pFile, const void *zBuf, int iAmt, sqlite_int64 iOfst)
|
||||
{
|
||||
telemetry_file *p = (telemetry_file *)pFile;
|
||||
if (p->quotaObject && !p->quotaObject->MaybeAllocateMoreSpace(iOfst, iAmt)) {
|
||||
return SQLITE_FULL;
|
||||
}
|
||||
IOThreadAutoTimer ioTimer(p->histograms->writeMS);
|
||||
int rc;
|
||||
rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst);
|
||||
@ -144,6 +158,9 @@ xTruncate(sqlite3_file *pFile, sqlite_int64 size)
|
||||
int rc;
|
||||
Telemetry::AutoTimer<Telemetry::MOZ_SQLITE_TRUNCATE_MS> timer;
|
||||
rc = p->pReal->pMethods->xTruncate(p->pReal, size);
|
||||
if (rc == SQLITE_OK && p->quotaObject) {
|
||||
p->quotaObject->UpdateSize(size);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -300,6 +317,18 @@ xOpen(sqlite3_vfs* vfs, const char *zName, sqlite3_file* pFile,
|
||||
break;
|
||||
}
|
||||
p->histograms = h;
|
||||
|
||||
const char* origin;
|
||||
if ((flags & SQLITE_OPEN_URI) &&
|
||||
(origin = sqlite3_uri_parameter(zName, "origin"))) {
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
MOZ_ASSERT(quotaManager);
|
||||
|
||||
p->quotaObject = quotaManager->GetQuotaObject(nsDependentCString(origin),
|
||||
NS_ConvertUTF8toUTF16(zName));
|
||||
|
||||
}
|
||||
|
||||
rc = orig_vfs->xOpen(orig_vfs, zName, p->pReal, flags, pOutFlags);
|
||||
if( rc != SQLITE_OK )
|
||||
return rc;
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "nsIMemoryReporter.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIFileURL.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/CondVar.h"
|
||||
@ -471,34 +472,83 @@ Connection::getAsyncExecutionTarget()
|
||||
}
|
||||
|
||||
nsresult
|
||||
Connection::initialize(nsIFile *aDatabaseFile,
|
||||
const char* aVFSName)
|
||||
Connection::initialize()
|
||||
{
|
||||
NS_ASSERTION (!mDBConn, "Initialize called on already opened database!");
|
||||
SAMPLE_LABEL("storage", "Connection::initialize");
|
||||
|
||||
int srv;
|
||||
nsresult rv;
|
||||
|
||||
mDatabaseFile = aDatabaseFile;
|
||||
|
||||
if (aDatabaseFile) {
|
||||
nsAutoString path;
|
||||
rv = aDatabaseFile->GetPath(path);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
srv = ::sqlite3_open_v2(NS_ConvertUTF16toUTF8(path).get(), &mDBConn, mFlags,
|
||||
aVFSName);
|
||||
}
|
||||
else {
|
||||
// in memory database requested, sqlite uses a magic file name
|
||||
srv = ::sqlite3_open_v2(":memory:", &mDBConn, mFlags, aVFSName);
|
||||
}
|
||||
// in memory database requested, sqlite uses a magic file name
|
||||
int srv = ::sqlite3_open_v2(":memory:", &mDBConn, mFlags, NULL);
|
||||
if (srv != SQLITE_OK) {
|
||||
mDBConn = nullptr;
|
||||
return convertResultCode(srv);
|
||||
}
|
||||
|
||||
return initializeInternal(nullptr);
|
||||
}
|
||||
|
||||
nsresult
|
||||
Connection::initialize(nsIFile *aDatabaseFile)
|
||||
{
|
||||
NS_ASSERTION (aDatabaseFile, "Passed null file!");
|
||||
NS_ASSERTION (!mDBConn, "Initialize called on already opened database!");
|
||||
SAMPLE_LABEL("storage", "Connection::initialize");
|
||||
|
||||
mDatabaseFile = aDatabaseFile;
|
||||
|
||||
nsAutoString path;
|
||||
nsresult rv = aDatabaseFile->GetPath(path);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
int srv = ::sqlite3_open_v2(NS_ConvertUTF16toUTF8(path).get(), &mDBConn,
|
||||
mFlags, NULL);
|
||||
if (srv != SQLITE_OK) {
|
||||
mDBConn = nullptr;
|
||||
return convertResultCode(srv);
|
||||
}
|
||||
|
||||
rv = initializeInternal(aDatabaseFile);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mDatabaseFile = aDatabaseFile;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Connection::initialize(nsIFileURL *aFileURL)
|
||||
{
|
||||
NS_ASSERTION (aFileURL, "Passed null file URL!");
|
||||
NS_ASSERTION (!mDBConn, "Initialize called on already opened database!");
|
||||
SAMPLE_LABEL("storage", "Connection::initialize");
|
||||
|
||||
nsCOMPtr<nsIFile> databaseFile;
|
||||
nsresult rv = aFileURL->GetFile(getter_AddRefs(databaseFile));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoCString spec;
|
||||
rv = aFileURL->GetSpec(spec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
int srv = ::sqlite3_open_v2(spec.get(), &mDBConn, mFlags, NULL);
|
||||
if (srv != SQLITE_OK) {
|
||||
mDBConn = nullptr;
|
||||
return convertResultCode(srv);
|
||||
}
|
||||
|
||||
rv = initializeInternal(databaseFile);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mFileURL = aFileURL;
|
||||
mDatabaseFile = databaseFile;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
Connection::initializeInternal(nsIFile* aDatabaseFile)
|
||||
{
|
||||
// Properly wrap the database handle's mutex.
|
||||
sharedDBMutex.initWithMutex(sqlite3_db_mutex(mDBConn));
|
||||
|
||||
@ -522,14 +572,14 @@ Connection::initialize(nsIFile *aDatabaseFile,
|
||||
nsAutoCString pageSizeQuery(MOZ_STORAGE_UNIQUIFY_QUERY_STR
|
||||
"PRAGMA page_size = ");
|
||||
pageSizeQuery.AppendInt(pageSize);
|
||||
rv = ExecuteSimpleSQL(pageSizeQuery);
|
||||
nsresult rv = ExecuteSimpleSQL(pageSizeQuery);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Get the current page_size, since it may differ from the specified value.
|
||||
sqlite3_stmt *stmt;
|
||||
NS_NAMED_LITERAL_CSTRING(pragma_page_size,
|
||||
MOZ_STORAGE_UNIQUIFY_QUERY_STR "PRAGMA page_size");
|
||||
srv = prepareStatement(pragma_page_size, &stmt);
|
||||
int srv = prepareStatement(pragma_page_size, &stmt);
|
||||
if (srv == SQLITE_OK) {
|
||||
if (SQLITE_ROW == stepStatement(stmt)) {
|
||||
pageSize = ::sqlite3_column_int64(stmt, 0);
|
||||
@ -962,7 +1012,8 @@ Connection::Clone(bool aReadOnly,
|
||||
nsRefPtr<Connection> clone = new Connection(mStorageService, flags);
|
||||
NS_ENSURE_TRUE(clone, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsresult rv = clone->initialize(mDatabaseFile);
|
||||
nsresult rv = mFileURL ? clone->initialize(mFileURL)
|
||||
: clone->initialize(mDatabaseFile);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Copy over pragmas from the original connection.
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
struct PRLock;
|
||||
class nsIFile;
|
||||
class nsIFileURL;
|
||||
class nsIEventTarget;
|
||||
class nsIThread;
|
||||
|
||||
@ -62,19 +63,28 @@ public:
|
||||
*/
|
||||
Connection(Service *aService, int aFlags);
|
||||
|
||||
/**
|
||||
* Creates the connection to an in-memory database.
|
||||
*/
|
||||
nsresult initialize();
|
||||
|
||||
/**
|
||||
* Creates the connection to the database.
|
||||
*
|
||||
* @param aDatabaseFile
|
||||
* The nsIFile of the location of the database to open, or create if it
|
||||
* does not exist. Passing in nullptr here creates an in-memory
|
||||
* database.
|
||||
* @param aVFSName
|
||||
* The VFS that SQLite will use when opening this database. NULL means
|
||||
* "default".
|
||||
* does not exist.
|
||||
*/
|
||||
nsresult initialize(nsIFile *aDatabaseFile,
|
||||
const char* aVFSName = NULL);
|
||||
nsresult initialize(nsIFile *aDatabaseFile);
|
||||
|
||||
/**
|
||||
* Creates the connection to the database.
|
||||
*
|
||||
* @param aFileURL
|
||||
* The nsIFileURL of the location of the database to open, or create if it
|
||||
* does not exist.
|
||||
*/
|
||||
nsresult initialize(nsIFileURL *aFileURL);
|
||||
|
||||
// fetch the native handle
|
||||
sqlite3 *GetNativeConnection() { return mDBConn; }
|
||||
@ -155,6 +165,8 @@ public:
|
||||
private:
|
||||
~Connection();
|
||||
|
||||
nsresult initializeInternal(nsIFile *aDatabaseFile);
|
||||
|
||||
/**
|
||||
* Sets the database into a closed state so no further actions can be
|
||||
* performed.
|
||||
@ -206,6 +218,7 @@ private:
|
||||
int progressHandler();
|
||||
|
||||
sqlite3 *mDBConn;
|
||||
nsCOMPtr<nsIFileURL> mFileURL;
|
||||
nsCOMPtr<nsIFile> mDatabaseFile;
|
||||
|
||||
/**
|
||||
|
@ -24,8 +24,6 @@
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
#include "sqlite3.h"
|
||||
#include "test_quota.h"
|
||||
#include "test_quota.c"
|
||||
|
||||
#ifdef SQLITE_OS_WIN
|
||||
// "windows.h" was included and it can #define lots of things we care about...
|
||||
@ -35,61 +33,6 @@
|
||||
#include "nsIPromptService.h"
|
||||
#include "nsIMemoryReporter.h"
|
||||
|
||||
namespace {
|
||||
|
||||
class QuotaCallbackData
|
||||
{
|
||||
public:
|
||||
QuotaCallbackData(mozIStorageQuotaCallback *aCallback,
|
||||
nsISupports *aUserData)
|
||||
: callback(aCallback), userData(aUserData)
|
||||
{
|
||||
MOZ_COUNT_CTOR(QuotaCallbackData);
|
||||
}
|
||||
|
||||
~QuotaCallbackData()
|
||||
{
|
||||
MOZ_COUNT_DTOR(QuotaCallbackData);
|
||||
}
|
||||
|
||||
static void Callback(const char *zFilename,
|
||||
sqlite3_int64 *piLimit,
|
||||
sqlite3_int64 iSize,
|
||||
void *pArg)
|
||||
{
|
||||
NS_ASSERTION(zFilename && strlen(zFilename), "Null or empty filename!");
|
||||
NS_ASSERTION(piLimit, "Null pointer!");
|
||||
|
||||
QuotaCallbackData *data = static_cast<QuotaCallbackData*>(pArg);
|
||||
if (!data) {
|
||||
// No callback specified, return immediately.
|
||||
return;
|
||||
}
|
||||
|
||||
NS_ASSERTION(data->callback, "Should never have a null callback!");
|
||||
|
||||
nsDependentCString filename(zFilename);
|
||||
|
||||
int64_t newLimit;
|
||||
if (NS_SUCCEEDED(data->callback->QuotaExceeded(filename, *piLimit,
|
||||
iSize, data->userData,
|
||||
&newLimit))) {
|
||||
*piLimit = newLimit;
|
||||
}
|
||||
}
|
||||
|
||||
static void Destroy(void *aUserData)
|
||||
{
|
||||
delete static_cast<QuotaCallbackData*>(aUserData);
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<mozIStorageQuotaCallback> callback;
|
||||
nsCOMPtr<nsISupports> userData;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Defines
|
||||
|
||||
@ -345,11 +288,10 @@ private:
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Service
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS3(
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS2(
|
||||
Service,
|
||||
mozIStorageService,
|
||||
nsIObserver,
|
||||
mozIStorageServiceQuotaManagement
|
||||
nsIObserver
|
||||
)
|
||||
|
||||
Service *Service::gService = nullptr;
|
||||
@ -438,10 +380,6 @@ Service::~Service()
|
||||
|
||||
// Shutdown the sqlite3 API. Warn if shutdown did not turn out okay, but
|
||||
// there is nothing actionable we can do in that case.
|
||||
rc = ::sqlite3_quota_shutdown();
|
||||
if (rc != SQLITE_OK)
|
||||
NS_WARNING("sqlite3 did not shutdown cleanly.");
|
||||
|
||||
rc = ::sqlite3_shutdown();
|
||||
if (rc != SQLITE_OK)
|
||||
NS_WARNING("sqlite3 did not shutdown cleanly.");
|
||||
@ -636,9 +574,6 @@ Service::initialize()
|
||||
} else {
|
||||
NS_WARNING("Failed to register telemetry VFS");
|
||||
}
|
||||
rc = ::sqlite3_quota_initialize("telemetry-vfs", 0);
|
||||
if (rc != SQLITE_OK)
|
||||
return convertResultCode(rc);
|
||||
|
||||
// Set the default value for the toolkit.storage.synchronous pref. It will be
|
||||
// updated with the user preference on the main thread.
|
||||
@ -739,28 +674,24 @@ Service::OpenSpecialDatabase(const char *aStorageKey,
|
||||
// connection to use a memory DB.
|
||||
}
|
||||
else if (::strcmp(aStorageKey, "profile") == 0) {
|
||||
|
||||
rv = NS_GetSpecialDirectory(NS_APP_STORAGE_50_FILE,
|
||||
getter_AddRefs(storageFile));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsString filename;
|
||||
storageFile->GetPath(filename);
|
||||
nsCString filename8 = NS_ConvertUTF16toUTF8(filename.get());
|
||||
// fall through to DB initialization
|
||||
}
|
||||
else {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
Connection *msc = new Connection(this, SQLITE_OPEN_READWRITE);
|
||||
NS_ENSURE_TRUE(msc, NS_ERROR_OUT_OF_MEMORY);
|
||||
nsRefPtr<Connection> msc = new Connection(this, SQLITE_OPEN_READWRITE);
|
||||
|
||||
rv = msc->initialize(storageFile);
|
||||
rv = storageFile ? msc->initialize(storageFile) : msc->initialize();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ADDREF(*_connection = msc);
|
||||
msc.forget(_connection);
|
||||
return NS_OK;
|
||||
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -774,12 +705,11 @@ Service::OpenDatabase(nsIFile *aDatabaseFile,
|
||||
int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_SHAREDCACHE |
|
||||
SQLITE_OPEN_CREATE;
|
||||
nsRefPtr<Connection> msc = new Connection(this, flags);
|
||||
NS_ENSURE_TRUE(msc, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsresult rv = msc->initialize(aDatabaseFile);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ADDREF(*_connection = msc);
|
||||
msc.forget(_connection);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -794,12 +724,30 @@ Service::OpenUnsharedDatabase(nsIFile *aDatabaseFile,
|
||||
int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_PRIVATECACHE |
|
||||
SQLITE_OPEN_CREATE;
|
||||
nsRefPtr<Connection> msc = new Connection(this, flags);
|
||||
NS_ENSURE_TRUE(msc, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsresult rv = msc->initialize(aDatabaseFile);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ADDREF(*_connection = msc);
|
||||
msc.forget(_connection);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Service::OpenDatabaseWithFileURL(nsIFileURL *aFileURL,
|
||||
mozIStorageConnection **_connection)
|
||||
{
|
||||
NS_ENSURE_ARG(aFileURL);
|
||||
|
||||
// Always ensure that SQLITE_OPEN_CREATE is passed in for compatibility
|
||||
// reasons.
|
||||
int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_SHAREDCACHE |
|
||||
SQLITE_OPEN_CREATE | SQLITE_OPEN_URI;
|
||||
nsRefPtr<Connection> msc = new Connection(this, flags);
|
||||
|
||||
nsresult rv = msc->initialize(aFileURL);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
msc.forget(_connection);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -885,67 +833,5 @@ Service::Observe(nsISupports *, const char *aTopic, const PRUnichar *)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// mozIStorageServiceQuotaManagement
|
||||
|
||||
NS_IMETHODIMP
|
||||
Service::OpenDatabaseWithVFS(nsIFile *aDatabaseFile,
|
||||
const nsACString &aVFSName,
|
||||
mozIStorageConnection **_connection)
|
||||
{
|
||||
NS_ENSURE_ARG(aDatabaseFile);
|
||||
|
||||
// Always ensure that SQLITE_OPEN_CREATE is passed in for compatibility
|
||||
// reasons.
|
||||
int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_SHAREDCACHE |
|
||||
SQLITE_OPEN_CREATE;
|
||||
nsRefPtr<Connection> msc = new Connection(this, flags);
|
||||
NS_ENSURE_TRUE(msc, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsresult rv = msc->initialize(aDatabaseFile,
|
||||
PromiseFlatCString(aVFSName).get());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ADDREF(*_connection = msc);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Service::SetQuotaForFilenamePattern(const nsACString &aPattern,
|
||||
int64_t aSizeLimit,
|
||||
mozIStorageQuotaCallback *aCallback,
|
||||
nsISupports *aUserData)
|
||||
{
|
||||
NS_ENSURE_FALSE(aPattern.IsEmpty(), NS_ERROR_INVALID_ARG);
|
||||
|
||||
nsAutoPtr<QuotaCallbackData> data;
|
||||
if (aSizeLimit && aCallback) {
|
||||
data = new QuotaCallbackData(aCallback, aUserData);
|
||||
}
|
||||
|
||||
int rc = ::sqlite3_quota_set(PromiseFlatCString(aPattern).get(),
|
||||
aSizeLimit, QuotaCallbackData::Callback,
|
||||
data, QuotaCallbackData::Destroy);
|
||||
NS_ENSURE_TRUE(rc == SQLITE_OK, convertResultCode(rc));
|
||||
|
||||
data.forget();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Service::UpdateQuotaInformationForFile(nsIFile *aFile)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aFile);
|
||||
|
||||
nsString path;
|
||||
nsresult rv = aFile->GetPath(path);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
int rc = ::sqlite3_quota_file(NS_ConvertUTF16toUTF8(path).get());
|
||||
NS_ENSURE_TRUE(rc == SQLITE_OK, convertResultCode(rc));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace storage
|
||||
} // namespace mozilla
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include "mozilla/Mutex.h"
|
||||
|
||||
#include "mozIStorageService.h"
|
||||
#include "mozIStorageServiceQuotaManagement.h"
|
||||
|
||||
class nsIMemoryReporter;
|
||||
class nsIMemoryMultiReporter;
|
||||
@ -28,7 +27,6 @@ namespace storage {
|
||||
class Connection;
|
||||
class Service : public mozIStorageService
|
||||
, public nsIObserver
|
||||
, public mozIStorageServiceQuotaManagement
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@ -58,7 +56,6 @@ public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_MOZISTORAGESERVICE
|
||||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_MOZISTORAGESERVICEQUOTAMANAGEMENT
|
||||
|
||||
/**
|
||||
* Obtains an already AddRefed pointer to XPConnect. This is used by
|
||||
|
@ -68,6 +68,7 @@ MAKEFILES_dom="
|
||||
dom/plugins/base/Makefile
|
||||
dom/plugins/ipc/Makefile
|
||||
dom/power/Makefile
|
||||
dom/quota/Makefile
|
||||
dom/settings/Makefile
|
||||
dom/sms/Makefile
|
||||
dom/sms/interfaces/Makefile
|
||||
|
Loading…
Reference in New Issue
Block a user