summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/platform/sql
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2011-05-18 13:36:51 +0100
committerSteve Block <steveblock@google.com>2011-05-24 15:38:28 +0100
commit2fc2651226baac27029e38c9d6ef883fa32084db (patch)
treee396d4bf89dcce6ed02071be66212495b1df1dec /Source/WebCore/platform/sql
parentb3725cedeb43722b3b175aaeff70552e562d2c94 (diff)
downloadexternal_webkit-2fc2651226baac27029e38c9d6ef883fa32084db.zip
external_webkit-2fc2651226baac27029e38c9d6ef883fa32084db.tar.gz
external_webkit-2fc2651226baac27029e38c9d6ef883fa32084db.tar.bz2
Merge WebKit at r78450: Initial merge by git.
Change-Id: I6d3e5f1f868ec266a0aafdef66182ddc3f265dc1
Diffstat (limited to 'Source/WebCore/platform/sql')
-rw-r--r--Source/WebCore/platform/sql/SQLiteStatement.cpp40
-rw-r--r--Source/WebCore/platform/sql/SQLiteStatement.h2
-rw-r--r--Source/WebCore/platform/sql/chromium/SQLiteFileSystemChromiumPosix.cpp1081
3 files changed, 85 insertions, 1038 deletions
diff --git a/Source/WebCore/platform/sql/SQLiteStatement.cpp b/Source/WebCore/platform/sql/SQLiteStatement.cpp
index af9518a..d9186dc 100644
--- a/Source/WebCore/platform/sql/SQLiteStatement.cpp
+++ b/Source/WebCore/platform/sql/SQLiteStatement.cpp
@@ -176,6 +176,20 @@ int SQLiteStatement::bindBlob(int index, const void* blob, int size)
return sqlite3_bind_blob(m_statement, index, blob, size, SQLITE_TRANSIENT);
}
+int SQLiteStatement::bindBlob(int index, const String& text)
+{
+ // String::characters() returns 0 for the empty string, which SQLite
+ // treats as a null, so we supply a non-null pointer for that case.
+ UChar anyCharacter = 0;
+ const UChar* characters;
+ if (text.isEmpty() && !text.isNull())
+ characters = &anyCharacter;
+ else
+ characters = text.characters();
+
+ return bindBlob(index, characters, text.length() * sizeof(UChar));
+}
+
int SQLiteStatement::bindText(int index, const String& text)
{
ASSERT(m_isPrepared);
@@ -355,7 +369,29 @@ int64_t SQLiteStatement::getColumnInt64(int col)
return 0;
return sqlite3_column_int64(m_statement, col);
}
-
+
+String SQLiteStatement::getColumnBlobAsString(int col)
+{
+ ASSERT(col >= 0);
+
+ if (!m_statement && prepareAndStep() != SQLITE_ROW)
+ return String();
+
+ if (columnCount() <= col)
+ return String();
+
+ const void* blob = sqlite3_column_blob(m_statement, col);
+ if (!blob)
+ return String();
+
+ int size = sqlite3_column_bytes(m_statement, col);
+ if (size < 0)
+ return String();
+
+ ASSERT(!(size % sizeof(UChar)));
+ return String(static_cast<const UChar*>(blob), size / sizeof(UChar));
+}
+
void SQLiteStatement::getColumnBlobAsVector(int col, Vector<char>& result)
{
ASSERT(col >= 0);
@@ -379,7 +415,7 @@ void SQLiteStatement::getColumnBlobAsVector(int col, Vector<char>& result)
int size = sqlite3_column_bytes(m_statement, col);
result.resize((size_t)size);
for (int i = 0; i < size; ++i)
- result[i] = ((const unsigned char*)blob)[i];
+ result[i] = (static_cast<const unsigned char*>(blob))[i];
}
const void* SQLiteStatement::getColumnBlob(int col, int& size)
diff --git a/Source/WebCore/platform/sql/SQLiteStatement.h b/Source/WebCore/platform/sql/SQLiteStatement.h
index fd1abfb..35dcecf 100644
--- a/Source/WebCore/platform/sql/SQLiteStatement.h
+++ b/Source/WebCore/platform/sql/SQLiteStatement.h
@@ -42,6 +42,7 @@ public:
int prepare();
int bindBlob(int index, const void* blob, int size);
+ int bindBlob(int index, const String&);
int bindText(int index, const String&);
int bindInt(int index, int);
int bindInt64(int index, int64_t);
@@ -80,6 +81,7 @@ public:
int getColumnInt(int col);
int64_t getColumnInt64(int col);
const void* getColumnBlob(int col, int& size);
+ String getColumnBlobAsString(int col);
void getColumnBlobAsVector(int col, Vector<char>&);
bool returnTextResults(int col, Vector<String>&);
diff --git a/Source/WebCore/platform/sql/chromium/SQLiteFileSystemChromiumPosix.cpp b/Source/WebCore/platform/sql/chromium/SQLiteFileSystemChromiumPosix.cpp
index 37f96be..6dbc384 100644
--- a/Source/WebCore/platform/sql/chromium/SQLiteFileSystemChromiumPosix.cpp
+++ b/Source/WebCore/platform/sql/chromium/SQLiteFileSystemChromiumPosix.cpp
@@ -34,938 +34,23 @@
#include "PlatformBridge.h"
#include <sqlite3.h>
-#include <errno.h>
#include <fcntl.h>
#include <string.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/types.h>
#include <unistd.h>
using namespace WebCore;
-// Chromium's Posix implementation of SQLite VFS.
-// This is heavily based on SQLite's os_unix.c,
-// without parts we don't need.
-
-// Identifies a file by its device number and inode.
-struct ChromiumFileId {
- dev_t dev; // Device number.
- ino_t ino; // Inode number.
-};
-
-// Information about file locks (one per open inode). Note that many open
-// file descriptors may refer to the same inode.
-struct ChromiumLockInfo {
- ChromiumFileId lockKey; // File identifier.
- int cnt; // Number of shared locks held.
- int locktype; // Type of the lock.
- int nRef; // Reference count.
-
- // Double-linked list pointers.
- ChromiumLockInfo* pNext;
- ChromiumLockInfo* pPrev;
-};
-
-// Information about a file descriptor that cannot be closed immediately.
-struct ChromiumUnusedFd {
- int fd; // File descriptor.
- int flags; // Flags this file descriptor was opened with.
- ChromiumUnusedFd* pNext; // Next unused file descriptor on the same file.
-};
-
-// Information about an open inode. When we want to close an inode
-// that still has locks, we defer the close until all locks are cleared.
-struct ChromiumOpenInfo {
- ChromiumFileId fileId; // The lookup key.
- int nRef; // Reference count.
- int nLock; // Number of outstanding locks.
- ChromiumUnusedFd* pUnused; // List of file descriptors to close.
-
- // Double-linked list pointers.
- ChromiumOpenInfo* pNext;
- ChromiumOpenInfo* pPrev;
-};
-
-// Keep track of locks and inodes in double-linked lists.
-static struct ChromiumLockInfo* lockList = 0;
-static struct ChromiumOpenInfo* openList = 0;
-
-// Extension of sqlite3_file specific to the chromium VFS.
-struct ChromiumFile {
- sqlite3_io_methods const* pMethod; // Implementation of sqlite3_file.
- ChromiumOpenInfo* pOpen; // Information about all open file descriptors for this file.
- ChromiumLockInfo* pLock; // Information about all locks for this file.
- int h; // File descriptor.
- int dirfd; // File descriptor for the file directory.
- unsigned char locktype; // Type of the lock used for this file.
- int lastErrno; // Value of errno for last operation on this file.
- ChromiumUnusedFd* pUnused; // Information about unused file descriptors for this file.
-};
-
-// The following constants specify the range of bytes used for locking.
-// SQLiteSharedSize is the number of bytes available in the pool from which
-// a random byte is selected for a shared lock. The pool of bytes for
-// shared locks begins at SQLiteSharedFirstByte.
-// The values are the same as used by SQLite for compatibility.
-static const off_t SQLitePendingByte = 0x40000000;
-static const off_t SQLiteReservedByte = SQLitePendingByte + 1;
-static const off_t SQLiteSharedFirstByte = SQLitePendingByte + 2;
-static const off_t SQLiteSharedSize = 510;
-
-// Maps a POSIX error code to an SQLite error code.
-static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr)
-{
- switch (posixError) {
- case 0:
- return SQLITE_OK;
- case EAGAIN:
- case ETIMEDOUT:
- case EBUSY:
- case EINTR:
- case ENOLCK:
- return SQLITE_BUSY;
- case EACCES:
- // EACCES is like EAGAIN during locking operations.
- if ((sqliteIOErr == SQLITE_IOERR_LOCK) ||
- (sqliteIOErr == SQLITE_IOERR_UNLOCK) ||
- (sqliteIOErr == SQLITE_IOERR_RDLOCK) ||
- (sqliteIOErr == SQLITE_IOERR_CHECKRESERVEDLOCK))
- return SQLITE_BUSY;
- return SQLITE_PERM;
- case EPERM:
- return SQLITE_PERM;
- case EDEADLK:
- return SQLITE_IOERR_BLOCKED;
- default:
- return sqliteIOErr;
- }
-}
-
-// Releases a ChromiumLockInfo structure previously allocated by findLockInfo().
-static void releaseLockInfo(ChromiumLockInfo* pLock)
-{
- if (!pLock)
- return;
-
- pLock->nRef--;
- if (pLock->nRef > 0)
- return;
-
- if (pLock->pPrev) {
- ASSERT(pLock->pPrev->pNext == pLock);
- pLock->pPrev->pNext = pLock->pNext;
- } else {
- ASSERT(lockList == pLock);
- lockList = pLock->pNext;
- }
- if (pLock->pNext) {
- ASSERT(pLock->pNext->pPrev == pLock);
- pLock->pNext->pPrev = pLock->pPrev;
- }
-
- sqlite3_free(pLock);
-}
-
-// Releases a ChromiumOpenInfo structure previously allocated by findLockInfo().
-static void releaseOpenInfo(ChromiumOpenInfo* pOpen)
-{
- if (!pOpen)
- return;
-
- pOpen->nRef--;
- if (pOpen->nRef > 0)
- return;
-
- if (pOpen->pPrev) {
- ASSERT(pOpen->pPrev->pNext == pOpen);
- pOpen->pPrev->pNext = pOpen->pNext;
- } else {
- ASSERT(openList == pOpen);
- openList = pOpen->pNext;
- }
- if (pOpen->pNext) {
- ASSERT(pOpen->pNext->pPrev == pOpen);
- pOpen->pNext->pPrev = pOpen->pPrev;
- }
-
- ASSERT(!pOpen->pUnused); // Make sure we're not leaking memory and file descriptors.
-
- sqlite3_free(pOpen);
-}
-
-// Locates ChromiumLockInfo and ChromiumOpenInfo for given file descriptor (creating new ones if needed).
-// Returns a SQLite error code.
-static int findLockInfo(ChromiumFile* pFile, ChromiumLockInfo** ppLock, ChromiumOpenInfo** ppOpen)
-{
- int fd = pFile->h;
- struct stat statbuf;
- int rc = fstat(fd, &statbuf);
- if (rc) {
- pFile->lastErrno = errno;
-#ifdef EOVERFLOW
- if (pFile->lastErrno == EOVERFLOW)
- return SQLITE_NOLFS;
-#endif
- return SQLITE_IOERR;
- }
-
-#if OS(DARWIN)
- // On OS X on an msdos/fat filesystems, the inode number is reported
- // incorrectly for zero-size files. See http://www.sqlite.org/cvstrac/tktview?tn=3260.
- // To work around this problem we always increase the file size to 1 by writing a single byte
- // prior to accessing the inode number. The one byte written is an ASCII 'S' character which
- // also happens to be the first byte in the header of every SQLite database. In this way,
- // if there is a race condition such that another thread has already populated the first page
- // of the database, no damage is done.
- if (!statbuf.st_size) {
- rc = write(fd, "S", 1);
- if (rc != 1)
- return SQLITE_IOERR;
- rc = fstat(fd, &statbuf);
- if (rc) {
- pFile->lastErrno = errno;
- return SQLITE_IOERR;
- }
- }
-#endif
-
- ChromiumFileId fileId;
- memset(&fileId, 0, sizeof(fileId));
- fileId.dev = statbuf.st_dev;
- fileId.ino = statbuf.st_ino;
-
- ChromiumLockInfo* pLock = 0;
-
- if (ppLock) {
- pLock = lockList;
- while (pLock && memcmp(&fileId, &pLock->lockKey, sizeof(fileId)))
- pLock = pLock->pNext;
- if (pLock)
- pLock->nRef++;
- else {
- pLock = static_cast<ChromiumLockInfo*>(sqlite3_malloc(sizeof(*pLock)));
- if (!pLock)
- return SQLITE_NOMEM;
- pLock->lockKey = fileId;
- pLock->nRef = 1;
- pLock->cnt = 0;
- pLock->locktype = 0;
- pLock->pNext = lockList;
- pLock->pPrev = 0;
- if (lockList)
- lockList->pPrev = pLock;
- lockList = pLock;
- }
- *ppLock = pLock;
- }
-
- if (ppOpen) {
- ChromiumOpenInfo* pOpen = openList;
- while (pOpen && memcmp(&fileId, &pOpen->fileId, sizeof(fileId)))
- pOpen = pOpen->pNext;
- if (pOpen)
- pOpen->nRef++;
- else {
- pOpen = static_cast<ChromiumOpenInfo*>(sqlite3_malloc(sizeof(*pOpen)));
- if (!pOpen) {
- releaseLockInfo(pLock);
- return SQLITE_NOMEM;
- }
- memset(pOpen, 0, sizeof(*pOpen));
- pOpen->fileId = fileId;
- pOpen->nRef = 1;
- pOpen->pNext = openList;
- if (openList)
- openList->pPrev = pOpen;
- openList = pOpen;
- }
- *ppOpen = pOpen;
- }
-
- return rc;
-}
-
-// Checks if there is a RESERVED lock held on the specified file by this or any other process.
-// If the lock is held, sets pResOut to a non-zero value. Returns a SQLite error code.
-static int chromiumCheckReservedLock(sqlite3_file* id, int* pResOut)
-{
- ChromiumFile* pFile = reinterpret_cast<ChromiumFile*>(id);
- ASSERT(pFile);
-
- // Look for locks held by this process.
- int reserved = 0;
- if (pFile->pLock->locktype > SQLITE_LOCK_SHARED)
- reserved = 1;
-
- // Look for locks held by other processes.
- int rc = SQLITE_OK;
- if (!reserved) {
- struct flock lock;
- lock.l_whence = SEEK_SET;
- lock.l_start = SQLiteReservedByte;
- lock.l_len = 1;
- lock.l_type = F_WRLCK;
- if (-1 == fcntl(pFile->h, F_GETLK, &lock)) {
- int tErrno = errno;
- rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_CHECKRESERVEDLOCK);
- pFile->lastErrno = tErrno;
- } else if (lock.l_type != F_UNLCK)
- reserved = 1;
- }
-
- *pResOut = reserved;
- return rc;
-}
-
-// Performs a file locking operation on a range of bytes in a file.
-// The |op| parameter should be one of F_RFLCK, F_WRLCK or F_UNLCK.
-// Returns a Unix error code, and also writes it to pErrcode.
-static int rangeLock(ChromiumFile* pFile, int op, int* pErrcode)
-{
- struct flock lock;
- lock.l_type = op;
- lock.l_start = SQLiteSharedFirstByte;
- lock.l_whence = SEEK_SET;
- lock.l_len = SQLiteSharedSize;
- int rc = fcntl(pFile->h, F_SETLK, &lock);
- *pErrcode = errno;
- return rc;
-}
-
-// Locks the file with the lock specified by parameter locktype - one
-// of the following:
-//
-// (1) SQLITE_LOCK_SHARED
-// (2) SQLITE_LOCK_RESERVED
-// (3) SQLITE_LOCK_PENDING
-// (4) SQLITE_LOCK_EXCLUSIVE
-//
-// Sometimes when requesting one lock state, additional lock states
-// are inserted in between. The locking might fail on one of the later
-// transitions leaving the lock state different from what it started but
-// still short of its goal. The following chart shows the allowed
-// transitions and the inserted intermediate states:
-//
-// UNLOCKED -> SHARED
-// SHARED -> RESERVED
-// SHARED -> (PENDING) -> EXCLUSIVE
-// RESERVED -> (PENDING) -> EXCLUSIVE
-// PENDING -> EXCLUSIVE
-static int chromiumLock(sqlite3_file* id, int locktype)
-{
- // To obtain a SHARED lock, a read-lock is obtained on the 'pending
- // byte'. If this is successful, a random byte from the 'shared byte
- // range' is read-locked and the lock on the 'pending byte' released.
- //
- // A process may only obtain a RESERVED lock after it has a SHARED lock.
- // A RESERVED lock is implemented by grabbing a write-lock on the
- // 'reserved byte'.
- //
- // A process may only obtain a PENDING lock after it has obtained a
- // SHARED lock. A PENDING lock is implemented by obtaining a write-lock
- // on the 'pending byte'. This ensures that no new SHARED locks can be
- // obtained, but existing SHARED locks are allowed to persist. A process
- // does not have to obtain a RESERVED lock on the way to a PENDING lock.
- // This property is used by the algorithm for rolling back a journal file
- // after a crash.
- //
- // An EXCLUSIVE lock, obtained after a PENDING lock is held, is
- // implemented by obtaining a write-lock on the entire 'shared byte
- // range'. Since all other locks require a read-lock on one of the bytes
- // within this range, this ensures that no other locks are held on the
- // database.
-
- int rc = SQLITE_OK;
- struct flock lock;
- int s = 0;
- int tErrno;
-
- ChromiumFile* pFile = reinterpret_cast<ChromiumFile*>(id);
- ASSERT(pFile);
-
- ChromiumLockInfo* pLock = pFile->pLock;
-
- // If there is already a lock of this type or more restrictive, do nothing.
- if (pFile->locktype >= locktype)
- return SQLITE_OK;
-
- // Make sure we never move from unlocked to anything higher than shared lock.
- ASSERT(pFile->locktype != SQLITE_LOCK_NONE || locktype == SQLITE_LOCK_SHARED);
-
- // Make sure we never request a pending lock.
- ASSERT(locktype != SQLITE_LOCK_PENDING);
-
- // Make sure a shared lock is always held when a RESERVED lock is requested.
- ASSERT(locktype != SQLITE_LOCK_RESERVED || pFile->locktype == SQLITE_LOCK_SHARED);
-
- // If some thread using this PID has a lock via a different ChromiumFile
- // handle that precludes the requested lock, return BUSY.
- if (pFile->locktype != pLock->locktype &&
- (pLock->locktype >= SQLITE_LOCK_PENDING || locktype > SQLITE_LOCK_SHARED))
- return SQLITE_BUSY;
-
- // If a SHARED lock is requested, and some thread using this PID already
- // has a SHARED or RESERVED lock, then just increment reference counts.
- if (locktype == SQLITE_LOCK_SHARED &&
- (pLock->locktype == SQLITE_LOCK_SHARED || pLock->locktype == SQLITE_LOCK_RESERVED)) {
- ASSERT(!pFile->locktype);
- ASSERT(pLock->cnt > 0);
- pFile->locktype = SQLITE_LOCK_SHARED;
- pLock->cnt++;
- pFile->pOpen->nLock++;
- return SQLITE_OK;
- }
-
- // A PENDING lock is needed before acquiring a SHARED lock and before
- // acquiring an EXCLUSIVE lock. For the SHARED lock, the PENDING will
- // be released.
- lock.l_len = 1;
- lock.l_whence = SEEK_SET;
- if (locktype == SQLITE_LOCK_SHARED ||
- (locktype == SQLITE_LOCK_EXCLUSIVE && pFile->locktype < SQLITE_LOCK_PENDING)) {
- lock.l_type = (locktype == SQLITE_LOCK_SHARED ? F_RDLCK : F_WRLCK);
- lock.l_start = SQLitePendingByte;
- s = fcntl(pFile->h, F_SETLK, &lock);
- if (s == -1) {
- tErrno = errno;
- rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
- if ((rc != SQLITE_OK) && (rc != SQLITE_BUSY))
- pFile->lastErrno = tErrno;
- return rc;
- }
- }
-
- if (locktype == SQLITE_LOCK_SHARED) {
- ASSERT(!pLock->cnt);
- ASSERT(!pLock->locktype);
-
- s = rangeLock(pFile, F_RDLCK, &tErrno);
-
- // Drop the temporary PENDING lock.
- lock.l_start = SQLitePendingByte;
- lock.l_len = 1;
- lock.l_type = F_UNLCK;
- if (fcntl(pFile->h, F_SETLK, &lock)) {
- if (s != -1) {
- tErrno = errno;
- rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
- if ((rc != SQLITE_OK) && (rc != SQLITE_BUSY))
- pFile->lastErrno = tErrno;
- return rc;
- }
- }
- if (s == -1) {
- rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
- if ((rc != SQLITE_OK) && (rc != SQLITE_BUSY))
- pFile->lastErrno = tErrno;
- } else {
- pFile->locktype = SQLITE_LOCK_SHARED;
- pFile->pOpen->nLock++;
- pLock->cnt = 1;
- }
- } else if (locktype == SQLITE_LOCK_EXCLUSIVE && pLock->cnt > 1) {
- // We are trying for an exclusive lock but another thread in the
- // same process is still holding a shared lock.
- rc = SQLITE_BUSY;
- } else {
- // The request was for a RESERVED or EXCLUSIVE lock. It is
- // assumed that there is a SHARED or greater lock on the file
- // already.
- ASSERT(pFile->locktype);
- lock.l_type = F_WRLCK;
- switch (locktype) {
- case SQLITE_LOCK_RESERVED:
- lock.l_start = SQLiteReservedByte;
- s = fcntl(pFile->h, F_SETLK, &lock);
- tErrno = errno;
- break;
- case SQLITE_LOCK_EXCLUSIVE:
- s = rangeLock(pFile, F_WRLCK, &tErrno);
- break;
- default:
- ASSERT_NOT_REACHED();
- }
- if (s == -1) {
- rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
- if ((rc != SQLITE_OK) && (rc != SQLITE_BUSY))
- pFile->lastErrno = tErrno;
- }
- }
-
- if (rc == SQLITE_OK) {
- pFile->locktype = locktype;
- pLock->locktype = locktype;
- } else if (locktype == SQLITE_LOCK_EXCLUSIVE) {
- pFile->locktype = SQLITE_LOCK_PENDING;
- pLock->locktype = SQLITE_LOCK_PENDING;
- }
-
- return rc;
-}
-
-// Closes all file descriptors for given ChromiumFile for which the close has been deferred.
-// Returns a SQLite error code.
-static int closePendingFds(ChromiumFile* pFile)
-{
- int rc = SQLITE_OK;
- ChromiumOpenInfo* pOpen = pFile->pOpen;
- ChromiumUnusedFd* pError = 0;
- ChromiumUnusedFd* pNext;
- for (ChromiumUnusedFd* p = pOpen->pUnused; p; p = pNext) {
- pNext = p->pNext;
- if (close(p->fd)) {
- pFile->lastErrno = errno;
- rc = SQLITE_IOERR_CLOSE;
- p->pNext = pError;
- pError = p;
- } else
- sqlite3_free(p);
- }
- pOpen->pUnused = pError;
- return rc;
-}
-
-// Lowers the locking level on file descriptor.
-// locktype must be either SQLITE_LOCK_NONE or SQLITE_LOCK_SHARED.
-static int chromiumUnlock(sqlite3_file* id, int locktype)
-{
- ChromiumFile* pFile = reinterpret_cast<ChromiumFile*>(id);
- ASSERT(pFile);
- ASSERT(locktype <= SQLITE_LOCK_SHARED);
-
- if (pFile->locktype <= locktype)
- return SQLITE_OK;
-
- ChromiumLockInfo* pLock = pFile->pLock;
- ASSERT(pLock->cnt);
-
- struct flock lock;
- int rc = SQLITE_OK;
- int h = pFile->h;
- int tErrno;
-
- if (pFile->locktype > SQLITE_LOCK_SHARED) {
- ASSERT(pLock->locktype == pFile->locktype);
-
- if (locktype == SQLITE_LOCK_SHARED && rangeLock(pFile, F_RDLCK, &tErrno) == -1) {
- rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);
- if ((rc != SQLITE_OK) && (rc != SQLITE_BUSY))
- pFile->lastErrno = tErrno;
- if (rc == SQLITE_OK)
- pFile->locktype = locktype;
- return rc;
- }
- lock.l_type = F_UNLCK;
- lock.l_whence = SEEK_SET;
- lock.l_start = SQLitePendingByte;
- lock.l_len = 2;
- if (fcntl(h, F_SETLK, &lock) != -1)
- pLock->locktype = SQLITE_LOCK_SHARED;
- else {
- tErrno = errno;
- rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
- if ((rc != SQLITE_OK) && (rc != SQLITE_BUSY))
- pFile->lastErrno = tErrno;
- if (rc == SQLITE_OK)
- pFile->locktype = locktype;
- return rc;
- }
- }
- if (locktype == SQLITE_LOCK_NONE) {
- struct ChromiumOpenInfo *pOpen;
-
- pLock->cnt--;
-
- // Release the lock using an OS call only when all threads in this same process have released the lock.
- if (!pLock->cnt) {
- lock.l_type = F_UNLCK;
- lock.l_whence = SEEK_SET;
- lock.l_start = lock.l_len = 0L;
- if (fcntl(h, F_SETLK, &lock) != -1)
- pLock->locktype = SQLITE_LOCK_NONE;
- else {
- tErrno = errno;
- rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
- if ((rc != SQLITE_OK) && (rc != SQLITE_BUSY))
- pFile->lastErrno = tErrno;
- pLock->locktype = SQLITE_LOCK_NONE;
- pFile->locktype = SQLITE_LOCK_NONE;
- }
- }
-
- pOpen = pFile->pOpen;
- pOpen->nLock--;
- ASSERT(pOpen->nLock >= 0);
- if (!pOpen->nLock) {
- int rc2 = closePendingFds(pFile);
- if (rc == SQLITE_OK)
- rc = rc2;
- }
- }
-
- if (rc == SQLITE_OK)
- pFile->locktype = locktype;
- return rc;
+// Defined in Chromium's codebase in third_party/sqlite/src/os_unix.c
+extern "C" {
+void chromium_sqlite3_initialize_unix_sqlite3_file(sqlite3_file* file);
+int chromium_sqlite3_fill_in_unix_sqlite3_file(sqlite3_vfs* vfs, int fd, int dirfd, sqlite3_file* file, const char* fileName, int noLock);
+int chromium_sqlite3_get_reusable_file_handle(sqlite3_file* file, const char* fileName, int flags, int* fd);
+void chromium_sqlite3_update_reusable_file_handle(sqlite3_file* file, int fd, int flags);
+void chromium_sqlite3_destroy_reusable_file_handle(sqlite3_file* file);
}
-// Closes all file handles for given ChromiumFile and sets all its fields to 0.
-// Returns a SQLite error code.
-static int chromiumCloseNoLock(sqlite3_file* id)
-{
- ChromiumFile* pFile = reinterpret_cast<ChromiumFile*>(id);
- if (!pFile)
- return SQLITE_OK;
- if (pFile->dirfd >= 0) {
- if (close(pFile->dirfd)) {
- pFile->lastErrno = errno;
- return SQLITE_IOERR_DIR_CLOSE;
- }
- pFile->dirfd = -1;
- }
- if (pFile->h >= 0 && close(pFile->h)) {
- pFile->lastErrno = errno;
- return SQLITE_IOERR_CLOSE;
- }
- sqlite3_free(pFile->pUnused);
- memset(pFile, 0, sizeof(ChromiumFile));
- return SQLITE_OK;
-}
-
-// Closes a ChromiumFile, including locking operations. Returns a SQLite error code.
-static int chromiumClose(sqlite3_file* id)
-{
- if (!id)
- return SQLITE_OK;
-
- ChromiumFile* pFile = reinterpret_cast<ChromiumFile*>(id);
- chromiumUnlock(id, SQLITE_LOCK_NONE);
- if (pFile->pOpen && pFile->pOpen->nLock) {
- // If there are outstanding locks, do not actually close the file just
- // yet because that would clear those locks.
- ChromiumOpenInfo* pOpen = pFile->pOpen;
- ChromiumUnusedFd* p = pFile->pUnused;
- p->pNext = pOpen->pUnused;
- pOpen->pUnused = p;
- pFile->h = -1;
- pFile->pUnused = 0;
- }
- releaseLockInfo(pFile->pLock);
- releaseOpenInfo(pFile->pOpen);
- return chromiumCloseNoLock(id);
-}
-
-static int chromiumCheckReservedLockNoop(sqlite3_file*, int* pResOut)
-{
- *pResOut = 0;
- return SQLITE_OK;
-}
-
-static int chromiumLockNoop(sqlite3_file*, int)
-{
- return SQLITE_OK;
-}
-
-static int chromiumUnlockNoop(sqlite3_file*, int)
-{
- return SQLITE_OK;
-}
-
-// Seeks to the requested offset and reads up to |cnt| bytes into |pBuf|. Returns number of bytes actually read.
-static int seekAndRead(ChromiumFile* id, sqlite3_int64 offset, void* pBuf, int cnt)
-{
- sqlite_int64 newOffset = lseek(id->h, offset, SEEK_SET);
- if (newOffset != offset) {
- id->lastErrno = (newOffset == -1) ? errno : 0;
- return -1;
- }
- int got = read(id->h, pBuf, cnt);
- if (got < 0)
- id->lastErrno = errno;
- return got;
-}
-
-// Reads data from file into a buffer. Returns a SQLite error code.
-static int chromiumRead(sqlite3_file* id, void* pBuf, int amt, sqlite3_int64 offset)
-{
- ChromiumFile* pFile = reinterpret_cast<ChromiumFile*>(id);
- ASSERT(pFile);
-
- // The bytes in the locking range should never be read.
- ASSERT(!pFile->pUnused || offset >= SQLitePendingByte + 512 || offset + amt <= SQLitePendingByte);
-
- int got = seekAndRead(pFile, offset, pBuf, amt);
- if (got == amt)
- return SQLITE_OK;
-
- if (got < 0)
- return SQLITE_IOERR_READ;
-
- // Unread parts of the buffer must be zero-filled.
- memset(&(reinterpret_cast<char*>(pBuf))[got], 0, amt - got);
- pFile->lastErrno = 0;
- return SQLITE_IOERR_SHORT_READ;
-}
-
-// Seeks to the requested offset and writes up to |cnt| bytes. Returns number of bytes actually written.
-static int seekAndWrite(ChromiumFile* id, sqlite_int64 offset, const void* pBuf, int cnt)
-{
- sqlite_int64 newOffset = lseek(id->h, offset, SEEK_SET);
- if (newOffset != offset) {
- id->lastErrno = (newOffset == -1) ? errno : 0;
- return -1;
- }
- int got = write(id->h, pBuf, cnt);
- if (got < 0)
- id->lastErrno = errno;
- return got;
-}
-
-// Writes data from buffer into a file. Returns a SQLite error code.
-static int chromiumWrite(sqlite3_file* id, const void* pBuf, int amt, sqlite3_int64 offset)
-{
- ChromiumFile* pFile = reinterpret_cast<ChromiumFile*>(id);
- ASSERT(pFile);
- ASSERT(amt > 0);
-
- // The bytes in the locking range should never be written.
- ASSERT(!pFile->pUnused || offset >= SQLitePendingByte + 512 || offset + amt <= SQLitePendingByte);
-
- int wrote = 0;
- while (amt > 0 && (wrote = seekAndWrite(pFile, offset, pBuf, amt)) > 0) {
- amt -= wrote;
- offset += wrote;
- pBuf = &(reinterpret_cast<const char*>(pBuf))[wrote];
- }
- if (amt > 0) {
- if (wrote < 0)
- return SQLITE_IOERR_WRITE;
- pFile->lastErrno = 0;
- return SQLITE_FULL;
- }
- return SQLITE_OK;
-}
-
-static bool syncWrapper(int fd, bool fullSync)
-{
-#if OS(DARWIN)
- bool success = false;
- if (fullSync)
- success = !fcntl(fd, F_FULLFSYNC, 0);
- if (!success)
- success = !fsync(fd);
- return success;
-#else
- return !fdatasync(fd);
-#endif
-}
-
-// Makes sure all writes to a particular file are committed to disk. Returns a SQLite error code.
-static int chromiumSync(sqlite3_file* id, int flags)
-{
- ASSERT((flags & 0x0F) == SQLITE_SYNC_NORMAL || (flags & 0x0F) == SQLITE_SYNC_FULL);
-
- ChromiumFile* pFile = reinterpret_cast<ChromiumFile*>(id);
- ASSERT(pFile);
-
- bool isFullSync = ((flags & 0x0F) == SQLITE_SYNC_FULL);
-
- if (!syncWrapper(pFile->h, isFullSync)) {
- pFile->lastErrno = errno;
- return SQLITE_IOERR_FSYNC;
- }
-
- if (pFile->dirfd >= 0) {
-#if !OS(DARWIN)
- if (!isFullSync) {
- // Ignore directory sync failures, see http://www.sqlite.org/cvstrac/tktview?tn=1657.
- syncWrapper(pFile->dirfd, false);
- }
-#endif
- if (!close(pFile->dirfd))
- pFile->dirfd = -1;
- else {
- pFile->lastErrno = errno;
- return SQLITE_IOERR_DIR_CLOSE;
- }
- }
-
- return SQLITE_OK;
-}
-
-// Truncates an open file to the specified size. Returns a SQLite error code.
-static int chromiumTruncate(sqlite3_file* id, sqlite_int64 nByte)
-{
- ChromiumFile* pFile = reinterpret_cast<ChromiumFile*>(id);
- ASSERT(pFile);
-
- if (ftruncate(pFile->h, nByte)) {
- pFile->lastErrno = errno;
- return SQLITE_IOERR_TRUNCATE;
- }
-
- return SQLITE_OK;
-}
-
-// Determines the size of a file in bytes. Returns a SQLite error code.
-static int chromiumFileSize(sqlite3_file* id, sqlite_int64* pSize)
-{
- ChromiumFile* pFile = reinterpret_cast<ChromiumFile*>(id);
- ASSERT(pFile);
-
- struct stat buf;
- if (fstat(pFile->h, &buf)) {
- pFile->lastErrno = errno;
- return SQLITE_IOERR_FSTAT;
- }
- *pSize = buf.st_size;
-
- // When opening a zero-size database, findLockInfo writes a single byte into that file
- // in order to work around a bug in the OS X msdos filesystem. In order to avoid problems
- // with upper layers, we need to report this file size as zero even though it is really 1.
- // See http://www.sqlite.org/cvstrac/tktview?tn=3260.
- if (*pSize == 1)
- *pSize = 0;
-
- return SQLITE_OK;
-}
-
-static int chromiumFileControl(sqlite3_file* id, int op, void* pArg)
-{
- ChromiumFile* pFile = reinterpret_cast<ChromiumFile*>(id);
- ASSERT(pFile);
-
- switch (op) {
- case SQLITE_FCNTL_LOCKSTATE:
- *reinterpret_cast<int*>(pArg) = pFile->locktype;
- return SQLITE_OK;
- case SQLITE_LAST_ERRNO:
- *reinterpret_cast<int*>(pArg) = pFile->lastErrno;
- return SQLITE_OK;
- }
- return SQLITE_ERROR;
-}
-
-// Same as SQLITE_DEFAULT_SECTOR_SIZE from sqlite's os.h.
-static const int SQLiteDefaultSectorSize = 512;
-
-static int chromiumSectorSize(sqlite3_file*)
-{
- return SQLiteDefaultSectorSize;
-}
-
-static int chromiumDeviceCharacteristics(sqlite3_file*)
-{
- return 0;
-}
-
-static const sqlite3_io_methods posixIoMethods = {
- 1,
- chromiumClose,
- chromiumRead,
- chromiumWrite,
- chromiumTruncate,
- chromiumSync,
- chromiumFileSize,
- chromiumLock,
- chromiumUnlock,
- chromiumCheckReservedLock,
- chromiumFileControl,
- chromiumSectorSize,
- chromiumDeviceCharacteristics
-};
-
-static const sqlite3_io_methods nolockIoMethods = {
- 1,
- chromiumCloseNoLock,
- chromiumRead,
- chromiumWrite,
- chromiumTruncate,
- chromiumSync,
- chromiumFileSize,
- chromiumLockNoop,
- chromiumUnlockNoop,
- chromiumCheckReservedLockNoop,
- chromiumFileControl,
- chromiumSectorSize,
- chromiumDeviceCharacteristics
-};
-
-// Initializes a ChromiumFile. Returns a SQLite error code.
-static int fillInChromiumFile(sqlite3_vfs* pVfs, int h, int dirfd, sqlite3_file* pId, const char* zFilename, int noLock)
-{
- ChromiumFile* pNew = reinterpret_cast<ChromiumFile*>(pId);
-
- ASSERT(!pNew->pLock);
- ASSERT(!pNew->pOpen);
-
- pNew->h = h;
- pNew->dirfd = dirfd;
-
- int rc = SQLITE_OK;
- const sqlite3_io_methods* pLockingStyle;
- if (noLock)
- pLockingStyle = &nolockIoMethods;
- else {
- pLockingStyle = &posixIoMethods;
- rc = findLockInfo(pNew, &pNew->pLock, &pNew->pOpen);
- if (rc != SQLITE_OK) {
- // If an error occured in findLockInfo(), close the file descriptor
- // immediately. This can happen in two scenarios:
- //
- // (a) A call to fstat() failed.
- // (b) A malloc failed.
- //
- // Scenario (b) may only occur if the process is holding no other
- // file descriptors open on the same file. If there were other file
- // descriptors on this file, then no malloc would be required by
- // findLockInfo(). If this is the case, it is quite safe to close
- // handle h - as it is guaranteed that no posix locks will be released
- // by doing so.
- //
- // If scenario (a) caused the error then things are not so safe. The
- // implicit assumption here is that if fstat() fails, things are in
- // such bad shape that dropping a lock or two doesn't matter much.
- close(h);
- h = -1;
- }
- }
-
- pNew->lastErrno = 0;
- if (rc != SQLITE_OK) {
- if (dirfd >= 0)
- close(dirfd);
- if (h >= 0)
- close(h);
- } else
- pNew->pMethod = pLockingStyle;
- return rc;
-}
-
-// Searches for an unused file descriptor that was opened on the database
-// file identified by zPath with matching flags. Returns 0 if not found.
-static ChromiumUnusedFd* findReusableFd(const char* zPath, int flags)
-{
- ChromiumUnusedFd* pUnused = 0;
-
- struct stat sStat;
- if (!stat(zPath, &sStat)) {
- ChromiumFileId id;
- id.dev = sStat.st_dev;
- id.ino = sStat.st_ino;
-
- ChromiumOpenInfo* pO = 0;
- for (pO = openList; pO && memcmp(&id, &pO->fileId, sizeof(id)); pO = pO->pNext) { }
- if (pO) {
- ChromiumUnusedFd** pp;
- for (pp = &pO->pUnused; *pp && (*pp)->flags != flags; pp = &((*pp)->pNext)) { }
- pUnused = *pp;
- if (pUnused)
- *pp = pUnused->pNext;
- }
- }
- return pUnused;
-}
+// Chromium's Posix implementation of SQLite VFS
+namespace {
// Opens a file.
//
@@ -974,26 +59,14 @@ static ChromiumUnusedFd* findReusableFd(const char* zPath, int flags)
// id - the structure that will manipulate the newly opened file.
// desiredFlags - the desired open mode flags.
// usedFlags - the actual open mode flags that were used.
-static int chromiumOpen(sqlite3_vfs* vfs, const char* fileName,
- sqlite3_file* id, int desiredFlags, int* usedFlags)
+int chromiumOpen(sqlite3_vfs* vfs, const char* fileName,
+ sqlite3_file* id, int desiredFlags, int* usedFlags)
{
- // The mask 0x00007F00 gives us the 7 bits that determine the type of the file SQLite is trying to open.
- int fileType = desiredFlags & 0x00007F00;
-
- memset(id, 0, sizeof(ChromiumFile));
- ChromiumFile* chromiumFile = reinterpret_cast<ChromiumFile*>(id);
+ chromium_sqlite3_initialize_unix_sqlite3_file(id);
int fd = -1;
- if (fileType == SQLITE_OPEN_MAIN_DB) {
- ChromiumUnusedFd* unusedFd = findReusableFd(fileName, desiredFlags);
- if (unusedFd)
- fd = unusedFd->fd;
- else {
- unusedFd = static_cast<ChromiumUnusedFd*>(sqlite3_malloc(sizeof(*unusedFd)));
- if (!unusedFd)
- return SQLITE_NOMEM;
- }
- chromiumFile->pUnused = unusedFd;
- }
+ int result = chromium_sqlite3_get_reusable_file_handle(id, fileName, desiredFlags, &fd);
+ if (result != SQLITE_OK)
+ return result;
if (fd < 0) {
fd = PlatformBridge::databaseOpenFile(fileName, desiredFlags);
@@ -1003,24 +76,23 @@ static int chromiumOpen(sqlite3_vfs* vfs, const char* fileName,
}
}
if (fd < 0) {
- sqlite3_free(chromiumFile->pUnused);
+ chromium_sqlite3_destroy_reusable_file_handle(id);
return SQLITE_CANTOPEN;
}
if (usedFlags)
*usedFlags = desiredFlags;
- if (chromiumFile->pUnused) {
- chromiumFile->pUnused->fd = fd;
- chromiumFile->pUnused->flags = desiredFlags;
- }
+ chromium_sqlite3_update_reusable_file_handle(id, fd, desiredFlags);
fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
+ // The mask 0x00007F00 gives us the 7 bits that determine the type of the file SQLite is trying to open.
+ int fileType = desiredFlags & 0x00007F00;
int noLock = (fileType != SQLITE_OPEN_MAIN_DB);
- int rc = fillInChromiumFile(vfs, fd, -1, id, fileName, noLock);
- if (rc != SQLITE_OK)
- sqlite3_free(chromiumFile->pUnused);
- return rc;
+ result = chromium_sqlite3_fill_in_unix_sqlite3_file(vfs, fd, -1, id, fileName, noLock);
+ if (result != SQLITE_OK)
+ chromium_sqlite3_destroy_reusable_file_handle(id);
+ return result;
}
// Deletes the given file.
@@ -1029,7 +101,7 @@ static int chromiumOpen(sqlite3_vfs* vfs, const char* fileName,
// fileName - the name of the file.
// syncDir - determines if the directory to which this file belongs
// should be synched after the file is deleted.
-static int chromiumDelete(sqlite3_vfs*, const char* fileName, int syncDir)
+int chromiumDelete(sqlite3_vfs*, const char* fileName, int syncDir)
{
return PlatformBridge::databaseDeleteFile(fileName, syncDir);
}
@@ -1040,7 +112,7 @@ static int chromiumDelete(sqlite3_vfs*, const char* fileName, int syncDir)
// fileName - the name of the file.
// flag - the type of test to make on this file.
// res - the result.
-static int chromiumAccess(sqlite3_vfs*, const char* fileName, int flag, int* res)
+int chromiumAccess(sqlite3_vfs*, const char* fileName, int flag, int* res)
{
int attr = static_cast<int>(PlatformBridge::databaseGetFileAttributes(fileName));
if (attr < 0) {
@@ -1050,7 +122,7 @@ static int chromiumAccess(sqlite3_vfs*, const char* fileName, int flag, int* res
switch (flag) {
case SQLITE_ACCESS_EXISTS:
- *res = 1; // if the file doesn't exist, attr < 0
+ *res = 1; // if the file doesn't exist, attr < 0
break;
case SQLITE_ACCESS_READWRITE:
*res = (attr & W_OK) && (attr & R_OK);
@@ -1071,8 +143,8 @@ static int chromiumAccess(sqlite3_vfs*, const char* fileName, int flag, int* res
// relativePath - the relative path.
// bufSize - the size of the output buffer in bytes.
// absolutePath - the output buffer where the absolute path will be stored.
-static int chromiumFullPathname(sqlite3_vfs* vfs, const char* relativePath,
- int, char* absolutePath)
+int chromiumFullPathname(sqlite3_vfs* vfs, const char* relativePath,
+ int, char* absolutePath)
{
// The renderer process doesn't need to know the absolute path of the file
sqlite3_snprintf(vfs->mxPathname, absolutePath, "%s", relativePath);
@@ -1080,107 +152,44 @@ static int chromiumFullPathname(sqlite3_vfs* vfs, const char* relativePath,
}
#ifndef SQLITE_OMIT_LOAD_EXTENSION
-// We disallow loading DSOs inside the renderer process, so the following procedures are no-op.
-static void* chromiumDlOpen(sqlite3_vfs*, const char*)
-{
- return 0;
-}
-
-static void chromiumDlError(sqlite3_vfs*, int, char*)
-{
-}
-
-static void (*chromiumDlSym(sqlite3_vfs*, void*, const char*))()
+// Returns NULL, thus disallowing loading libraries in the renderer process.
+//
+// vfs - pointer to the sqlite3_vfs object.
+// fileName - the name of the shared library file.
+void* chromiumDlOpen(sqlite3_vfs*, const char*)
{
return 0;
}
-
-static void chromiumDlClose(sqlite3_vfs*, void*)
-{
-}
#else
#define chromiumDlOpen 0
-#define chromiumDlError 0
-#define chromiumDlSym 0
-#define chromiumDlClose 0
#endif // SQLITE_OMIT_LOAD_EXTENSION
-// Generates a seed for SQLite's PRNG.
-static int chromiumRandomness(sqlite3_vfs*, int nBuf, char *zBuf)
-{
- ASSERT(static_cast<size_t>(nBuf) >= (sizeof(time_t) + sizeof(int)));
-
- memset(zBuf, 0, nBuf);
- int fd = open("/dev/urandom", O_RDONLY);
- if (fd < 0) {
- time_t t;
- time(&t);
- memcpy(zBuf, &t, sizeof(t));
- int pid = getpid();
- memcpy(&zBuf[sizeof(t)], &pid, sizeof(pid));
- return sizeof(t) + sizeof(pid);
- }
- nBuf = read(fd, zBuf, nBuf);
- close(fd);
- return nBuf;
-}
-
-// Sleeps for at least |microseconds|, and returns the actual
-// amount of time spent sleeping (in microseconds).
-static int chromiumSleep(sqlite3_vfs*, int microseconds)
-{
-#if OS(DARWIN)
- usleep(microseconds);
- return microseconds;
-#else
- // Round to the nearest second.
- int seconds = (microseconds + 999999) / 1000000;
- sleep(seconds);
- return seconds * 1000000;
-#endif
-}
-
-// Retrieves the current system time (UTC).
-static int chromiumCurrentTime(sqlite3_vfs*, double* now)
-{
- struct timeval timeval;
- gettimeofday(&timeval, 0);
- *now = 2440587.5 + timeval.tv_sec / 86400.0 + timeval.tv_usec / 86400000000.0;
- return 0;
-}
-
-// This is not yet implemented in SQLite core.
-static int chromiumGetLastError(sqlite3_vfs*, int, char*)
-{
- return 0;
-}
-
-// Same as MAX_PATHNAME from sqlite's os_unix.c.
-static const int chromiumMaxPathname = 512;
+} // namespace
namespace WebCore {
void SQLiteFileSystem::registerSQLiteVFS()
{
+ sqlite3_vfs* unix_vfs = sqlite3_vfs_find("unix");
static sqlite3_vfs chromium_vfs = {
1,
- sizeof(ChromiumFile),
- chromiumMaxPathname,
+ unix_vfs->szOsFile,
+ unix_vfs->mxPathname,
0,
"chromium_vfs",
- 0,
+ unix_vfs->pAppData,
chromiumOpen,
chromiumDelete,
chromiumAccess,
chromiumFullPathname,
chromiumDlOpen,
- chromiumDlError,
- chromiumDlSym,
- chromiumDlClose,
- chromiumRandomness,
- chromiumSleep,
- chromiumCurrentTime,
- chromiumGetLastError
+ unix_vfs->xDlError,
+ unix_vfs->xDlSym,
+ unix_vfs->xDlClose,
+ unix_vfs->xRandomness,
+ unix_vfs->xSleep,
+ unix_vfs->xCurrentTime,
+ unix_vfs->xGetLastError
};
sqlite3_vfs_register(&chromium_vfs, 0);
}