?? os_win.c
字號:
if( zWide ){
exists = GetFileAttributesW(zWide) != 0xffffffff;
sqliteFree(zWide);
}else{
#if OS_WINCE
return SQLITE_NOMEM;
#else
exists = GetFileAttributesA(zFilename) != 0xffffffff;
#endif
}
return exists;
}
/* Forward declaration */
static int allocateWinFile(winFile *pInit, OsFile **pId);
/*
** Attempt to open a file for both reading and writing. If that
** fails, try opening it read-only. If the file does not exist,
** try to create it.
**
** On success, a handle for the open file is written to *id
** and *pReadonly is set to 0 if the file was opened for reading and
** writing or 1 if the file was opened read-only. The function returns
** SQLITE_OK.
**
** On failure, the function returns SQLITE_CANTOPEN and leaves
** *id and *pReadonly unchanged.
*/
int sqlite3WinOpenReadWrite(
const char *zFilename,
OsFile **pId,
int *pReadonly
){
winFile f;
HANDLE h;
WCHAR *zWide = utf8ToUnicode(zFilename);
assert( *pId==0 );
if( zWide ){
h = CreateFileW(zWide,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
NULL
);
if( h==INVALID_HANDLE_VALUE ){
h = CreateFileW(zWide,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
NULL
);
if( h==INVALID_HANDLE_VALUE ){
sqliteFree(zWide);
return SQLITE_CANTOPEN;
}
*pReadonly = 1;
}else{
*pReadonly = 0;
}
#if OS_WINCE
if (!winceCreateLock(zFilename, &f)){
CloseHandle(h);
sqliteFree(zWide);
return SQLITE_CANTOPEN;
}
#endif
sqliteFree(zWide);
}else{
#if OS_WINCE
return SQLITE_NOMEM;
#else
h = CreateFileA(zFilename,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
NULL
);
if( h==INVALID_HANDLE_VALUE ){
h = CreateFileA(zFilename,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
NULL
);
if( h==INVALID_HANDLE_VALUE ){
return SQLITE_CANTOPEN;
}
*pReadonly = 1;
}else{
*pReadonly = 0;
}
#endif /* OS_WINCE */
}
f.h = h;
#if OS_WINCE
f.zDeleteOnClose = 0;
#endif
TRACE3("OPEN R/W %d \"%s\"\n", h, zFilename);
return allocateWinFile(&f, pId);
}
/*
** Attempt to open a new file for exclusive access by this process.
** The file will be opened for both reading and writing. To avoid
** a potential security problem, we do not allow the file to have
** previously existed. Nor do we allow the file to be a symbolic
** link.
**
** If delFlag is true, then make arrangements to automatically delete
** the file when it is closed.
**
** On success, write the file handle into *id and return SQLITE_OK.
**
** On failure, return SQLITE_CANTOPEN.
**
** Sometimes if we have just deleted a prior journal file, windows
** will fail to open a new one because there is a "pending delete".
** To work around this bug, we pause for 100 milliseconds and attempt
** a second open after the first one fails. The whole operation only
** fails if both open attempts are unsuccessful.
*/
int sqlite3WinOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
winFile f;
HANDLE h;
int fileflags;
WCHAR *zWide = utf8ToUnicode(zFilename);
assert( *pId == 0 );
fileflags = FILE_FLAG_RANDOM_ACCESS;
#if !OS_WINCE
if( delFlag ){
fileflags |= FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE;
}
#endif
if( zWide ){
int cnt = 0;
do{
h = CreateFileW(zWide,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
fileflags,
NULL
);
}while( h==INVALID_HANDLE_VALUE && cnt++ < 2 && (Sleep(100), 1) );
sqliteFree(zWide);
}else{
#if OS_WINCE
return SQLITE_NOMEM;
#else
int cnt = 0;
do{
h = CreateFileA(zFilename,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
fileflags,
NULL
);
}while( h==INVALID_HANDLE_VALUE && cnt++ < 2 && (Sleep(100), 1) );
#endif /* OS_WINCE */
}
if( h==INVALID_HANDLE_VALUE ){
return SQLITE_CANTOPEN;
}
f.h = h;
#if OS_WINCE
f.zDeleteOnClose = delFlag ? utf8ToUnicode(zFilename) : 0;
f.hMutex = NULL;
#endif
TRACE3("OPEN EX %d \"%s\"\n", h, zFilename);
return allocateWinFile(&f, pId);
}
/*
** Attempt to open a new file for read-only access.
**
** On success, write the file handle into *id and return SQLITE_OK.
**
** On failure, return SQLITE_CANTOPEN.
*/
int sqlite3WinOpenReadOnly(const char *zFilename, OsFile **pId){
winFile f;
HANDLE h;
WCHAR *zWide = utf8ToUnicode(zFilename);
assert( *pId==0 );
if( zWide ){
h = CreateFileW(zWide,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
NULL
);
sqliteFree(zWide);
}else{
#if OS_WINCE
return SQLITE_NOMEM;
#else
h = CreateFileA(zFilename,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
NULL
);
#endif
}
if( h==INVALID_HANDLE_VALUE ){
return SQLITE_CANTOPEN;
}
f.h = h;
#if OS_WINCE
f.zDeleteOnClose = 0;
f.hMutex = NULL;
#endif
TRACE3("OPEN RO %d \"%s\"\n", h, zFilename);
return allocateWinFile(&f, pId);
}
/*
** Attempt to open a file descriptor for the directory that contains a
** file. This file descriptor can be used to fsync() the directory
** in order to make sure the creation of a new file is actually written
** to disk.
**
** This routine is only meaningful for Unix. It is a no-op under
** windows since windows does not support hard links.
**
** On success, a handle for a previously open file is at *id is
** updated with the new directory file descriptor and SQLITE_OK is
** returned.
**
** On failure, the function returns SQLITE_CANTOPEN and leaves
** *id unchanged.
*/
static int winOpenDirectory(
OsFile *id,
const char *zDirname
){
return SQLITE_OK;
}
/*
** If the following global variable points to a string which is the
** name of a directory, then that directory will be used to store
** temporary files.
*/
char *sqlite3_temp_directory = 0;
/*
** Create a temporary file name in zBuf. zBuf must be big enough to
** hold at least SQLITE_TEMPNAME_SIZE characters.
*/
int sqlite3WinTempFileName(char *zBuf){
static char zChars[] =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";
int i, j;
char zTempPath[SQLITE_TEMPNAME_SIZE];
if( sqlite3_temp_directory ){
strncpy(zTempPath, sqlite3_temp_directory, SQLITE_TEMPNAME_SIZE-30);
zTempPath[SQLITE_TEMPNAME_SIZE-30] = 0;
}else if( isNT() ){
char *zMulti;
WCHAR zWidePath[SQLITE_TEMPNAME_SIZE];
GetTempPathW(SQLITE_TEMPNAME_SIZE-30, zWidePath);
zMulti = unicodeToUtf8(zWidePath);
if( zMulti ){
strncpy(zTempPath, zMulti, SQLITE_TEMPNAME_SIZE-30);
zTempPath[SQLITE_TEMPNAME_SIZE-30] = 0;
sqliteFree(zMulti);
}
}else{
GetTempPathA(SQLITE_TEMPNAME_SIZE-30, zTempPath);
}
for(i=strlen(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){}
zTempPath[i] = 0;
for(;;){
sprintf(zBuf, "%s\\"TEMP_FILE_PREFIX, zTempPath);
j = strlen(zBuf);
sqlite3Randomness(15, &zBuf[j]);
for(i=0; i<15; i++, j++){
zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
}
zBuf[j] = 0;
if( !sqlite3OsFileExists(zBuf) ) break;
}
TRACE2("TEMP FILENAME: %s\n", zBuf);
return SQLITE_OK;
}
/*
** Close a file.
**
** It is reported that an attempt to close a handle might sometimes
** fail. This is a very unreasonable result, but windows is notorious
** for being unreasonable so I do not doubt that it might happen. If
** the close fails, we pause for 100 milliseconds and try again. As
** many as MX_CLOSE_ATTEMPT attempts to close the handle are made before
** giving up and returning an error.
*/
#define MX_CLOSE_ATTEMPT 3
static int winClose(OsFile **pId){
winFile *pFile;
int rc = 1;
if( pId && (pFile = (winFile*)*pId)!=0 ){
int rc, cnt = 0;
TRACE2("CLOSE %d\n", pFile->h);
do{
rc = CloseHandle(pFile->h);
}while( rc==0 && cnt++ < MX_CLOSE_ATTEMPT && (Sleep(100), 1) );
#if OS_WINCE
winceDestroyLock(pFile);
if( pFile->zDeleteOnClose ){
DeleteFileW(pFile->zDeleteOnClose);
sqliteFree(pFile->zDeleteOnClose);
}
#endif
OpenCounter(-1);
sqliteFree(pFile);
*pId = 0;
}
return rc ? SQLITE_OK : SQLITE_IOERR;
}
/*
** 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 winRead(OsFile *id, void *pBuf, int amt){
DWORD got;
assert( id!=0 );
SimulateIOError(return SQLITE_IOERR);
TRACE3("READ %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype);
if( !ReadFile(((winFile*)id)->h, pBuf, amt, &got, 0) ){
got = 0;
}
if( got==(DWORD)amt ){
return SQLITE_OK;
}else{
return SQLITE_IOERR;
}
}
/*
** Write data from a buffer into a file. Return SQLITE_OK on success
** or some other error code on failure.
*/
static int winWrite(OsFile *id, const void *pBuf, int amt){
int rc = 0;
DWORD wrote;
assert( id!=0 );
SimulateIOError(return SQLITE_IOERR);
SimulateDiskfullError(return SQLITE_FULL);
TRACE3("WRITE %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype);
assert( amt>0 );
while( amt>0 && (rc = WriteFile(((winFile*)id)->h, pBuf, amt, &wrote, 0))!=0
&& wrote>0 ){
amt -= wrote;
pBuf = &((char*)pBuf)[wrote];
}
if( !rc || amt>(int)wrote ){
return SQLITE_FULL;
}
return SQLITE_OK;
}
/*
** Some microsoft compilers lack this definition.
*/
#ifndef INVALID_SET_FILE_POINTER
# define INVALID_SET_FILE_POINTER ((DWORD)-1)
#endif
/*
** Move the read/write pointer in a file.
*/
static int winSeek(OsFile *id, i64 offset){
LONG upperBits = offset>>32;
LONG lowerBits = offset & 0xffffffff;
DWORD rc;
assert( id!=0 );
#ifdef SQLITE_TEST
if( offset ) SimulateDiskfullError(return SQLITE_FULL);
#endif
SEEK(offset/1024 + 1);
rc = SetFilePointer(((winFile*)id)->h, lowerBits, &upperBits, FILE_BEGIN);
TRACE3("SEEK %d %lld\n", ((winFile*)id)->h, offset);
if( rc==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR ){
return SQLITE_FULL;
}
return SQLITE_OK;
}
/*
** Make sure all writes to a particular file are committed to disk.
*/
static int winSync(OsFile *id, int dataOnly){
assert( id!=0 );
TRACE3("SYNC %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype);
if( FlushFileBuffers(((winFile*)id)->h) ){
return SQLITE_OK;
}else{
return SQLITE_IOERR;
}
}
/*
** Sync the directory zDirname. This is a no-op on operating systems other
** than UNIX.
*/
int sqlite3WinSyncDirectory(const char *zDirname){
SimulateIOError(return SQLITE_IOERR);
return SQLITE_OK;
}
/*
** Truncate an open file to a specified size
*/
static int winTruncate(OsFile *id, i64 nByte){
LONG upperBits = nByte>>32;
assert( id!=0 );
TRACE3("TRUNCATE %d %lld\n", ((winFile*)id)->h, nByte);
SimulateIOError(return SQLITE_IOERR);
SetFilePointer(((winFile*)id)->h, nByte, &upperBits, FILE_BEGIN);
SetEndOfFile(((winFile*)id)->h);
return SQLITE_OK;
}
/*
** Determine the current size of a file in bytes
*/
static int winFileSize(OsFile *id, i64 *pSize){
DWORD upperBits, lowerBits;
assert( id!=0 );
SimulateIOError(return SQLITE_IOERR);
lowerBits = GetFileSize(((winFile*)id)->h, &upperBits);
*pSize = (((i64)upperBits)<<32) + lowerBits;
return SQLITE_OK;
}
/*
** LOCKFILE_FAIL_IMMEDIATELY is undefined on some Windows systems.
*/
#ifndef LOCKFILE_FAIL_IMMEDIATELY
# define LOCKFILE_FAIL_IMMEDIATELY 1
#endif
/*
** Acquire a reader lock.
** Different API routines are called depending on whether or not this
** is Win95 or WinNT.
*/
static int getReadLock(winFile *id){
int res;
if( isNT() ){
OVERLAPPED ovlp;
ovlp.Offset = SHARED_FIRST;
ovlp.OffsetHigh = 0;
ovlp.hEvent = 0;
res = LockFileEx(id->h, LOCKFILE_FAIL_IMMEDIATELY, 0, SHARED_SIZE,0,&ovlp);
}else{
int lk;
sqlite3Randomness(sizeof(lk), &lk);
id->sharedLockByte = (lk & 0x7fffffff)%(SHARED_SIZE - 1);
res = LockFile(id->h, SHARED_FIRST+id->sharedLockByte, 0, 1, 0);
}
return res;
}
/*
** Undo a readlock
*/
static int unlockReadLock(winFile *pFile){
int res;
if( isNT() ){
res = UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
}else{
res = UnlockFile(pFile->h, SHARED_FIRST + pFile->sharedLockByte, 0, 1, 0);
}
return res;
}
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
/*
** Check that a given pathname is a directory and is writable
**
*/
int sqlite3WinIsDirWritable(char *zDirname){
int fileAttr;
WCHAR *zWide;
if( zDirname==0 ) return 0;
if( !isNT() && strlen(zDirname)>MAX_PATH ) return 0;
zWide = utf8ToUnicode(zDirname);
if( zWide ){
fileAttr = GetFileAttributesW(zWide);
sqliteFree(zWide);
}else{
#if OS_WINCE
return 0;
#else
fileAttr = GetFileAttributesA(zDirname);
#endif
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -