提交 23151605 编写于 作者: xpxyr's avatar xpxyr 提交者: geniusgogo

add vfs/fs porting

上级 d47febdc
/*
** 2004 May 22
**
** 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 code that is specific to Windows.
*/
#include "sqliteInt.h"
#if SQLITE_OS_RTT /* This file is used for rt-thread only */
#include <rtthread.h>
/*
** Include code that is common to all os_*.c files
*/
#include "os_common.h"
/*
** Compiling and using WAL mode requires several APIs that are not
** available in rt-thread.
*/
#if !defined(SQLITE_OMIT_WAL)
# error "WAL mode requires not support from the rt-thread, compile\
with SQLITE_OMIT_WAL."
#endif
/*
** Are most of the rtt ANSI APIs available (i.e. with certain exceptions
** based on the sub-platform)?
*/
#if !defined(SQLITE_RTT_NO_ANSI)
# warning "please ensure rtt ANSI APIs is available, otherwise compile with\
SQLITE_RTT_NO_ANSI"
# define SQLITE_RTT_HAS_ANSI
#endif
/*
** Are most of the rtt Unicode APIs available (i.e. with certain exceptions
** based on the sub-platform)?
*/
#if !defined(SQLITE_RTT_NO_WIDE)
# error "rtt not support Unicode APIs"
# define SQLITE_RTT_HAS_WIDE
#endif
/*
** Make sure at least one set of rtt APIs is available.
*/
#if !defined(SQLITE_RTT_HAS_ANSI) && !defined(SQLITE_RTT_HAS_WIDE)
# error "At least one of SQLITE_RTT_HAS_ANSI and SQLITE_RTT_HAS_WIDE\
must be defined."
#endif
/*
** Maximum pathname length (in chars) for rtt. This should normally be
** MAX_PATH.
*/
#ifndef SQLITE_RTT_MAX_PATH_CHARS
# warning "default Maximum pathname length be 255, otherwise compile with\
SQLITE_RTT_MAX_PATH_CHARS=?"
# define SQLITE_RTT_MAX_PATH_CHARS (255)
#endif
/*
** Maximum supported path-length.
*/
#define MAX_PATHNAME 512
/*
** Returns non-zero if the character should be treated as a directory
** separator.
*/
#ifndef rttIsDirSep
# define rttIsDirSep(a) ((a) == '/')
#endif
/*
** This macro is used when a local variable is set to a value that is
** [sometimes] not used by the code (e.g. via conditional compilation).
*/
#ifndef UNUSED_VARIABLE_VALUE
# define UNUSED_VARIABLE_VALUE(x) (void)(x)
#endif
/*
** Returns the string that should be used as the directory separator.
*/
#ifndef rttGetDirDep
# define rttGetDirDep() "/"
#endif
/*
** The winFile structure is a subclass of sqlite3_file* specific to the win32
** portability layer.
*/
typedef struct rttFile rttFile;
struct rttFile {
sqlite3_io_methods const *pMethod; /* Always the first entry */
sqlite3_vfs *pVfs; /* The VFS that created this rttFile */
int h; /* The file descriptor */
unsigned short int ctrlFlags; /* Behavioral bits. UNIXFILE_* flags */
unsigned char eFileLock; /* The type of lock held on this fd */
int lastErrno; /* The unix errno from last I/O error */
void *lockingContext; /* Locking style specific state */
const char *zPath; /* Name of the file */
int szChunk; /* Configured by FCNTL_CHUNK_SIZE */
#if SQLITE_ENABLE_LOCKING_STYLE
int openFlags; /* The flags specified at open() */
#endif
#if SQLITE_ENABLE_LOCKING_STYLE
unsigned fsFlags; /* cached details from statfs() */
#endif
#ifdef SQLITE_DEBUG
/* The next group of variables are used to track whether or not the
** transaction counter in bytes 24-27 of database files are updated
** whenever any part of the database changes. An assertion fault will
** occur if a file is updated without also updating the transaction
** counter. This test is made to avoid new problems similar to the
** one described by ticket #3584.
*/
unsigned char transCntrChng; /* True if the transaction counter changed */
unsigned char dbUpdate; /* True if any part of database file changed */
unsigned char inNormalWrite; /* True if in a normal write operation */
#endif
#ifdef SQLITE_TEST
/* In test mode, increase the size of this structure a bit so that
** it is larger than the struct CrashFile defined in test6.c.
*/
char aPadding[32];
#endif
};
/*
** Allowed values for the rttFile.ctrlFlags bitmask:
*/
#define UNIXFILE_EXCL 0x01 /* Connections from one process only */
#define UNIXFILE_RDONLY 0x02 /* Connection is read only */
#define UNIXFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */
#ifndef SQLITE_DISABLE_DIRSYNC
# define UNIXFILE_DIRSYNC 0x08 /* Directory sync needed */
#else
# define UNIXFILE_DIRSYNC 0x00
#endif
#define UNIXFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */
#define UNIXFILE_DELETE 0x20 /* Delete on close */
#define UNIXFILE_URI 0x40 /* Filename might have query parameters */
#define UNIXFILE_NOLOCK 0x80 /* Do no file locking */
#define UNIXFILE_WARNED 0x0100 /* verifyDbFile() warnings have been issued */
/*
** The following variable is (normally) set once and never changes
** thereafter. It records whether the operating system is Win9x
** or WinNT.
**
** 0: Operating system unknown.
** 1: Operating system is rtt.
**
** In order to facilitate testing on a rtt system, the test fixture
** can manually set this value to 1 to emulate Win98 behavior.
*/
#ifdef SQLITE_TEST
int sqlite3_os_type = 0;
#elif !SQLITE_OS_RTT && \
defined(SQLITE_RTT_HAS_ANSI) && defined(SQLITE_RTT_HAS_WIDE)
static int sqlite3_os_type = 0;
#endif
#ifndef SYSCALL
# define SYSCALL sqlite3_syscall_ptr
#endif
#include <dfs_posix.h>
static int _Access(const char *pathname, int mode)
{
int fd;
fd = open(pathname, O_RDONLY, mode);
if (fd >= 0)
{
close(fd);
return 0;
}
return -1;
}
/*
** Invoke open(). Do so multiple times, until it either succeeds or
** fails for some reason other than EINTR.
**
** If the file creation mode "m" is 0 then set it to the default for
** SQLite. The default is SQLITE_DEFAULT_FILE_PERMISSIONS (normally
** 0644) as modified by the system umask. If m is not 0, then
** make the file creation mode be exactly m ignoring the umask.
**
** The m parameter will be non-zero only when creating -wal, -journal,
** and -shm files. We want those files to have *exactly* the same
** permissions as their original database, unadulterated by the umask.
** In that way, if a database file is -rw-rw-rw or -rw-rw-r-, and a
** transaction crashes and leaves behind hot journals, then any
** process that is able to write to the database will also be able to
** recover the hot journals.
*/
static int robust_open(const char *z, int f, mode_t m);
/*
** Open a file descriptor to the directory containing file zFilename.
** If successful, *pFd is set to the opened file descriptor and
** SQLITE_OK is returned. If an error occurs, either SQLITE_NOMEM
** or SQLITE_CANTOPEN is returned and *pFd is set to an undefined
** value.
**
** The directory file descriptor is used for only one thing - to
** fsync() a directory to make sure file creation and deletion events
** are flushed to disk. Such fsyncs are not needed on newer
** journaling filesystems, but are required on older filesystems.
**
** This routine can be overridden using the xSetSysCall interface.
** The ability to override this routine was added in support of the
** chromium sandbox. Opening a directory is a security risk (we are
** told) so making it overrideable allows the chromium sandbox to
** replace this routine with a harmless no-op. To make this routine
** a no-op, replace it with a stub that returns SQLITE_OK but leaves
** *pFd set to a negative number.
**
** If SQLITE_OK is returned, the caller is responsible for closing
** the file descriptor *pFd using close().
*/
static int openDirectory(const char *zFilename, int *pFd);
/*
** Many system calls are accessed through pointer-to-functions so that
** they may be overridden at runtime to facilitate fault injection during
** testing and sandboxing. The following array holds the names and pointers
** to all overrideable system calls.
*/
static struct rtt_syscall {
const char *zName; /* Name of the system call */
sqlite3_syscall_ptr pCurrent; /* Current value of the system call */
sqlite3_syscall_ptr pDefault; /* Default value */
} aSyscall[] = {
{"sleep", (sqlite3_syscall_ptr)rt_thread_delay, 0},
#define osSleep ((rt_err_t(*)(rt_tick_t))aSyscall[0].pCurrent)
{ "open", (sqlite3_syscall_ptr)open, 0 },
#define osOpen ((int(*)(const char*,int,int))aSyscall[1].pCurrent)
{ "close", (sqlite3_syscall_ptr)close, 0 },
#define osClose ((int(*)(int))aSyscall[2].pCurrent)
{ "getcwd", (sqlite3_syscall_ptr)getcwd, 0 },
#define osGetcwd ((char*(*)(char*,size_t))aSyscall[3].pCurrent)
{ "stat", (sqlite3_syscall_ptr)stat, 0 },
#define osStat ((int(*)(const char*,struct stat*))aSyscall[4].pCurrent)
{ "fstat", (sqlite3_syscall_ptr)fstat, 0 },
#define osFstat ((int(*)(int,struct stat*))aSyscall[5].pCurrent)
{ "read", (sqlite3_syscall_ptr)read, 0 },
#define osRead ((ssize_t(*)(int,void*,size_t))aSyscall[6].pCurrent)
{ "write", (sqlite3_syscall_ptr)write, 0 },
#define osWrite ((ssize_t(*)(int,const void*,size_t))aSyscall[7].pCurrent)
{ "unlink", (sqlite3_syscall_ptr)unlink, 0 },
#define osUnlink ((int(*)(const char*))aSyscall[8].pCurrent)
{ "openDirectory", (sqlite3_syscall_ptr)openDirectory, 0 },
#define osOpenDirectory ((int(*)(const char*,int*))aSyscall[9].pCurrent)
{ "mkdir", (sqlite3_syscall_ptr)mkdir, 0 },
#define osMkdir ((int(*)(const char*,mode_t))aSyscall[10].pCurrent)
{ "rmdir", (sqlite3_syscall_ptr)rmdir, 0 },
#define osRmdir ((int(*)(const char*))aSyscall[11].pCurrent)
{"access", (sqlite3_syscall_ptr)_Access, 0 },
#define osAccess ((int(*)(const char*, int))aSyscall[12].pCurrent)
}; /* End of the overrideable system calls */
/*
** Do not accept any file descriptor less than this value, in order to avoid
** opening database file using file descriptors that are commonly used for
** standard input, output, and error.
*/
#ifndef SQLITE_MINIMUM_FILE_DESCRIPTOR
# define SQLITE_MINIMUM_FILE_DESCRIPTOR 3
#endif
/*
** Invoke open(). Do so multiple times, until it either succeeds or
** fails for some reason other than EINTR.
**
** If the file creation mode "m" is 0 then set it to the default for
** SQLite. The default is SQLITE_DEFAULT_FILE_PERMISSIONS (normally
** 0644) as modified by the system umask. If m is not 0, then
** make the file creation mode be exactly m ignoring the umask.
**
** The m parameter will be non-zero only when creating -wal, -journal,
** and -shm files. We want those files to have *exactly* the same
** permissions as their original database, unadulterated by the umask.
** In that way, if a database file is -rw-rw-rw or -rw-rw-r-, and a
** transaction crashes and leaves behind hot journals, then any
** process that is able to write to the database will also be able to
** recover the hot journals.
*/
static int robust_open(const char *z, int f, mode_t m){
int fd;
mode_t m2 = m ;
while(1){
#if defined(O_CLOEXEC)
fd = osOpen(z,f|O_CLOEXEC,m2);
#else
fd = osOpen(z,f,m2);
#endif
if( fd<0 ){
if( errno==EINTR ) continue;
break;
}
if( fd>=SQLITE_MINIMUM_FILE_DESCRIPTOR ) break;
osClose(fd);
sqlite3_log(SQLITE_WARNING,
"attempt to open \"%s\" as file descriptor %d", z, fd);
fd = -1;
if( osOpen("/dev/null", f, m)<0 ) break;
}
return fd;
}
/*
** Open a file descriptor to the directory containing file zFilename.
** If successful, *pFd is set to the opened file descriptor and
** SQLITE_OK is returned. If an error occurs, either SQLITE_NOMEM
** or SQLITE_CANTOPEN is returned and *pFd is set to an undefined
** value.
**
** The directory file descriptor is used for only one thing - to
** fsync() a directory to make sure file creation and deletion events
** are flushed to disk. Such fsyncs are not needed on newer
** journaling filesystems, but are required on older filesystems.
**
** This routine can be overridden using the xSetSysCall interface.
** The ability to override this routine was added in support of the
** chromium sandbox. Opening a directory is a security risk (we are
** told) so making it overrideable allows the chromium sandbox to
** replace this routine with a harmless no-op. To make this routine
** a no-op, replace it with a stub that returns SQLITE_OK but leaves
** *pFd set to a negative number.
**
** If SQLITE_OK is returned, the caller is responsible for closing
** the file descriptor *pFd using close().
*/
static int openDirectory(const char *zFilename, int *pFd){
int ii;
int fd = -1;
char zDirname[MAX_PATHNAME+1];
sqlite3_snprintf(MAX_PATHNAME, zDirname, "%s", zFilename);
for(ii=(int)strlen(zDirname); ii>1 && zDirname[ii]!='/'; ii--);
if( ii>0 ){
zDirname[ii] = '\0';
fd = robust_open(zDirname, O_RDONLY|O_BINARY, 0);
if( fd>=0 ){
OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname));
}
}
*pFd = fd;
return (fd>=0?SQLITE_OK:rttLogError(SQLITE_CANTOPEN_BKPT, "open", zDirname));
}
/*
** This is the xSetSystemCall() method of sqlite3_vfs for all of the
** "win32" VFSes. Return SQLITE_OK opon successfully updating the
** system call pointer, or SQLITE_NOTFOUND if there is no configurable
** system call named zName.
*/
static int rttSetSystemCall(
sqlite3_vfs *pNotUsed, /* The VFS pointer. Not used */
const char *zName, /* Name of system call to override */
sqlite3_syscall_ptr pNewFunc /* Pointer to new system call value */
){
unsigned int i;
int rc = SQLITE_NOTFOUND;
UNUSED_PARAMETER(pNotUsed);
if( zName==0 ){
/* If no zName is given, restore all system calls to their default
** settings and return NULL
*/
rc = SQLITE_OK;
for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
if( aSyscall[i].pDefault ){
aSyscall[i].pCurrent = aSyscall[i].pDefault;
}
}
}else{
/* If zName is specified, operate on only the one system call
** specified.
*/
for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
if( strcmp(zName, aSyscall[i].zName)==0 ){
if( aSyscall[i].pDefault==0 ){
aSyscall[i].pDefault = aSyscall[i].pCurrent;
}
rc = SQLITE_OK;
if( pNewFunc==0 ) pNewFunc = aSyscall[i].pDefault;
aSyscall[i].pCurrent = pNewFunc;
break;
}
}
}
return rc;
}
/*
** Return the value of a system call. Return NULL if zName is not a
** recognized system call name. NULL is also returned if the system call
** is currently undefined.
*/
static sqlite3_syscall_ptr rttGetSystemCall(
sqlite3_vfs *pNotUsed,
const char *zName
){
unsigned int i;
UNUSED_PARAMETER(pNotUsed);
for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
if( strcmp(zName, aSyscall[i].zName)==0 ) return aSyscall[i].pCurrent;
}
return 0;
}
/*
** Return the name of the first system call after zName. If zName==NULL
** then return the name of the first system call. Return NULL if zName
** is the last system call or if zName is not the name of a valid
** system call.
*/
static const char *rttNextSystemCall(sqlite3_vfs *p, const char *zName){
int i = -1;
UNUSED_PARAMETER(p);
if( zName ){
for(i=0; i<ArraySize(aSyscall)-1; i++){
if( strcmp(zName, aSyscall[i].zName)==0 ) break;
}
}
for(i++; i<ArraySize(aSyscall); i++){
if( aSyscall[i].pCurrent!=0 ) return aSyscall[i].zName;
}
return 0;
}
/*
** The following routine suspends the current thread for at least ms
** milliseconds. This is equivalent to the Win32 Sleep() interface.
*/
void sqlite3_rtt_sleep(int milliseconds){
rt_tick_t sleep_tick;
if (milliseconds <= 0)
return;
sleep_tick = rt_tick_from_millisecond(milliseconds);
osSleep(sleep_tick);
}
/*
** Helper functions to obtain and relinquish the global mutex. The
** global mutex is used to protect the unixInodeInfo and
** vxworksFileId objects used by this file, all of which may be
** shared by multiple threads.
**
** Function unixMutexHeld() is used to assert() that the global mutex
** is held when required. This function is only used as part of assert()
** statements. e.g.
**
** unixEnterMutex()
** assert( unixMutexHeld() );
** unixEnterLeave()
*/
static void rttEnterMutex(void){
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
}
static void rttLeaveMutex(void){
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
}
#ifdef SQLITE_DEBUG
static int rttMutexHeld(void) {
return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
}
#endif
#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
/*
** Helper function for printing out trace information from debugging
** binaries. This returns the string represetation of the supplied
** integer lock-type.
*/
static const char *azFileLock(int eFileLock){
switch( eFileLock ){
case NO_LOCK: return "NONE";
case SHARED_LOCK: return "SHARED";
case RESERVED_LOCK: return "RESERVED";
case PENDING_LOCK: return "PENDING";
case EXCLUSIVE_LOCK: return "EXCLUSIVE";
}
return "ERROR";
}
#endif
/*
** This routine translates a standard POSIX errno code into something
** useful to the clients of the sqlite3 functions. Specifically, it is
** intended to translate a variety of "try again" errors into SQLITE_BUSY
** and a variety of "please close the file descriptor NOW" errors into
** SQLITE_IOERR
**
** Errors during initialization of locks, or file system support for locks,
** should handle ENOLCK, ENOTSUP, EOPNOTSUPP separately.
*/
static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) {
switch (posixError) {
#if 0
/* At one point this code was not commented out. In theory, this branch
** should never be hit, as this function should only be called after
** a locking-related function (i.e. fcntl()) has returned non-zero with
** the value of errno as the first argument. Since a system call has failed,
** errno should be non-zero.
**
** Despite this, if errno really is zero, we still don't want to return
** SQLITE_OK. The system call failed, and *some* SQLite error should be
** propagated back to the caller. Commenting this branch out means errno==0
** will be handled by the "default:" case below.
*/
case 0:
return SQLITE_OK;
#endif
case EAGAIN:
case ETIMEDOUT:
case EBUSY:
case EINTR:
case ENOLCK:
/* random NFS retry error, unless during file system support
* introspection, in which it actually means what it says */
return SQLITE_BUSY;
case EACCES:
/* EACCES is like EAGAIN during locking operations, but not any other time*/
if( (sqliteIOErr == SQLITE_IOERR_LOCK) ||
(sqliteIOErr == SQLITE_IOERR_UNLOCK) ||
(sqliteIOErr == SQLITE_IOERR_RDLOCK) ||
(sqliteIOErr == SQLITE_IOERR_CHECKRESERVEDLOCK) ){
return SQLITE_BUSY;
}
/* else fall through */
case EPERM:
return SQLITE_PERM;
/* EDEADLK is only possible if a call to fcntl(F_SETLKW) is made. And
** this module never makes such a call. And the code in SQLite itself
** asserts that SQLITE_IOERR_BLOCKED is never returned. For these reasons
** this case is also commented out. If the system does set errno to EDEADLK,
** the default SQLITE_IOERR_XXX code will be returned. */
#if 0
case EDEADLK:
return SQLITE_IOERR_BLOCKED;
#endif
#if EOPNOTSUPP!=ENOTSUP
case EOPNOTSUPP:
/* something went terribly awry, unless during file system support
* introspection, in which it actually means what it says */
#endif
#ifdef ENOTSUP
case ENOTSUP:
/* invalid fd, unless during file system support introspection, in which
* it actually means what it says */
#endif
case EIO:
case EBADF:
case EINVAL:
case ENOTCONN:
case ENODEV:
case ENXIO:
case ENOENT:
#ifdef ESTALE /* ESTALE is not defined on Interix systems */
case ESTALE:
#endif
case ENOSYS:
/* these should force the client to close the file and reconnect */
default:
return sqliteIOErr;
}
}
/*
**
** This function - unixLogError_x(), is only ever called via the macro
** unixLogError().
**
** It is invoked after an error occurs in an OS function and errno has been
** set. It logs a message using sqlite3_log() containing the current value of
** errno and, if possible, the human-readable equivalent from strerror() or
** strerror_r().
**
** The first argument passed to the macro should be the error code that
** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN).
** The two subsequent arguments should be the name of the OS function that
** failed (e.g. "unlink", "open") and the associated file-system path,
** if any.
*/
#define rttLogError(a,b,c) rttLogErrorAtLine(a,b,c,__LINE__)
static int rttLogErrorAtLine(
int errcode, /* SQLite error code */
const char *zFunc, /* Name of OS function that failed */
const char *zPath, /* File path associated with error */
int iLine /* Source line number where error occurred */
){
char *zErr; /* Message from strerror() or equivalent */
int iErrno = errno; /* Saved syscall error number */
/* If this is not a threadsafe build (SQLITE_THREADSAFE==0), then use
** the strerror() function to obtain the human-readable error message
** equivalent to errno. Otherwise, use strerror_r().
*/
#if SQLITE_THREADSAFE && defined(HAVE_STRERROR_R)
char aErr[80];
memset(aErr, 0, sizeof(aErr));
zErr = aErr;
/* If STRERROR_R_CHAR_P (set by autoconf scripts) or __USE_GNU is defined,
** assume that the system provides the GNU version of strerror_r() that
** returns a pointer to a buffer containing the error message. That pointer
** may point to aErr[], or it may point to some static storage somewhere.
** Otherwise, assume that the system provides the POSIX version of
** strerror_r(), which always writes an error message into aErr[].
**
** If the code incorrectly assumes that it is the POSIX version that is
** available, the error message will often be an empty string. Not a
** huge problem. Incorrectly concluding that the GNU version is available
** could lead to a segfault though.
*/
#if defined(STRERROR_R_CHAR_P) || defined(__USE_GNU)
zErr =
# endif
strerror_r(iErrno, aErr, sizeof(aErr)-1);
#elif SQLITE_THREADSAFE
/* This is a threadsafe build, but strerror_r() is not available. */
zErr = "";
#else
/* Non-threadsafe build, use strerror(). */
zErr = strerror(iErrno);
#endif
if( zPath==0 ) zPath = "";
sqlite3_log(errcode,
"os_rtt.c:%d: (%d) %s(%s) - %s",
iLine, iErrno, zFunc, zPath, zErr
);
return errcode;
}
static int robust_ftruncate(int h, sqlite3_int64 sz){
int rc;
rc = -1;
return rc;
}
/*
** Close a file descriptor.
**
** We assume that close() almost always works, since it is only in a
** very sick application or on a very sick platform that it might fail.
** If it does fail, simply leak the file descriptor, but do log the
** error.
**
** Note that it is not safe to retry close() after EINTR since the
** file descriptor might have already been reused by another thread.
** So we don't even try to recover from an EINTR. Just log the error
** and move on.
*/
static void robust_close(rttFile *pFile, int h, int lineno){
if( osClose(h) ){
rttLogErrorAtLine(SQLITE_IOERR_CLOSE, "close",
pFile ? pFile->zPath : 0, lineno);
}
}
/*
** Check a rttFile that is a database. Verify the following:
**
** (1) There is exactly one hard link on the file
** (2) The file is not a symbolic link
** (3) The file has not been renamed or unlinked
**
** Issue sqlite3_log(SQLITE_WARNING,...) messages if anything is not right.
*/
static void verifyDbFile(rttFile *pFile){
struct stat buf;
int rc;
if( pFile->ctrlFlags & UNIXFILE_WARNED ){
/* One or more of the following warnings have already been issued. Do not
** repeat them so as not to clutter the error log */
return;
}
rc = osFstat(pFile->h, &buf);
if( rc!=0 ){
sqlite3_log(SQLITE_WARNING, "cannot fstat db file %s", pFile->zPath);
pFile->ctrlFlags |= UNIXFILE_WARNED;
return;
}
if( buf.st_nlink==0 && (pFile->ctrlFlags & UNIXFILE_DELETE)==0 ){
sqlite3_log(SQLITE_WARNING, "file unlinked while open: %s", pFile->zPath);
pFile->ctrlFlags |= UNIXFILE_WARNED;
return;
}
}
/*
** This function performs the parts of the "close file" operation
** common to all locking schemes. It closes the directory and file
** handles, if they are valid, and sets all fields of the rttFile
** structure to 0.
**
** It is *not* necessary to hold the mutex when this routine is called,
** even on VxWorks. A mutex will be acquired on VxWorks by the
** vxworksReleaseFileId() routine.
*/
static int closeRttFile(sqlite3_file *id){
rttFile *pFile = (rttFile*)id;
if( pFile->h>=0 ){
robust_close(pFile, pFile->h, __LINE__);
pFile->h = -1;
}
OSTRACE(("CLOSE %-3d\n", pFile->h));
OpenCounter(-1);
memset(pFile, 0, sizeof(rttFile));
return SQLITE_OK;
}
/************** End of the posix advisory lock implementation *****************
******************************************************************************/
/******************************************************************************
****************************** No-op Locking **********************************
**
** Of the various locking implementations available, this is by far the
** simplest: locking is ignored. No attempt is made to lock the database
** file for reading or writing.
**
** This locking mode is appropriate for use on read-only databases
** (ex: databases that are burned into CD-ROM, for example.) It can
** also be used if the application employs some external mechanism to
** prevent simultaneous access of the same database by two or more
** database connections. But there is a serious risk of database
** corruption if this locking mode is used in situations where multiple
** database connections are accessing the same database file at the same
** time and one or more of those connections are writing.
*/
static int nolockCheckReservedLock(sqlite3_file *NotUsed, int *pResOut){
UNUSED_PARAMETER(NotUsed);
*pResOut = 0;
return SQLITE_OK;
}
static int nolockLock(sqlite3_file *NotUsed, int NotUsed2){
UNUSED_PARAMETER2(NotUsed, NotUsed2);
return SQLITE_OK;
}
static int nolockUnlock(sqlite3_file *NotUsed, int NotUsed2){
UNUSED_PARAMETER2(NotUsed, NotUsed2);
return SQLITE_OK;
}
/*
** Close the file.
*/
static int nolockClose(sqlite3_file *id) {
return closeRttFile(id);
}
/******************* End of the no-op lock implementation *********************
******************************************************************************/
/******************************************************************************
************************* Begin dot-file Locking ******************************
**
** The dotfile locking implementation uses the existence of separate lock
** files (really a directory) to control access to the database. This works
** on just about every filesystem imaginable. But there are serious downsides:
**
** (1) There is zero concurrency. A single reader blocks all other
** connections from reading or writing the database.
**
** (2) An application crash or power loss can leave stale lock files
** sitting around that need to be cleared manually.
**
** Nevertheless, a dotlock is an appropriate locking mode for use if no
** other locking strategy is available.
**
** Dotfile locking works by creating a subdirectory in the same directory as
** the database and with the same name but with a ".lock" extension added.
** The existence of a lock directory implies an EXCLUSIVE lock. All other
** lock types (SHARED, RESERVED, PENDING) are mapped into EXCLUSIVE.
*/
/*
** The file suffix added to the data base filename in order to create the
** lock directory.
*/
#define DOTLOCK_SUFFIX ".lock"
/*
** This routine checks if there is a RESERVED lock held on the specified
** file by this or any other process. If such a lock is held, set *pResOut
** to a non-zero value otherwise *pResOut is set to zero. The return value
** is set to SQLITE_OK unless an I/O error occurs during lock checking.
**
** In dotfile locking, either a lock exists or it does not. So in this
** variation of CheckReservedLock(), *pResOut is set to true if any lock
** is held on the file and false if the file is unlocked.
*/
static int dotlockCheckReservedLock(sqlite3_file *id, int *pResOut) {
int rc = SQLITE_OK;
int reserved = 0;
rttFile *pFile = (rttFile*)id;
SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
assert( pFile );
/* Check if a thread in this process holds such a lock */
if( pFile->eFileLock>SHARED_LOCK ){
/* Either this connection or some other connection in the same process
** holds a lock on the file. No need to check further. */
reserved = 1;
}else{
/* The lock is held if and only if the lockfile exists */
const char *zLockFile = (const char*)pFile->lockingContext;
reserved = 0;
}
OSTRACE(("TEST WR-LOCK %d %d %d (dotlock)\n", pFile->h, rc, reserved));
*pResOut = reserved;
return rc;
}
/*
** Lock the file with the lock specified by parameter eFileLock - one
** of the following:
**
** (1) SHARED_LOCK
** (2) RESERVED_LOCK
** (3) PENDING_LOCK
** (4) EXCLUSIVE_LOCK
**
** 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
**
** This routine will only increase a lock. Use the sqlite3OsUnlock()
** routine to lower a locking level.
**
** With dotfile locking, we really only support state (4): EXCLUSIVE.
** But we track the other locking levels internally.
*/
static int dotlockLock(sqlite3_file *id, int eFileLock) {
rttFile *pFile = (rttFile*)id;
char *zLockFile = (char *)pFile->lockingContext;
int rc = SQLITE_OK;
/* If we have any lock, then the lock file already exists. All we have
** to do is adjust our internal record of the lock level.
*/
if( pFile->eFileLock > NO_LOCK ){
pFile->eFileLock = eFileLock;
return SQLITE_OK;
}
/* grab an exclusive lock */
rc = osMkdir(zLockFile, 0777);
if( rc<0 ){
/* failed to open/create the lock directory */
int tErrno = errno;
if( EEXIST == tErrno ){
rc = SQLITE_BUSY;
} else {
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
if( IS_LOCK_ERROR(rc) ){
pFile->lastErrno = tErrno;
}
}
return rc;
}
/* got it, set the type and return ok */
pFile->eFileLock = eFileLock;
return rc;
}
/*
** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
** must be either NO_LOCK or SHARED_LOCK.
**
** If the locking level of the file descriptor is already at or below
** the requested locking level, this routine is a no-op.
**
** When the locking level reaches NO_LOCK, delete the lock file.
*/
static int dotlockUnlock(sqlite3_file *id, int eFileLock) {
rttFile *pFile = (rttFile*)id;
char *zLockFile = (char *)pFile->lockingContext;
int rc;
assert( pFile );
OSTRACE(("UNLOCK %d %d was %d tnm=%s (dotlock)\n", pFile->h, eFileLock,
pFile->eFileLock, rt_thread_self()->name ));
assert( eFileLock<=SHARED_LOCK );
/* no-op if possible */
if( pFile->eFileLock==eFileLock ){
return SQLITE_OK;
}
/* To downgrade to shared, simply update our internal notion of the
** lock state. No need to mess with the file on disk.
*/
if( eFileLock==SHARED_LOCK ){
pFile->eFileLock = SHARED_LOCK;
return SQLITE_OK;
}
/* To fully unlock the database, delete the lock file */
assert( eFileLock==NO_LOCK );
rc = osRmdir(zLockFile);
if( rc<0 && errno==ENOTDIR ) rc = osUnlink(zLockFile);
if( rc<0 ){
int tErrno = errno;
rc = 0;
if( ENOENT != tErrno ){
rc = SQLITE_IOERR_UNLOCK;
}
if( IS_LOCK_ERROR(rc) ){
pFile->lastErrno = tErrno;
}
return rc;
}
pFile->eFileLock = NO_LOCK;
return SQLITE_OK;
}
/*
** Close a file. Make sure the lock has been released before closing.
*/
static int dotlockClose(sqlite3_file *id) {
int rc = SQLITE_OK;
if( id ){
rttFile *pFile = (rttFile*)id;
dotlockUnlock(id, NO_LOCK);
sqlite3_free(pFile->lockingContext);
rc = closeRttFile(id);
}
return rc;
}
/****************** End of the dot-file lock implementation *******************
******************************************************************************/
/******************************************************************************
************************** Begin flock Locking ********************************
**
** Use the flock() system call to do file locking.
**
** flock() locking is like dot-file locking in that the various
** fine-grain locking levels supported by SQLite are collapsed into
** a single exclusive lock. In other words, SHARED, RESERVED, and
** PENDING locks are the same thing as an EXCLUSIVE lock. SQLite
** still works when you do this, but concurrency is reduced since
** only a single process can be reading the database at a time.
**
** Omit this section if SQLITE_ENABLE_LOCKING_STYLE is turned off or if
** compiling for VXWORKS.
*/
#if SQLITE_ENABLE_LOCKING_STYLE
#warning "rtt file lock not available"
/*
** Retry flock() calls that fail with EINTR
*/
static int robust_flock(int fd, int op){
int rc = 0;
return rc;
}
/*
** This routine checks if there is a RESERVED lock held on the specified
** file by this or any other process. If such a lock is held, set *pResOut
** to a non-zero value otherwise *pResOut is set to zero. The return value
** is set to SQLITE_OK unless an I/O error occurs during lock checking.
*/
static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){
int rc = SQLITE_OK;
int reserved = 0;
rttFile *pFile = (rttFile*)id;
SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
assert( pFile );
/* Check if a thread in this process holds such a lock */
if( pFile->eFileLock>SHARED_LOCK ){
reserved = 1;
}
/* Otherwise see if some other process holds it. */
if( !reserved ){
/* attempt to get the lock */
int lrc = robust_flock(pFile->h, LOCK_EX | LOCK_NB);
if( !lrc ){
/* got the lock, unlock it */
lrc = robust_flock(pFile->h, LOCK_UN);
if ( lrc ) {
int tErrno = errno;
/* unlock failed with an error */
lrc = SQLITE_IOERR_UNLOCK;
if( IS_LOCK_ERROR(lrc) ){
pFile->lastErrno = tErrno;
rc = lrc;
}
}
} else {
int tErrno = errno;
reserved = 1;
/* someone else might have it reserved */
lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
if( IS_LOCK_ERROR(lrc) ){
pFile->lastErrno = tErrno;
rc = lrc;
}
}
}
OSTRACE(("TEST WR-LOCK %d %d %d (flock)\n", pFile->h, rc, reserved));
#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
if( (rc & SQLITE_IOERR) == SQLITE_IOERR ){
rc = SQLITE_OK;
reserved=1;
}
#endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */
*pResOut = reserved;
return rc;
}
/*
** Lock the file with the lock specified by parameter eFileLock - one
** of the following:
**
** (1) SHARED_LOCK
** (2) RESERVED_LOCK
** (3) PENDING_LOCK
** (4) EXCLUSIVE_LOCK
**
** 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
**
** flock() only really support EXCLUSIVE locks. We track intermediate
** lock states in the sqlite3_file structure, but all locks SHARED or
** above are really EXCLUSIVE locks and exclude all other processes from
** access the file.
**
** This routine will only increase a lock. Use the sqlite3OsUnlock()
** routine to lower a locking level.
*/
static int flockLock(sqlite3_file *id, int eFileLock) {
int rc = SQLITE_OK;
rttFile *pFile = (rttFile*)id;
assert( pFile );
/* if we already have a lock, it is exclusive.
** Just adjust level and punt on outta here. */
if (pFile->eFileLock > NO_LOCK) {
pFile->eFileLock = eFileLock;
return SQLITE_OK;
}
/* grab an exclusive lock */
if (robust_flock(pFile->h, LOCK_EX | LOCK_NB)) {
int tErrno = errno;
/* didn't get, must be busy */
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
if( IS_LOCK_ERROR(rc) ){
pFile->lastErrno = tErrno;
}
} else {
/* got it, set the type and return ok */
pFile->eFileLock = eFileLock;
}
OSTRACE(("LOCK %d %s %s (flock)\n", pFile->h, azFileLock(eFileLock),
rc==SQLITE_OK ? "ok" : "failed"));
#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
if( (rc & SQLITE_IOERR) == SQLITE_IOERR ){
rc = SQLITE_BUSY;
}
#endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */
return rc;
}
/*
** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
** must be either NO_LOCK or SHARED_LOCK.
**
** If the locking level of the file descriptor is already at or below
** the requested locking level, this routine is a no-op.
*/
static int flockUnlock(sqlite3_file *id, int eFileLock) {
rttFile *pFile = (rttFile*)id;
assert( pFile );
OSTRACE(("UNLOCK %d %d was %d tnm=%s (flock)\n", pFile->h, eFileLock,
pFile->eFileLock, rt_thread_self()->name));
assert( eFileLock<=SHARED_LOCK );
/* no-op if possible */
if( pFile->eFileLock==eFileLock ){
return SQLITE_OK;
}
/* shared can just be set because we always have an exclusive */
if (eFileLock==SHARED_LOCK) {
pFile->eFileLock = eFileLock;
return SQLITE_OK;
}
/* no, really, unlock. */
if( robust_flock(pFile->h, LOCK_UN) ){
#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
return SQLITE_OK;
#endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */
return SQLITE_IOERR_UNLOCK;
}else{
pFile->eFileLock = NO_LOCK;
return SQLITE_OK;
}
}
/*
** Close a file.
*/
static int flockClose(sqlite3_file *id) {
int rc = SQLITE_OK;
if( id ){
flockUnlock(id, NO_LOCK);
rc = closeRttFile(id);
}
return rc;
}
#endif /* SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORK */
/******************* End of the flock lock implementation *********************
******************************************************************************/
/******************************************************************************
**************** Non-locking sqlite3_file methods *****************************
**
** The next division contains implementations for all methods of the
** sqlite3_file object other than the locking methods. The locking
** methods were defined in divisions above (one locking method per
** division). Those methods that are common to all locking modes
** are gather together into this division.
*/
/*
** Seek to the offset passed as the second argument, then read cnt
** bytes into pBuf. Return the number of bytes actually read.
**
** NB: If you define USE_PREAD or USE_PREAD64, then it might also
** be necessary to define _XOPEN_SOURCE to be 500. This varies from
** one system to another. Since SQLite does not define USE_PREAD
** any any form by default, we will not attempt to define _XOPEN_SOURCE.
** See tickets #2741 and #2681.
**
** To avoid stomping the errno value on a failed read the lastErrno value
** is set before returning.
*/
static int seekAndRead(rttFile *id, sqlite3_int64 offset, void *pBuf, int cnt){
int got;
int prior = 0;
#if (!defined(USE_PREAD) && !defined(USE_PREAD64))
i64 newOffset;
#endif
TIMER_START;
assert( cnt==(cnt&0x1ffff) );
assert( id->h>2 );
cnt &= 0x1ffff;
do{
#if defined(USE_PREAD)
#error "rtt pread not support"
got = osPread(id->h, pBuf, cnt, offset);
SimulateIOError( got = -1 );
#elif defined(USE_PREAD64)
#error "rtt pread64 not support"
got = osPread64(id->h, pBuf, cnt, offset);
SimulateIOError( got = -1 );
#else
newOffset = lseek(id->h, offset, SEEK_SET);
SimulateIOError( newOffset-- );
if( newOffset!=offset ){
if( newOffset == -1 ){
((rttFile*)id)->lastErrno = errno;
}else{
((rttFile*)id)->lastErrno = 0;
}
return -1;
}
got = osRead(id->h, pBuf, cnt);
#endif
if( got==cnt ) break;
if( got<0 ){
if( errno==EINTR ){ got = 1; continue; }
prior = 0;
((rttFile*)id)->lastErrno = errno;
break;
}else if( got>0 ){
cnt -= got;
offset += got;
prior += got;
pBuf = (void*)(got + (char*)pBuf);
}
}while( got>0 );
TIMER_END;
OSTRACE(("READ %-3d %5d %7lld %llu\n",
id->h, got+prior, offset-prior, TIMER_ELAPSED));
return got+prior;
}
/*
** Read data from a file into a buffer. Return SQLITE_OK if all
** bytes were read successfully and SQLITE_IOERR if anything goes
** wrong.
*/
static int rttRead(
sqlite3_file *id,
void *pBuf,
int amt,
sqlite3_int64 offset
){
rttFile *pFile = (rttFile *)id;
int got;
assert( id );
assert( offset>=0 );
assert( amt>0 );
got = seekAndRead(pFile, offset, pBuf, amt);
if( got==amt ){
return SQLITE_OK;
}else if( got<0 ){
/* lastErrno set by seekAndRead */
return SQLITE_IOERR_READ;
}else{
pFile->lastErrno = 0; /* not a system error */
/* Unread parts of the buffer must be zero-filled */
memset(&((char*)pBuf)[got], 0, amt-got);
return SQLITE_IOERR_SHORT_READ;
}
}
/*
** Attempt to seek the file-descriptor passed as the first argument to
** absolute offset iOff, then attempt to write nBuf bytes of data from
** pBuf to it. If an error occurs, return -1 and set *piErrno. Otherwise,
** return the actual number of bytes written (which may be less than
** nBuf).
*/
static int seekAndWriteFd(
int fd, /* File descriptor to write to */
i64 iOff, /* File offset to begin writing at */
const void *pBuf, /* Copy data from this buffer to the file */
int nBuf, /* Size of buffer pBuf in bytes */
int *piErrno /* OUT: Error number if error occurs */
){
int rc = 0; /* Value returned by system call */
assert( nBuf==(nBuf&0x1ffff) );
assert( fd>2 );
nBuf &= 0x1ffff;
TIMER_START;
#if defined(USE_PREAD)
do{ rc = osPwrite(fd, pBuf, nBuf, iOff); }while( rc<0 && errno==EINTR );
#elif defined(USE_PREAD64)
do{ rc = osPwrite64(fd, pBuf, nBuf, iOff);}while( rc<0 && errno==EINTR);
#else
do{
i64 iSeek = lseek(fd, iOff, SEEK_SET);
SimulateIOError( iSeek-- );
if( iSeek!=iOff ){
if( piErrno ) *piErrno = (iSeek==-1 ? errno : 0);
return -1;
}
rc = osWrite(fd, pBuf, nBuf);
}while( rc<0 && errno==EINTR );
#endif
TIMER_END;
OSTRACE(("WRITE %-3d %5d %7lld %llu\n", fd, rc, iOff, TIMER_ELAPSED));
if( rc<0 && piErrno ) *piErrno = errno;
return rc;
}
/*
** Seek to the offset in id->offset then read cnt bytes into pBuf.
** Return the number of bytes actually read. Update the offset.
**
** To avoid stomping the errno value on a failed write the lastErrno value
** is set before returning.
*/
static int seekAndWrite(rttFile *id, i64 offset, const void *pBuf, int cnt){
return seekAndWriteFd(id->h, offset, pBuf, cnt, &id->lastErrno);
}
/*
** Write data from a buffer into a file. Return SQLITE_OK on success
** or some other error code on failure.
*/
static int rttWrite(
sqlite3_file *id,
const void *pBuf,
int amt,
sqlite3_int64 offset
){
rttFile *pFile = (rttFile*)id;
int wrote = 0;
assert( id );
assert( amt>0 );
#ifdef SQLITE_DEBUG
/* If we are doing a normal write to a database file (as opposed to
** doing a hot-journal rollback or a write to some file other than a
** normal database file) then record the fact that the database
** has changed. If the transaction counter is modified, record that
** fact too.
*/
if( pFile->inNormalWrite ){
pFile->dbUpdate = 1; /* The database has been modified */
if( offset<=24 && offset+amt>=27 ){
int rc;
char oldCntr[4];
SimulateIOErrorBenign(1);
rc = seekAndRead(pFile, 24, oldCntr, 4);
SimulateIOErrorBenign(0);
if( rc!=4 || memcmp(oldCntr, &((char*)pBuf)[24-offset], 4)!=0 ){
pFile->transCntrChng = 1; /* The transaction counter has changed */
}
}
}
#endif
while( amt>0 && (wrote = seekAndWrite(pFile, offset, pBuf, amt))>0 ){
amt -= wrote;
offset += wrote;
pBuf = &((char*)pBuf)[wrote];
}
SimulateIOError(( wrote=(-1), amt=1 ));
SimulateDiskfullError(( wrote=0, amt=1 ));
if( amt>0 ){
if( wrote<0 && pFile->lastErrno!=ENOSPC ){
/* lastErrno set by seekAndWrite */
return SQLITE_IOERR_WRITE;
}else{
pFile->lastErrno = 0; /* not a system error */
return SQLITE_FULL;
}
}
return SQLITE_OK;
}
#ifdef SQLITE_TEST
/*
** Count the number of fullsyncs and normal syncs. This is used to test
** that syncs and fullsyncs are occurring at the right times.
*/
int sqlite3_sync_count = 0;
int sqlite3_fullsync_count = 0;
#endif
/*
** We do not trust systems to provide a working fdatasync(). Some do.
** Others do no. To be safe, we will stick with the (slightly slower)
** fsync(). If you know that your system does support fdatasync() correctly,
** then simply compile with -Dfdatasync=fdatasync
*/
#if !defined(fdatasync)
#include "dfs.h"
#include "dfs_file.h"
int fdatasync(fd)
{
struct dfs_fd *dfs_fd;
dfs_fd = fd_get(fd);
return dfs_file_flush(dfs_fd);
}
#endif
/*
** Define HAVE_FULLFSYNC to 0 or 1 depending on whether or not
** the F_FULLFSYNC macro is defined. F_FULLFSYNC is currently
** only available on Mac OS X. But that could change.
*/
#ifdef F_FULLFSYNC
# define HAVE_FULLFSYNC 0
#endif
/*
** The fsync() system call does not work as advertised on many
** unix systems. The following procedure is an attempt to make
** it work better.
**
** The SQLITE_NO_SYNC macro disables all fsync()s. This is useful
** for testing when we want to run through the test suite quickly.
** You are strongly advised *not* to deploy with SQLITE_NO_SYNC
** enabled, however, since with SQLITE_NO_SYNC enabled, an OS crash
** or power failure will likely corrupt the database file.
**
** SQLite sets the dataOnly flag if the size of the file is unchanged.
** The idea behind dataOnly is that it should only write the file content
** to disk, not the inode. We only set dataOnly if the file size is
** unchanged since the file size is part of the inode. However,
** Ted Ts'o tells us that fdatasync() will also write the inode if the
** file size has changed. The only real difference between fdatasync()
** and fsync(), Ted tells us, is that fdatasync() will not flush the
** inode if the mtime or owner or other inode attributes have changed.
** We only care about the file size, not the other file attributes, so
** as far as SQLite is concerned, an fdatasync() is always adequate.
** So, we always use fdatasync() if it is available, regardless of
** the value of the dataOnly flag.
*/
static int full_fsync(int fd, int fullSync, int dataOnly){
int rc;
/* The following "ifdef/elif/else/" block has the same structure as
** the one below. It is replicated here solely to avoid cluttering
** up the real code with the UNUSED_PARAMETER() macros.
*/
#ifdef SQLITE_NO_SYNC
UNUSED_PARAMETER(fd);
UNUSED_PARAMETER(fullSync);
UNUSED_PARAMETER(dataOnly);
#elif HAVE_FULLFSYNC
UNUSED_PARAMETER(dataOnly);
#else
UNUSED_PARAMETER(fullSync);
UNUSED_PARAMETER(dataOnly);
#endif
/* Record the number of times that we do a normal fsync() and
** FULLSYNC. This is used during testing to verify that this procedure
** gets called with the correct arguments.
*/
#ifdef SQLITE_TEST
if( fullSync ) sqlite3_fullsync_count++;
sqlite3_sync_count++;
#endif
/* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a
** no-op
*/
#ifdef SQLITE_NO_SYNC
rc = SQLITE_OK;
#elif HAVE_FULLFSYNC
#error "rtt not support FULLFSYNC"
#else
rc = fdatasync(fd);
#endif /* ifdef SQLITE_NO_SYNC elif HAVE_FULLFSYNC */
return rc;
}
/*
** Make sure all writes to a particular file are committed to disk.
**
** If dataOnly==0 then both the file itself and its metadata (file
** size, access time, etc) are synced. If dataOnly!=0 then only the
** file data is synced.
**
** Under Rtt, also make sure that the directory entry for the file
** has been created by fsync-ing the directory that contains the file.
** If we do not do this and we encounter a power failure, the directory
** entry for the journal might not exist after we reboot. The next
** SQLite to access the file will not know that the journal exists (because
** the directory entry for the journal was never created) and the transaction
** will not roll back - possibly leading to database corruption.
*/
static int rttSync(sqlite3_file *id, int flags){
int rc;
rttFile *pFile = (rttFile*)id;
int isDataOnly = (flags&SQLITE_SYNC_DATAONLY);
int isFullsync = (flags&0x0F)==SQLITE_SYNC_FULL;
/* Check that one of SQLITE_SYNC_NORMAL or FULL was passed */
assert((flags&0x0F)==SQLITE_SYNC_NORMAL
|| (flags&0x0F)==SQLITE_SYNC_FULL
);
/* Rtt cannot, but some systems may return SQLITE_FULL from here. This
** line is to test that doing so does not cause any problems.
*/
SimulateDiskfullError( return SQLITE_FULL );
assert( pFile );
OSTRACE(("SYNC %-3d\n", pFile->h));
rc = full_fsync(pFile->h, isFullsync, isDataOnly);
SimulateIOError( rc=1 );
if( rc ){
pFile->lastErrno = errno;
return rttLogError(SQLITE_IOERR_FSYNC, "full_fsync", pFile->zPath);
}
/* Also fsync the directory containing the file if the DIRSYNC flag
** is set. This is a one-time occurrence. Many systems (examples: AIX)
** are unable to fsync a directory, so ignore errors on the fsync.
*/
if( pFile->ctrlFlags & UNIXFILE_DIRSYNC ){
int dirfd;
OSTRACE(("DIRSYNC %s (have_fullfsync=%d fullsync=%d)\n", pFile->zPath,
HAVE_FULLFSYNC, isFullsync));
rc = osOpenDirectory(pFile->zPath, &dirfd);
if( rc==SQLITE_OK && dirfd>=0 ){
full_fsync(dirfd, 0, 0);
robust_close(pFile, dirfd, __LINE__);
}else if( rc==SQLITE_CANTOPEN ){
rc = SQLITE_OK;
}
pFile->ctrlFlags &= ~UNIXFILE_DIRSYNC;
}
return rc;
}
/*
** Truncate an open file to a specified size
*/
static int rttTruncate(sqlite3_file *id, i64 nByte){
rttFile *pFile = (rttFile *)id;
int rc;
assert( pFile );
SimulateIOError( return SQLITE_IOERR_TRUNCATE );
/* If the user has configured a chunk-size for this file, truncate the
** file so that it consists of an integer number of chunks (i.e. the
** actual file size after the operation may be larger than the requested
** size).
*/
if( pFile->szChunk>0 ){
nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
}
rc = robust_ftruncate(pFile->h, (off_t)nByte);
if( rc ){
pFile->lastErrno = errno;
return rttLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
}else{
#ifdef SQLITE_DEBUG
/* If we are doing a normal write to a database file (as opposed to
** doing a hot-journal rollback or a write to some file other than a
** normal database file) and we truncate the file to zero length,
** that effectively updates the change counter. This might happen
** when restoring a database using the backup API from a zero-length
** source.
*/
if( pFile->inNormalWrite && nByte==0 ){
pFile->transCntrChng = 1;
}
#endif
return SQLITE_OK;
}
}
/*
** Determine the current size of a file in bytes
*/
static int rttFileSize(sqlite3_file *id, i64 *pSize){
int rc;
struct stat buf;
assert( id );
rc = osFstat(((rttFile*)id)->h, &buf);
SimulateIOError( rc=1 );
if( rc!=0 ){
((rttFile*)id)->lastErrno = errno;
return SQLITE_IOERR_FSTAT;
}
*pSize = buf.st_size;
/* When opening a zero-size database, the findInodeInfo() procedure
** 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. Ticket #3260.
*/
if( *pSize==1 ) *pSize = 0;
return SQLITE_OK;
}
/*
** This function is called to handle the SQLITE_FCNTL_SIZE_HINT
** file-control operation. Enlarge the database to nBytes in size
** (rounded up to the next chunk-size). If the database is already
** nBytes or larger, this routine is a no-op.
*/
static int fcntlSizeHint(rttFile *pFile, i64 nByte){
if( pFile->szChunk>0 ){
i64 nSize; /* Required file size */
struct stat buf; /* Used to hold return values of fstat() */
if( osFstat(pFile->h, &buf) ) return SQLITE_IOERR_FSTAT;
nSize = ((nByte+pFile->szChunk-1) / pFile->szChunk) * pFile->szChunk;
if( nSize>(i64)buf.st_size ){
/* If the OS does not have posix_fallocate(), fake it. First use
** ftruncate() to set the file size, then write a single byte to
** the last byte in each block within the extended region. This
** is the same technique used by glibc to implement posix_fallocate()
** on systems that do not have a real fallocate() system call.
*/
int nBlk = buf.st_blksize; /* File-system block size */
i64 iWrite; /* Next offset to write to */
if( robust_ftruncate(pFile->h, nSize) ){
pFile->lastErrno = errno;
return rttLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
}
iWrite = ((buf.st_size + 2*nBlk - 1)/nBlk)*nBlk-1;
while( iWrite<nSize ){
int nWrite = seekAndWrite(pFile, iWrite, "", 1);
if( nWrite!=1 ) return SQLITE_IOERR_WRITE;
iWrite += nBlk;
}
}
}
return SQLITE_OK;
}
/*
** If *pArg is inititially negative then this is a query. Set *pArg to
** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set.
**
** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags.
*/
static void rttModeBit(rttFile *pFile, unsigned char mask, int *pArg){
if( *pArg<0 ){
*pArg = (pFile->ctrlFlags & mask)!=0;
}else if( (*pArg)==0 ){
pFile->ctrlFlags &= ~mask;
}else{
pFile->ctrlFlags |= mask;
}
}
/* Forward declaration */
static int rttGetTempname(int nBuf, char *zBuf);
/*
** Information and control of an open file handle.
*/
static int rttFileControl(sqlite3_file *id, int op, void *pArg){
rttFile *pFile = (rttFile*)id;
switch( op ){
case SQLITE_FCNTL_LOCKSTATE: {
*(int*)pArg = pFile->eFileLock;
return SQLITE_OK;
}
case SQLITE_LAST_ERRNO: {
*(int*)pArg = pFile->lastErrno;
return SQLITE_OK;
}
case SQLITE_FCNTL_CHUNK_SIZE: {
pFile->szChunk = *(int *)pArg;
return SQLITE_OK;
}
case SQLITE_FCNTL_SIZE_HINT: {
int rc;
SimulateIOErrorBenign(1);
rc = fcntlSizeHint(pFile, *(i64 *)pArg);
SimulateIOErrorBenign(0);
return rc;
}
case SQLITE_FCNTL_PERSIST_WAL: {
rttModeBit(pFile, UNIXFILE_PERSIST_WAL, (int*)pArg);
return SQLITE_OK;
}
case SQLITE_FCNTL_POWERSAFE_OVERWRITE: {
rttModeBit(pFile, UNIXFILE_PSOW, (int*)pArg);
return SQLITE_OK;
}
case SQLITE_FCNTL_VFSNAME: {
*(char**)pArg = sqlite3_mprintf("%s", pFile->pVfs->zName);
return SQLITE_OK;
}
case SQLITE_FCNTL_TEMPFILENAME: {
char *zTFile = sqlite3_malloc( pFile->pVfs->mxPathname );
if( zTFile ){
rttGetTempname(pFile->pVfs->mxPathname, zTFile);
*(char**)pArg = zTFile;
}
return SQLITE_OK;
}
#ifdef SQLITE_DEBUG
/* The pager calls this method to signal that it has done
** a rollback and that the database is therefore unchanged and
** it hence it is OK for the transaction change counter to be
** unchanged.
*/
case SQLITE_FCNTL_DB_UNCHANGED: {
((rttFile*)id)->dbUpdate = 0;
return SQLITE_OK;
}
#endif
}
return SQLITE_NOTFOUND;
}
/*
** Return the sector size in bytes of the underlying block device for
** the specified file. This is almost always 512 bytes, but may be
** larger for some devices.
**
** SQLite code assumes this function cannot fail. It also assumes that
** if two files are created in the same file-system directory (i.e.
** a database and its journal file) that the sector size will be the
** same for both.
*/
static int rttSectorSize(sqlite3_file *NotUsed){
UNUSED_PARAMETER(NotUsed);
return SQLITE_DEFAULT_SECTOR_SIZE;
}
/*
** Return the device characteristics for the file.
**
** This VFS is set up to return SQLITE_IOCAP_POWERSAFE_OVERWRITE by default.
** However, that choice is contraversial since technically the underlying
** file system does not always provide powersafe overwrites. (In other
** words, after a power-loss event, parts of the file that were never
** written might end up being altered.) However, non-PSOW behavior is very,
** very rare. And asserting PSOW makes a large reduction in the amount
** of required I/O for journaling, since a lot of padding is eliminated.
** Hence, while POWERSAFE_OVERWRITE is on by default, there is a file-control
** available to turn it off and URI query parameter available to turn it off.
*/
static int rttDeviceCharacteristics(sqlite3_file *id){
rttFile *p = (rttFile*)id;
int rc = 0;
if( p->ctrlFlags & UNIXFILE_PSOW ){
rc |= SQLITE_IOCAP_POWERSAFE_OVERWRITE;
}
return rc;
}
#ifndef SQLITE_OMIT_WAL
# error "WAL mode requires not support from the rt-thread, compile\
with SQLITE_OMIT_WAL."
#else
# define rttShmMap 0
# define rttShmLock 0
# define rttShmBarrier 0
# define rttShmUnmap 0
#endif /* #ifndef SQLITE_OMIT_WAL */
#if SQLITE_MAX_MMAP_SIZE>0
#error "rtt not spportt mmap"
#endif /* SQLITE_MAX_MMAP_SIZE>0 */
/*
** If possible, return a pointer to a mapping of file fd starting at offset
** iOff. The mapping must be valid for at least nAmt bytes.
**
** If such a pointer can be obtained, store it in *pp and return SQLITE_OK.
** Or, if one cannot but no error occurs, set *pp to 0 and return SQLITE_OK.
** Finally, if an error does occur, return an SQLite error code. The final
** value of *pp is undefined in this case.
**
** If this function does return a pointer, the caller must eventually
** release the reference by calling unixUnfetch().
*/
static int rttFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
*pp = 0;
return SQLITE_OK;
}
/*
** If the third argument is non-NULL, then this function releases a
** reference obtained by an earlier call to unixFetch(). The second
** argument passed to this function must be the same as the corresponding
** argument that was passed to the unixFetch() invocation.
**
** Or, if the third argument is NULL, then this function is being called
** to inform the VFS layer that, according to POSIX, any existing mapping
** may now be invalid and should be unmapped.
*/
static int rttUnfetch(sqlite3_file *fd, i64 iOff, void *p){
rttFile *pFd = (rttFile *)fd; /* The underlying database file */
UNUSED_PARAMETER(iOff);
return SQLITE_OK;
}
/*
** Here ends the implementation of all sqlite3_file methods.
**
********************** End sqlite3_file Methods *******************************
******************************************************************************/
/*
** This division contains definitions of sqlite3_io_methods objects that
** implement various file locking strategies. It also contains definitions
** of "finder" functions. A finder-function is used to locate the appropriate
** sqlite3_io_methods object for a particular database file. The pAppData
** field of the sqlite3_vfs VFS objects are initialized to be pointers to
** the correct finder-function for that VFS.
**
** Most finder functions return a pointer to a fixed sqlite3_io_methods
** object. The only interesting finder-function is autolockIoFinder, which
** looks at the filesystem type and tries to guess the best locking
** strategy from that.
**
** For finder-funtion F, two objects are created:
**
** (1) The real finder-function named "FImpt()".
**
** (2) A constant pointer to this function named just "F".
**
**
** A pointer to the F pointer is used as the pAppData value for VFS
** objects. We have to do this instead of letting pAppData point
** directly at the finder-function since C90 rules prevent a void*
** from be cast into a function pointer.
**
**
** Each instance of this macro generates two objects:
**
** * A constant sqlite3_io_methods object call METHOD that has locking
** methods CLOSE, LOCK, UNLOCK, CKRESLOCK.
**
** * An I/O method finder function called FINDER that returns a pointer
** to the METHOD object in the previous bullet.
*/
#define IOMETHODS(FINDER, METHOD, VERSION, CLOSE, LOCK, UNLOCK, CKLOCK) \
static const sqlite3_io_methods METHOD = { \
VERSION, /* iVersion */ \
CLOSE, /* xClose */ \
rttRead, /* xRead */ \
rttWrite, /* xWrite */ \
rttTruncate, /* xTruncate */ \
rttSync, /* xSync */ \
rttFileSize, /* xFileSize */ \
LOCK, /* xLock */ \
UNLOCK, /* xUnlock */ \
CKLOCK, /* xCheckReservedLock */ \
rttFileControl, /* xFileControl */ \
rttSectorSize, /* xSectorSize */ \
rttDeviceCharacteristics, /* xDeviceCapabilities */ \
rttShmMap, /* xShmMap */ \
rttShmLock, /* xShmLock */ \
rttShmBarrier, /* xShmBarrier */ \
rttShmUnmap, /* xShmUnmap */ \
rttFetch, /* xFetch */ \
rttUnfetch, /* xUnfetch */ \
}; \
static const sqlite3_io_methods *FINDER##Impl(const char *z, rttFile *p){ \
UNUSED_PARAMETER(z); UNUSED_PARAMETER(p); \
return &METHOD; \
} \
static const sqlite3_io_methods *(*const FINDER)(const char*,rttFile *p) \
= FINDER##Impl;
/*
** Here are all of the sqlite3_io_methods objects for each of the
** locking strategies. Functions that return pointers to these methods
** are also created.
*/
IOMETHODS(
nolockIoFinder, /* Finder function name */
nolockIoMethods, /* sqlite3_io_methods object name */
1, /* shared memory is disabled */
nolockClose, /* xClose method */
nolockLock, /* xLock method */
nolockUnlock, /* xUnlock method */
nolockCheckReservedLock /* xCheckReservedLock method */
)
IOMETHODS(
dotlockIoFinder, /* Finder function name */
dotlockIoMethods, /* sqlite3_io_methods object name */
1, /* shared memory is disabled */
dotlockClose, /* xClose method */
dotlockLock, /* xLock method */
dotlockUnlock, /* xUnlock method */
dotlockCheckReservedLock /* xCheckReservedLock method */
)
#if SQLITE_ENABLE_LOCKING_STYLE
IOMETHODS(
flockIoFinder, /* Finder function name */
flockIoMethods, /* sqlite3_io_methods object name */
1, /* shared memory is disabled */
flockClose, /* xClose method */
flockLock, /* xLock method */
flockUnlock, /* xUnlock method */
flockCheckReservedLock /* xCheckReservedLock method */
)
#endif
/*
** An abstract type for a pointer to a IO method finder function:
*/
typedef const sqlite3_io_methods *(*finder_type)(const char*,rttFile*);
/****************************************************************************
**************************** sqlite3_vfs methods ****************************
**
** This division contains the implementation of methods on the
** sqlite3_vfs object.
*/
/*
** Initialize the contents of the rttFile structure pointed to by pId.
*/
static int fillInRttFile(
sqlite3_vfs *pVfs, /* Pointer to vfs object */
int h, /* Open file descriptor of file being opened */
sqlite3_file *pId, /* Write to the rttFile structure here */
const char *zFilename, /* Name of the file being opened */
int ctrlFlags /* Zero or more UNIXFILE_* values */
){
const sqlite3_io_methods *pLockingStyle;
rttFile *pNew = (rttFile *)pId;
int rc = SQLITE_OK;
assert( pNew->pInode==NULL );
/* Usually the path zFilename should not be a relative pathname. The
** exception is when opening the proxy "conch" file in builds that
** include the special Apple locking styles.
*/
assert( zFilename==0 || zFilename[0]=='/' );
/* No locking occurs in temporary files */
assert( zFilename!=0 || (ctrlFlags & UNIXFILE_NOLOCK)!=0 );
OSTRACE(("OPEN %-3d %s\n", h, zFilename));
pNew->h = h;
pNew->pVfs = pVfs;
pNew->zPath = zFilename;
pNew->ctrlFlags = (u8)ctrlFlags;
if( sqlite3_uri_boolean(((ctrlFlags & UNIXFILE_URI) ? zFilename : 0),
"psow", SQLITE_POWERSAFE_OVERWRITE) ){
pNew->ctrlFlags |= UNIXFILE_PSOW;
}
if( strcmp(pVfs->zName,"unix-excl")==0 ){
pNew->ctrlFlags |= UNIXFILE_EXCL;
}
if( ctrlFlags & UNIXFILE_NOLOCK ){
pLockingStyle = &nolockIoMethods;
}else{
pLockingStyle = (**(finder_type*)pVfs->pAppData)(zFilename, pNew);
#if SQLITE_ENABLE_LOCKING_STYLE
/* Cache zFilename in the locking context (AFP and dotlock override) for
** proxyLock activation is possible (remote proxy is based on db name)
** zFilename remains valid until file is closed, to support */
pNew->lockingContext = (void*)zFilename;
#endif
}
if( pLockingStyle == &dotlockIoMethods ){
/* Dotfile locking uses the file path so it needs to be included in
** the dotlockLockingContext
*/
char *zLockFile;
int nFilename;
assert( zFilename!=0 );
nFilename = (int)strlen(zFilename) + 6;
zLockFile = (char *)sqlite3_malloc(nFilename);
if( zLockFile==0 ){
rc = SQLITE_NOMEM;
}else{
sqlite3_snprintf(nFilename, zLockFile, "%s" DOTLOCK_SUFFIX, zFilename);
}
pNew->lockingContext = zLockFile;
}
pNew->lastErrno = 0;
if( rc!=SQLITE_OK ){
if( h>=0 ) robust_close(pNew, h, __LINE__);
}else{
pNew->pMethod = pLockingStyle;
OpenCounter(+1);
verifyDbFile(pNew);
}
return rc;
}
/*
** Return the name of a directory in which to put temporary files.
** If no suitable temporary file directory can be found, return NULL.
*/
static const char *rttTempFileDir(void){
static const char *azDirs[] = {
0,
"/sql",
"/sql/tmp"
"/tmp",
0 /* List terminator */
};
unsigned int i;
struct stat buf;
const char *zDir = 0;
azDirs[0] = sqlite3_temp_directory;
for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); zDir=azDirs[i++]){
if( zDir==0 ) continue;
if( osStat(zDir, &buf) ) continue;
if( !S_ISDIR(buf.st_mode) ) continue;
break;
}
return zDir;
}
/*
** Create a temporary file name in zBuf. zBuf must be allocated
** by the calling process and must be big enough to hold at least
** pVfs->mxPathname bytes.
*/
static int rttGetTempname(int nBuf, char *zBuf){
static const unsigned char zChars[] =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";
unsigned int i, j;
const char *zDir;
/* It's odd to simulate an io-error here, but really this is just
** using the io-error infrastructure to test that SQLite handles this
** function failing.
*/
SimulateIOError( return SQLITE_IOERR );
zDir = rttTempFileDir();
if( zDir==0 ) zDir = ".";
/* Check that the output buffer is large enough for the temporary file
** name. If it is not, return SQLITE_ERROR.
*/
if( (strlen(zDir) + strlen(SQLITE_TEMP_FILE_PREFIX) + 18) >= (size_t)nBuf ){
return SQLITE_ERROR;
}
do{
sqlite3_snprintf(nBuf-18, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX, zDir);
j = (int)strlen(zBuf);
sqlite3_randomness(15, &zBuf[j]);
for(i=0; i<15; i++, j++){
zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
}
zBuf[j] = 0;
zBuf[j+1] = 0;
}while( osAccess(zBuf,0)==0 );
return SQLITE_OK;
}
/*
** Open the file zPath.
**
** Previously, the SQLite OS layer used three functions in place of this
** one:
**
** sqlite3OsOpenReadWrite();
** sqlite3OsOpenReadOnly();
** sqlite3OsOpenExclusive();
**
** These calls correspond to the following combinations of flags:
**
** ReadWrite() -> (READWRITE | CREATE)
** ReadOnly() -> (READONLY)
** OpenExclusive() -> (READWRITE | CREATE | EXCLUSIVE)
**
** The old OpenExclusive() accepted a boolean argument - "delFlag". If
** true, the file was configured to be automatically deleted when the
** file handle closed. To achieve the same effect using this new
** interface, add the DELETEONCLOSE flag to those specified above for
** OpenExclusive().
*/
static int rttOpen(
sqlite3_vfs *pVfs, /* The VFS for which this is the xOpen method */
const char *zPath, /* Pathname of file to be opened */
sqlite3_file *pFile, /* The file descriptor to be filled in */
int flags, /* Input flags to control the opening */
int *pOutFlags /* Output flags returned to SQLite core */
){
rttFile *p = (rttFile *)pFile;
int fd = -1; /* File descriptor returned by open() */
int openFlags = 0; /* Flags to pass to open() */
int eType = flags&0xFFFFFF00; /* Type of file to open */
int noLock; /* True to omit locking primitives */
int rc = SQLITE_OK; /* Function Return Code */
int ctrlFlags = 0; /* UNIXFILE_* flags */
int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE);
int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE);
int isCreate = (flags & SQLITE_OPEN_CREATE);
int isReadonly = (flags & SQLITE_OPEN_READONLY);
int isReadWrite = (flags & SQLITE_OPEN_READWRITE);
#if SQLITE_ENABLE_LOCKING_STYLE
int isAutoProxy = (flags & SQLITE_OPEN_AUTOPROXY);
#endif
/* If creating a master or main-file journal, this function will open
** a file-descriptor on the directory too. The first time unixSync()
** is called the directory file descriptor will be fsync()ed and close()d.
*/
int syncDir = (isCreate && (
eType==SQLITE_OPEN_MASTER_JOURNAL
|| eType==SQLITE_OPEN_MAIN_JOURNAL
|| eType==SQLITE_OPEN_WAL
));
/* If argument zPath is a NULL pointer, this function is required to open
** a temporary file. Use this buffer to store the file name in.
*/
char zTmpname[MAX_PATHNAME+2];
const char *zName = zPath;
/* Check the following statements are true:
**
** (a) Exactly one of the READWRITE and READONLY flags must be set, and
** (b) if CREATE is set, then READWRITE must also be set, and
** (c) if EXCLUSIVE is set, then CREATE must also be set.
** (d) if DELETEONCLOSE is set, then CREATE must also be set.
*/
assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly));
assert(isCreate==0 || isReadWrite);
assert(isExclusive==0 || isCreate);
assert(isDelete==0 || isCreate);
/* The main DB, main journal, WAL file and master journal are never
** automatically deleted. Nor are they ever temporary files. */
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB );
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL );
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL );
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL );
/* Assert that the upper layer has set one of the "file-type" flags. */
assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB
|| eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
|| eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL
|| eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
);
memset(p, 0, sizeof(rttFile));
if( !zName ){
/* If zName is NULL, the upper layer is requesting a temp file. */
assert(isDelete && !syncDir);
rc = rttGetTempname(MAX_PATHNAME+2, zTmpname);
if( rc!=SQLITE_OK ){
return rc;
}
zName = zTmpname;
/* Generated temporary filenames are always double-zero terminated
** for use by sqlite3_uri_parameter(). */
assert( zName[strlen(zName)+1]==0 );
}
/* Determine the value of the flags parameter passed to POSIX function
** open(). These must be calculated even if open() is not called, as
** they may be stored as part of the file handle and used by the
** 'conch file' locking functions later on. */
if( isReadonly ) openFlags |= O_RDONLY;
if( isReadWrite ) openFlags |= O_RDWR;
if( isCreate ) openFlags |= O_CREAT;
if( isExclusive ) openFlags |= (O_EXCL|0/*O_NOFOLLOW8*/);
openFlags |= (0/*O_LARGEFILE*/|O_BINARY);
if( fd<0 ){
mode_t openMode = 0; /* Permissions to create file with */
fd = robust_open(zName, openFlags, openMode);
OSTRACE(("OPENX %-3d %s 0%o\n", fd, zName, openFlags));
if( fd<0 && errno!=EISDIR && isReadWrite && !isExclusive ){
/* Failed to open the file for read/write access. Try read-only. */
flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
openFlags &= ~(O_RDWR|O_CREAT);
flags |= SQLITE_OPEN_READONLY;
openFlags |= O_RDONLY;
isReadonly = 1;
fd = robust_open(zName, openFlags, openMode);
}
if( fd<0 ){
rc = rttLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
goto open_finished;
}
}
assert( fd>=0 );
if( pOutFlags ){
*pOutFlags = flags;
}
if( isDelete ){
osUnlink(zName);
}
#if SQLITE_ENABLE_LOCKING_STYLE
else{
p->openFlags = openFlags;
}
#endif
noLock = eType!=SQLITE_OPEN_MAIN_DB;
/* Set up appropriate ctrlFlags */
if( isDelete ) ctrlFlags |= UNIXFILE_DELETE;
if( isReadonly ) ctrlFlags |= UNIXFILE_RDONLY;
if( noLock ) ctrlFlags |= UNIXFILE_NOLOCK;
if( syncDir ) ctrlFlags |= UNIXFILE_DIRSYNC;
if( flags & SQLITE_OPEN_URI ) ctrlFlags |= UNIXFILE_URI;
rc = fillInRttFile(pVfs, fd, pFile, zPath, ctrlFlags);
open_finished:
return rc;
}
/*
** Delete the file at zPath. If the dirSync argument is true, fsync()
** the directory after deleting the file.
*/
static int rttDelete(
sqlite3_vfs *NotUsed, /* VFS containing this as the xDelete method */
const char *zPath, /* Name of file to be deleted */
int dirSync /* If true, fsync() directory after deleting file */
){
int rc = SQLITE_OK;
UNUSED_PARAMETER(NotUsed);
SimulateIOError(return SQLITE_IOERR_DELETE);
if( osUnlink(zPath)==(-1) ){
if( errno==ENOENT ){
rc = SQLITE_IOERR_DELETE_NOENT;
}else{
rc = rttLogError(SQLITE_IOERR_DELETE, "unlink", zPath);
}
return rc;
}
#ifndef SQLITE_DISABLE_DIRSYNC
if( (dirSync & 1)!=0 ){
int fd;
rc = osOpenDirectory(zPath, &fd);
if( rc==SQLITE_OK ){
robust_close(0, fd, __LINE__);
}else if( rc==SQLITE_CANTOPEN ){
rc = SQLITE_OK;
}
}
#endif
return rc;
}
/*
** Test the existence of or access permissions of file zPath. The
** test performed depends on the value of flags:
**
** SQLITE_ACCESS_EXISTS: Return 1 if the file exists
** SQLITE_ACCESS_READWRITE: Return 1 if the file is read and writable.
** SQLITE_ACCESS_READONLY: Return 1 if the file is readable.
**
** Otherwise return 0.
*/
static int rttAccess(
sqlite3_vfs *NotUsed, /* The VFS containing this xAccess method */
const char *zPath, /* Path of the file to examine */
int flags, /* What do we want to learn about the zPath file? */
int *pResOut /* Write result boolean here */
){
int amode = 0;
UNUSED_PARAMETER(NotUsed);
SimulateIOError( return SQLITE_IOERR_ACCESS; );
switch( flags ){
case SQLITE_ACCESS_EXISTS:
amode = F_OK;
break;
case SQLITE_ACCESS_READWRITE:
amode = W_OK|R_OK;
break;
case SQLITE_ACCESS_READ:
amode = R_OK;
break;
default:
assert(!"Invalid flags argument");
}
*pResOut = (osAccess(zPath, amode)==0);
if( flags==SQLITE_ACCESS_EXISTS && *pResOut ){
struct stat buf;
if( 0==osStat(zPath, &buf) && buf.st_size==0 ){
*pResOut = 0;
}
}
return SQLITE_OK;
}
/*
** Turn a relative pathname into a full pathname. The relative path
** is stored as a nul-terminated string in the buffer pointed to by
** zPath.
**
** zOut points to a buffer of at least sqlite3_vfs.mxPathname bytes
** (in this case, MAX_PATHNAME bytes). The full-path is written to
** this buffer before returning.
*/
static int rttFullPathname(
sqlite3_vfs *pVfs, /* Pointer to vfs object */
const char *zPath, /* Possibly relative input path */
int nOut, /* Size of output buffer in bytes */
char *zOut /* Output buffer */
){
/* It's odd to simulate an io-error here, but really this is just
** using the io-error infrastructure to test that SQLite handles this
** function failing. This function could fail if, for example, the
** current working directory has been unlinked.
*/
SimulateIOError( return SQLITE_ERROR );
assert( pVfs->mxPathname==MAX_PATHNAME );
UNUSED_PARAMETER(pVfs);
zOut[nOut-1] = '\0';
if( zPath[0]=='/' ){
sqlite3_snprintf(nOut, zOut, "%s", zPath);
}else{
int nCwd;
if( osGetcwd(zOut, nOut-1)==0 ){
return rttLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath);
}
nCwd = (int)strlen(zOut);
sqlite3_snprintf(nOut-nCwd, &zOut[nCwd], "/%s", zPath);
}
return SQLITE_OK;
}
#ifndef SQLITE_OMIT_LOAD_EXTENSION
# error "rtt not support load extension, compile with SQLITE_OMIT_WAL."
#else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */
#define rttDlOpen 0
#define rttDlError 0
#define rttDlSym 0
#define rttDlClose 0
#endif
/*
** Write nBuf bytes of random data to the supplied buffer zBuf.
*/
static int rttRandomness(sqlite3_vfs *NotUsed, int nBuf, char *zBuf){
UNUSED_PARAMETER(NotUsed);
assert((size_t)nBuf>=(sizeof(time_t)+sizeof(int)));
/* We have to initialize zBuf to prevent valgrind from reporting
** errors. The reports issued by valgrind are incorrect - we would
** prefer that the randomness be increased by making use of the
** uninitialized space in zBuf - but valgrind errors tend to worry
** some users. Rather than argue, it seems easier just to initialize
** the whole array and silence valgrind, even if that means less randomness
** in the random seed.
**
** When testing, initializing zBuf[] to zero is all we do. That means
** that we always use the same random number sequence. This makes the
** tests repeatable.
*/
memset(zBuf, 0, nBuf);
{
int i;
char tick8, tick16;
tick8 = (char)rt_tick_get();
tick16 = (char)(rt_tick_get() >> 8);
for (i=0; i<nBuf; i++)
{
zBuf[i] = (char)(i ^ tick8 ^ tick16);
tick8 = zBuf[i];
tick16 = ~(tick8 ^ tick16);
}
}
return nBuf;
}
/*
** Sleep for a little while. Return the amount of time slept.
** The argument is the number of microseconds we want to sleep.
** The return value is the number of microseconds of sleep actually
** requested from the underlying operating system, a number which
** might be greater than or equal to the argument, but not less
** than the argument.
*/
static int rttSleep(sqlite3_vfs *NotUsed, int microseconds){
int seconds = (microseconds+999999)/1000000;
osSleep(seconds * 1000);
UNUSED_PARAMETER(NotUsed);
return seconds*1000000;
}
/*
** The following variable, if set to a non-zero value, is interpreted as
** the number of seconds since 1970 and is used to set the result of
** sqlite3OsCurrentTime() during testing.
*/
#ifdef SQLITE_TEST
int sqlite3_current_time = 0; /* Fake system time in seconds since 1970. */
#endif
#ifndef NO_GETTOD
#define NO_GETTOD 1
#endif
/*
** Find the current time (in Universal Coordinated Time). Write into *piNow
** the current time and date as a Julian Day number times 86_400_000. In
** other words, write into *piNow the number of milliseconds since the Julian
** epoch of noon in Greenwich on November 24, 4714 B.C according to the
** proleptic Gregorian calendar.
**
** On success, return SQLITE_OK. Return SQLITE_ERROR if the time and date
** cannot be found.
*/
static int rttCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){
static const sqlite3_int64 rttEpoch = 24405875*(sqlite3_int64)8640000;
int rc = SQLITE_OK;
#if defined(NO_GETTOD)
time_t t;
time(&t);
*piNow = ((sqlite3_int64)t)*1000 + rttEpoch;
#else
struct timeval sNow;
if( gettimeofday(&sNow, 0)==0 ){
*piNow = rttEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000;
}else{
rc = SQLITE_ERROR;
}
#endif
#ifdef SQLITE_TEST
if( sqlite3_current_time ){
*piNow = 1000*(sqlite3_int64)sqlite3_current_time + rttEpoch;
}
#endif
UNUSED_PARAMETER(NotUsed);
return rc;
}
/*
** Find the current time (in Universal Coordinated Time). Write the
** current time and date as a Julian Day number into *prNow and
** return 0. Return 1 if the time and date cannot be found.
*/
static int rttCurrentTime(sqlite3_vfs *NotUsed, double *prNow){
sqlite3_int64 i = 0;
int rc;
UNUSED_PARAMETER(NotUsed);
rc = rttCurrentTimeInt64(0, &i);
*prNow = i/86400000.0;
return rc;
}
/*
** We added the xGetLastError() method with the intention of providing
** better low-level error messages when operating-system problems come up
** during SQLite operation. But so far, none of that has been implemented
** in the core. So this routine is never called. For now, it is merely
** a place-holder.
*/
static int rttGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
UNUSED_PARAMETER(NotUsed);
UNUSED_PARAMETER(NotUsed2);
UNUSED_PARAMETER(NotUsed3);
return 0;
}
/*
************************ End of sqlite3_vfs methods ***************************
******************************************************************************/
/*
** Initialize the operating system interface.
**
** This routine registers all VFS implementations for unix-like operating
** systems. This routine, and the sqlite3_os_end() routine that follows,
** should be the only routines in this file that are visible from other
** files.
**
** This routine is called once during SQLite initialization and by a
** single thread. The memory allocation and mutex subsystems have not
** necessarily been initialized when this routine is called, and so they
** should not be used.
*/
/*
** The following macro defines an initializer for an sqlite3_vfs object.
** The name of the VFS is NAME. The pAppData is a pointer to a pointer
** to the "finder" function. (pAppData is a pointer to a pointer because
** silly C90 rules prohibit a void* from being cast to a function pointer
** and so we have to go through the intermediate pointer to avoid problems
** when compiling with -pedantic-errors on GCC.)
**
** The FINDER parameter to this macro is the name of the pointer to the
** finder-function. The finder-function returns a pointer to the
** sqlite_io_methods object that implements the desired locking
** behaviors. See the division above that contains the IOMETHODS
** macro for addition information on finder-functions.
**
** Most finders simply return a pointer to a fixed sqlite3_io_methods
** object. But the "autolockIoFinder" available on MacOSX does a little
** more than that; it looks at the filesystem type that hosts the
** database file and tries to choose an locking method appropriate for
** that filesystem time.
*/
#define UNIXVFS(VFSNAME, FINDER) { \
3, /* iVersion */ \
sizeof(rttFile), /* szOsFile */ \
MAX_PATHNAME, /* mxPathname */ \
0, /* pNext */ \
VFSNAME, /* zName */ \
(void*)&FINDER, /* pAppData */ \
rttOpen, /* xOpen */ \
rttDelete, /* xDelete */ \
rttAccess, /* xAccess */ \
rttFullPathname, /* xFullPathname */ \
rttDlOpen, /* xDlOpen */ \
rttDlError, /* xDlError */ \
rttDlSym, /* xDlSym */ \
rttDlClose, /* xDlClose */ \
rttRandomness, /* xRandomness */ \
rttSleep, /* xSleep */ \
rttCurrentTime, /* xCurrentTime */ \
rttGetLastError, /* xGetLastError */ \
rttCurrentTimeInt64, /* xCurrentTimeInt64 */ \
rttSetSystemCall, /* xSetSystemCall */ \
rttGetSystemCall, /* xGetSystemCall */ \
rttNextSystemCall, /* xNextSystemCall */ \
}
int sqlite3_os_init(void){
/*
** All default VFSes for unix are contained in the following array.
**
** Note that the sqlite3_vfs.pNext field of the VFS object is modified
** by the SQLite core when the VFS is registered. So the following
** array cannot be const.
*/
static sqlite3_vfs aVfs[] = {
UNIXVFS("unix-none", nolockIoFinder ),
UNIXVFS("unix-dotfile", dotlockIoFinder ),
#if SQLITE_ENABLE_LOCKING_STYLE
UNIXVFS("unix-flock", flockIoFinder ),
#endif
};
unsigned int i; /* Loop counter */
/* Double-check that the aSyscall[] array has been constructed
** correctly. See ticket [bb3a86e890c8e96ab] */
assert( ArraySize(aSyscall)==24 );
/* Register all VFSes defined in the aVfs[] array */
for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
sqlite3_vfs_register(&aVfs[i], i==0);
}
return SQLITE_OK;
}
/*
** Shutdown the operating system interface.
**
** Some operating systems might need to do some cleanup in this routine,
** to release dynamically allocated objects. But not on unix.
** This routine is a no-op for unix.
*/
int sqlite3_os_end(void){
return SQLITE_OK;
}
#endif /* SQLITE_OS_RTT */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册