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