|
@@ -0,0 +1,2651 @@
|
|
|
+/*
|
|
|
+** 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 */
|
|
|
+
|