2021SC@SDUSC
第八篇到第十一篇讲解了所有sqlite3_file方法的实现。
接下来是Sqlite的OS Interface部分收尾阶段。
首先是定义了win32一些vfs方法的两个向量。
/*该向量定义了对Win 32的sqlite 3_file进行操作的所有方法。*/
static const sqlite3_io_methods winIoMethod = {
3, /* 版本号 */
winClose,
winRead,
winWrite,
winTruncate,
winSync,
winFileSize,
winLock,
winUnlock,
winCheckReservedLock,
winFileControl,
winSectorSize,
winDeviceCharacteristics,
winShmMap,
winShmLock,
winShmBarrier,
winShmUnmap,
winFetch,
winUnfetch
};
/*该向量定义了所有可以对Win 32的sqlite 3_file进行操作而不执行任何锁定的方法。*/
static const sqlite3_io_methods winIoNolockMethod = {
3, /* 版本号 */
winClose,
winRead,
winWrite,
winTruncate,
winSync,
winFileSize,
winNolockLock,
winNolockUnlock,
winNolockCheckReservedLock,
winFileControl,
winSectorSize,
winDeviceCharacteristics,
winShmMap,
winShmLock,
winShmBarrier,
winShmUnmap,
winFetch,
winUnfetch
};
static winVfsAppData winAppData = {
&winIoMethod, /* pMethod */
0, /* pAppData */
0 /* bNoLock */
};
static winVfsAppData winNolockAppData = {
&winIoNolockMethod, /* pMethod */
0, /* pAppData */
1 /* bNoLock */
};
/*此分区包含sqlite3_VFS对象上方法的实现*/
#if defined(__CYGWIN__)
/* 将文件名从任何底层操作系统支持的文件名转换为UTF-8。保存结果的空间是从malloc获得的,必须由调用函数释放*/
static char *winConvertToUtf8Filename(const void *zFilename){
char *zConverted = 0;
if( osIsNT() ){
zConverted = winUnicodeToUtf8(zFilename);
}
#ifdef SQLITE_WIN32_HAS_ANSI
else{
zConverted = winMbcsToUtf8(zFilename, osAreFileApisANSI());
}
#endif
/* 调用者将处理内存不足 */
return zConverted;
}
#endif
/*是上面的逆操作。将UTF-8文件名转换为底层操作系统想要的任何形式的文件名。保存结果的空间同样是从malloc获得的,必须通过调用函数来释放。*/
static void *winConvertFromUtf8Filename(const char *zFilename){
void *zConverted = 0;
if( osIsNT() ){
zConverted = winUtf8ToUnicode(zFilename);
}
#ifdef SQLITE_WIN32_HAS_ANSI
else{
zConverted = winUtf8ToMbcs(zFilename, osAreFileApisANSI());
}
#endif
/* 调用者将处理内存不足 */
return zConverted;
}
如果指定的UTF-8字符串缓冲区以目录分隔符结束,或者成功地将一个字符添加到其中,则此函数返回非零。
static int winMakeEndInDirSep(int nBuf, char *zBuf){
if( zBuf ){
int nLen = sqlite3Strlen30(zBuf);
if( nLen>0 ){
if( winIsDirSep(zBuf[nLen-1]) ){
return 1;
}else if( nLen+1<nBuf ){
zBuf[nLen] = winGetDirSep();
zBuf[nLen+1] = '\0';
return 1;
}
}
}
return 0;
}
创建一个临时文件名,并将结果指针存储到pzBuf中。必须通过sqlite 3_free()释放pzBuf中返回的指针。
static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
static char zChars[] =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";
size_t i, j;
int nPre = sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX);
int nMax, nBuf, nDir, nLen;
char *zBuf;
/*计算出有效的临时目录。首先,检查应用程序是否显式设置了一个;否则,使用操作系统配置的一个*/
nDir = nMax - (nPre + 15);
assert( nDir>0 );
if( sqlite3_temp_directory ){
int nDirLen = sqlite3Strlen30(sqlite3_temp_directory);
if( nDirLen>0 ){
if( !winIsDirSep(sqlite3_temp_directory[nDirLen-1]) ){
nDirLen++;
}
if( nDirLen>nDir ){
sqlite3_free(zBuf);
OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n"));
return winLogError(SQLITE_ERROR, 0, "winGetTempname1", 0);
}
sqlite3_snprintf(nMax, zBuf, "%s", sqlite3_temp_directory);
}
}
如果指定的文件实际上是目录,则返回true。如果它不是目录,或者是任何类型的内存分配失败,则返回False。
static int winIsDir(const void *zConverted){
DWORD attr;
int rc = 0;
DWORD lastErrno;
if( osIsNT() ){
int cnt = 0;
WIN32_FILE_ATTRIBUTE_DATA sAttrData;
memset(&sAttrData, 0, sizeof(sAttrData));
while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted,
GetFileExInfoStandard,
&sAttrData)) && winRetryIoerr(&cnt, &lastErrno) ){}
if( !rc ){
return 0; /* 无效名? */
}
attr = sAttrData.dwFileAttributes;
#if SQLITE_OS_WINCE==0
}else{
attr = osGetFileAttributesA((char*)zConverted);
#endif
}
return (attr!=INVALID_FILE_ATTRIBUTES) && (attr&FILE_ATTRIBUTE_DIRECTORY);
}
/*前瞻性参考*/
static int winAccess(
sqlite3_vfs *pVfs, /* 未用于win32 */
const char *zFilename, /* 要检查的文件名*/
int flags, /* 要对此文件进行测试的类型 */
int *pResOut /*退出:结果 */
);
/* 打开一个文件*/
static int winOpen(
sqlite3_vfs *pVfs, /* 用来获取最大路径长度和AppData */
const char *zName, /* 文件名 (UTF-8) */
sqlite3_file *id, /* 在这里写入SQLite 文件句柄 */
int flags, /* 打开模式标志 */
int *pOutFlags /* 状态返回标志 */
){
HANDLE h;
DWORD lastErrno = 0;
DWORD dwDesiredAccess;
DWORD dwShareMode;
DWORD dwCreationDisposition;
DWORD dwFlagsAndAttributes = 0;
#if SQLITE_OS_WINCE
int isTemp = 0;
#endif
winVfsAppData *pAppData;
winFile *pFile = (winFile*)id;
void *zConverted; /* OS编码中的文件名*/
const char *zUtf8Name = zName; /* UTF-8编码中的文件名 */
int cnt = 0;
/* 如果参数zPath是空指针, 则需要这个函数打开一个临时文件。用这个缓冲区来存储文件名 */
char *zTmpname = 0; /*用于临时文件名,如果需要的话 */
int rc = SQLITE_OK; /* 函数返回代码 */
#if !defined(NDEBUG) || SQLITE_OS_WINCE
int eType = flags&0xFFFFFF00; /* 要打开的文件类型 */
#endif
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);
#ifndef NDEBUG
int isOpenJournal = (isCreate && (
eType==SQLITE_OPEN_SUPER_JOURNAL
|| eType==SQLITE_OPEN_MAIN_JOURNAL
|| eType==SQLITE_OPEN_WAL
));
#endif
OSTRACE(("OPEN name=%s, pFile=%p, flags=%x, pOutFlags=%p\n",
zUtf8Name, id, flags, pOutFlags));
检查以下语句为true
/*必须设置READWRITE 或READONLY标志之一*/
/*如果CREATE被设置,则READWRITE也必须被设置*/
/*如果EXCLUSIVE被设置,则CREATE也必须被设置*/
/*如果DELETEONCLOSE被设置,则CREATE也必须被设置*/
assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly));
assert(isCreate==0 || isReadWrite);
assert(isExclusive==0 || isCreate);
assert(isDelete==0 || isCreate);
主数据库、主日志、WAL文件和超级日志永远不会被自动删除,它们也不是临时文件
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB );
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL );
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_SUPER_JOURNAL );
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL );
断言上层设置了“文件类型”标志之一
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_SUPER_JOURNAL
|| eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
);
如果这个函数的第二个参数为空,则生成一个临时文件名使用
if( !zUtf8Name ){
assert( isDelete && !isOpenJournal );
rc = winGetTempname(pVfs, &zTmpname);
if( rc!=SQLITE_OK ){
OSTRACE(("OPEN name=%s, rc=%s", zUtf8Name, sqlite3ErrName(rc)));
return rc;
}
zUtf8Name = zTmpname;
}
如果数据库文件名不是带参数的URI,则为双零终止。因此,它们总是可以传递给sqlite3_uri_parameter()。
assert( (eType!=SQLITE_OPEN_MAIN_DB) || (flags & SQLITE_OPEN_URI) ||
zUtf8Name[sqlite3Strlen30(zUtf8Name)+1]==0 );
把文件名转化为系统编码
zConverted = winConvertFromUtf8Filename(zUtf8Name);
if( zConverted==0 ){
sqlite3_free(zTmpname);
OSTRACE(("OPEN name=%s, rc=SQLITE_IOERR_NOMEM", zUtf8Name));
return SQLITE_IOERR_NOMEM_BKPT;
}
if( winIsDir(zConverted) ){
sqlite3_free(zConverted);
sqlite3_free(zTmpname);
OSTRACE(("OPEN name=%s, rc=SQLITE_CANTOPEN_ISDIR", zUtf8Name));
return SQLITE_CANTOPEN_ISDIR;
}
if( isReadWrite ){
dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
}else{
dwDesiredAccess = GENERIC_READ;
}