📄 os_os2.c
字号:
/*** 2006 Feb 14**** 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 OS/2.*/#include "sqliteInt.h"#include "os.h"#if OS_OS2/*** Macros used to determine whether or not to use threads.*/#if defined(THREADSAFE) && THREADSAFE# define SQLITE_OS2_THREADS 1#endif/*** Include code that is common to all os_*.c files*/#include "os_common.h"/*** The os2File structure is subclass of OsFile specific for the OS/2** protability layer.*/typedef struct os2File os2File;struct os2File { IoMethod const *pMethod; /* Always the first entry */ HFILE h; /* Handle for accessing the file */ int delOnClose; /* True if file is to be deleted on close */ char* pathToDel; /* Name of file to delete on close */ unsigned char locktype; /* Type of lock currently held on this file */};/*** Do not include any of the File I/O interface procedures if the** SQLITE_OMIT_DISKIO macro is defined (indicating that there database** will be in-memory only)*/#ifndef SQLITE_OMIT_DISKIO/*** Delete the named file*/int sqlite3Os2Delete( const char *zFilename ){ APIRET rc = NO_ERROR; rc = DosDelete( (PSZ)zFilename ); OSTRACE2( "DELETE \"%s\"\n", zFilename ); return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;}/*** Return TRUE if the named file exists.*/int sqlite3Os2FileExists( const char *zFilename ){ FILESTATUS3 fsts3ConfigInfo; memset(&fsts3ConfigInfo, 0, sizeof(fsts3ConfigInfo)); return DosQueryPathInfo( (PSZ)zFilename, FIL_STANDARD, &fsts3ConfigInfo, sizeof(FILESTATUS3) ) == NO_ERROR;}/* Forward declaration */int allocateOs2File( os2File *pInit, OsFile **pld );/*** 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 sqlite3Os2OpenReadWrite( const char *zFilename, OsFile **pld, int *pReadonly){ os2File f; HFILE hf; ULONG ulAction; APIRET rc = NO_ERROR; assert( *pld == 0 ); rc = DosOpen( (PSZ)zFilename, &hf, &ulAction, 0L, FILE_ARCHIVED | FILE_NORMAL, OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS, OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_RANDOM | OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE, (PEAOP2)NULL ); if( rc != NO_ERROR ){ rc = DosOpen( (PSZ)zFilename, &hf, &ulAction, 0L, FILE_ARCHIVED | FILE_NORMAL, OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS, OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_RANDOM | OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY, (PEAOP2)NULL ); if( rc != NO_ERROR ){ return SQLITE_CANTOPEN; } *pReadonly = 1; } else{ *pReadonly = 0; } f.h = hf; f.locktype = NO_LOCK; f.delOnClose = 0; f.pathToDel = NULL; OpenCounter(+1); OSTRACE3( "OPEN R/W %d \"%s\"\n", hf, zFilename ); return allocateOs2File( &f, pld );}/*** 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.*/int sqlite3Os2OpenExclusive( const char *zFilename, OsFile **pld, int delFlag ){ os2File f; HFILE hf; ULONG ulAction; APIRET rc = NO_ERROR; assert( *pld == 0 ); rc = DosOpen( (PSZ)zFilename, &hf, &ulAction, 0L, FILE_NORMAL, OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS, OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_RANDOM | OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_READWRITE, (PEAOP2)NULL ); if( rc != NO_ERROR ){ return SQLITE_CANTOPEN; } f.h = hf; f.locktype = NO_LOCK; f.delOnClose = delFlag ? 1 : 0; f.pathToDel = delFlag ? sqlite3OsFullPathname( zFilename ) : NULL; OpenCounter( +1 ); if( delFlag ) DosForceDelete( (PSZ)sqlite3OsFullPathname( zFilename ) ); OSTRACE3( "OPEN EX %d \"%s\"\n", hf, sqlite3OsFullPathname ( zFilename ) ); return allocateOs2File( &f, pld );}/*** 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 sqlite3Os2OpenReadOnly( const char *zFilename, OsFile **pld ){ os2File f; HFILE hf; ULONG ulAction; APIRET rc = NO_ERROR; assert( *pld == 0 ); rc = DosOpen( (PSZ)zFilename, &hf, &ulAction, 0L, FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS, OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_RANDOM | OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY, (PEAOP2)NULL ); if( rc != NO_ERROR ){ return SQLITE_CANTOPEN; } f.h = hf; f.locktype = NO_LOCK; f.delOnClose = 0; f.pathToDel = NULL; OpenCounter( +1 ); OSTRACE3( "OPEN RO %d \"%s\"\n", hf, zFilename ); return allocateOs2File( &f, pld );}/*** 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** OS/2 since OS/2 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.*/int os2OpenDirectory( OsFile *id, const char *zDirname){ return SQLITE_OK;}/*** Create a temporary file name in zBuf. zBuf must be big enough to** hold at least SQLITE_TEMPNAME_SIZE characters.*/int sqlite3Os2TempFileName( char *zBuf ){ static const unsigned char zChars[] = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"; int i, j; PSZ zTempPath = 0; if( DosScanEnv( (PSZ)"TEMP", &zTempPath ) ){ if( DosScanEnv( (PSZ)"TMP", &zTempPath ) ){ if( DosScanEnv( (PSZ)"TMPDIR", &zTempPath ) ){ ULONG ulDriveNum = 0, ulDriveMap = 0; DosQueryCurrentDisk( &ulDriveNum, &ulDriveMap ); sprintf( (char*)zTempPath, "%c:", (char)( 'A' + ulDriveNum - 1 ) ); } } } 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; } OSTRACE2( "TEMP FILENAME: %s\n", zBuf ); return SQLITE_OK;}/*** Close a file.*/int os2Close( OsFile **pld ){ os2File *pFile; APIRET rc = NO_ERROR; if( pld && (pFile = (os2File*)*pld) != 0 ){ OSTRACE2( "CLOSE %d\n", pFile->h ); rc = DosClose( pFile->h ); pFile->locktype = NO_LOCK; if( pFile->delOnClose != 0 ){ rc = DosForceDelete( (PSZ)pFile->pathToDel ); } *pld = 0; OpenCounter( -1 ); } return rc == NO_ERROR ? 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.*/int os2Read( OsFile *id, void *pBuf, int amt ){ ULONG got; assert( id!=0 ); SimulateIOError( return SQLITE_IOERR ); OSTRACE3( "READ %d lock=%d\n", ((os2File*)id)->h, ((os2File*)id)->locktype ); DosRead( ((os2File*)id)->h, pBuf, amt, &got ); if (got == (ULONG)amt) return SQLITE_OK; else if (got == 0) return SQLITE_IOERR_READ; else { memset(&((char*)pBuf)[got], 0, amt-got); return SQLITE_IOERR_SHORT_READ; }}/*** Write data from a buffer into a file. Return SQLITE_OK on success** or some other error code on failure.*/int os2Write( OsFile *id, const void *pBuf, int amt ){ APIRET rc = NO_ERROR; ULONG wrote; assert( id!=0 ); SimulateIOError( return SQLITE_IOERR ); SimulateDiskfullError( return SQLITE_FULL ); OSTRACE3( "WRITE %d lock=%d\n", ((os2File*)id)->h, ((os2File*)id)->locktype ); while( amt > 0 && (rc = DosWrite( ((os2File*)id)->h, (PVOID)pBuf, amt, &wrote )) && wrote > 0 ){ amt -= wrote; pBuf = &((char*)pBuf)[wrote]; } return ( rc != NO_ERROR || amt > (int)wrote ) ? SQLITE_FULL : SQLITE_OK;}/*** Move the read/write pointer in a file.*/int os2Seek( OsFile *id, i64 offset ){ APIRET rc = NO_ERROR; ULONG filePointer = 0L; assert( id!=0 ); rc = DosSetFilePtr( ((os2File*)id)->h, offset, FILE_BEGIN, &filePointer ); OSTRACE3( "SEEK %d %lld\n", ((os2File*)id)->h, offset ); return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;}/*** Make sure all writes to a particular file are committed to disk.*/int os2Sync( OsFile *id, int dataOnly ){ assert( id!=0 ); OSTRACE3( "SYNC %d lock=%d\n", ((os2File*)id)->h, ((os2File*)id)->locktype ); return DosResetBuffer( ((os2File*)id)->h ) == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;}/*** Sync the directory zDirname. This is a no-op on operating systems other** than UNIX.*/int sqlite3Os2SyncDirectory( const char *zDirname ){ SimulateIOError( return SQLITE_IOERR ); return SQLITE_OK;}/*** Truncate an open file to a specified size*/int os2Truncate( OsFile *id, i64 nByte ){ APIRET rc = NO_ERROR; ULONG upperBits = nByte>>32; assert( id!=0 ); OSTRACE3( "TRUNCATE %d %lld\n", ((os2File*)id)->h, nByte ); SimulateIOError( return SQLITE_IOERR ); rc = DosSetFilePtr( ((os2File*)id)->h, nByte, FILE_BEGIN, &upperBits ); if( rc != NO_ERROR ){ return SQLITE_IOERR; } rc = DosSetFilePtr( ((os2File*)id)->h, 0L, FILE_END, &upperBits ); return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;}/*** Determine the current size of a file in bytes*/int os2FileSize( OsFile *id, i64 *pSize ){ APIRET rc = NO_ERROR; FILESTATUS3 fsts3FileInfo; memset(&fsts3FileInfo, 0, sizeof(fsts3FileInfo)); assert( id!=0 ); SimulateIOError( return SQLITE_IOERR ); rc = DosQueryFileInfo( ((os2File*)id)->h, FIL_STANDARD, &fsts3FileInfo, sizeof(FILESTATUS3) ); if( rc == NO_ERROR ){ *pSize = fsts3FileInfo.cbFile; return SQLITE_OK; } else{ return SQLITE_IOERR; }}/*** Acquire a reader lock.*/static int getReadLock( os2File *id ){ FILELOCK LockArea, UnlockArea; memset(&LockArea, 0, sizeof(LockArea)); memset(&UnlockArea, 0, sizeof(UnlockArea)); LockArea.lOffset = SHARED_FIRST; LockArea.lRange = SHARED_SIZE; UnlockArea.lOffset = 0L; UnlockArea.lRange = 0L; return DosSetFileLocks( id->h, &UnlockArea, &LockArea, 2000L, 1L );}/*** Undo a readlock*/static int unlockReadLock( os2File *id ){ FILELOCK LockArea, UnlockArea; memset(&LockArea, 0, sizeof(LockArea)); memset(&UnlockArea, 0, sizeof(UnlockArea)); LockArea.lOffset = 0L; LockArea.lRange = 0L; UnlockArea.lOffset = SHARED_FIRST; UnlockArea.lRange = SHARED_SIZE; return DosSetFileLocks( id->h, &UnlockArea, &LockArea, 2000L, 1L );}#ifndef SQLITE_OMIT_PAGER_PRAGMAS/*** Check that a given pathname is a directory and is writable***/int sqlite3Os2IsDirWritable( char *zDirname ){ FILESTATUS3 fsts3ConfigInfo; APIRET rc = NO_ERROR; memset(&fsts3ConfigInfo, 0, sizeof(fsts3ConfigInfo)); if( zDirname==0 ) return 0; if( strlen(zDirname)>CCHMAXPATH ) return 0; rc = DosQueryPathInfo( (PSZ)zDirname, FIL_STANDARD, &fsts3ConfigInfo, sizeof(FILESTATUS3) ); if( rc != NO_ERROR ) return 0; if( (fsts3ConfigInfo.attrFile & FILE_DIRECTORY) != FILE_DIRECTORY ) return 0; return 1;}#endif /* SQLITE_OMIT_PAGER_PRAGMAS *//*** Lock the file with the lock specified by parameter locktype - 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. The os2Unlock() routine** erases all locks at once and returns us immediately to locking level 0.** It is not possible to lower the locking level one step at a time. You** must go straight to locking level 0.*/int os2Lock( OsFile *id, int locktype ){ APIRET rc = SQLITE_OK; /* Return code from subroutines */ APIRET res = NO_ERROR; /* Result of an OS/2 lock call */ int newLocktype; /* Set id->locktype to this value before exiting */ int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */ FILELOCK LockArea, UnlockArea; os2File *pFile = (os2File*)id; memset(&LockArea, 0, sizeof(LockArea)); memset(&UnlockArea, 0, sizeof(UnlockArea)); assert( pFile!=0 ); OSTRACE4( "LOCK %d %d was %d\n", pFile->h, locktype, pFile->locktype ); /* If there is already a lock of this type or more restrictive on the ** OsFile, do nothing. Don't use the end_lock: exit path, as ** sqlite3OsEnterMutex() hasn't been called yet. */ if( pFile->locktype>=locktype ){ return SQLITE_OK; } /* Make sure the locking sequence is correct */ assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK ); assert( locktype!=PENDING_LOCK ); assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK ); /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or ** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of ** the PENDING_LOCK byte is temporary. */ newLocktype = pFile->locktype; if( pFile->locktype==NO_LOCK || (locktype==EXCLUSIVE_LOCK && pFile->locktype==RESERVED_LOCK) ){ int cnt = 3; LockArea.lOffset = PENDING_BYTE; LockArea.lRange = 1L; UnlockArea.lOffset = 0L; UnlockArea.lRange = 0L; while( cnt-->0 && (res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 2000L, 1L) )!=NO_ERROR ){ /* Try 3 times to get the pending lock. The pending lock might be ** held by another reader process who will release it momentarily. */ OSTRACE2( "could not get a PENDING lock. cnt=%d\n", cnt ); DosSleep(1); } gotPendingLock = res; } /* Acquire a shared lock */ if( locktype==SHARED_LOCK && res ){ assert( pFile->locktype==NO_LOCK ); res = getReadLock(pFile);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -