Split up os.c into separate files, one for each platform. (CVS 1441)

FossilOrigin-Name: 5c61be1c47ac960fba2a642e69a98436ce1cd725
diff --git a/src/main.c b/src/main.c
index fefb1f4..09883aa 100644
--- a/src/main.c
+++ b/src/main.c
@@ -14,7 +14,7 @@
 ** other files are for internal use by SQLite and should not be
 ** accessed by users of the library.
 **
-** $Id: main.c,v 1.184 2004/05/22 09:21:21 danielk1977 Exp $
+** $Id: main.c,v 1.185 2004/05/22 17:41:59 drh Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -30,6 +30,12 @@
 } InitData;
 
 /*
+** The following constant value is used by the SQLITE3_BIGENDIAN and
+** SQLITE3_LITTLEENDIAN macros.
+*/
+const int sqlite3one = 1;
+
+/*
 ** Fill the InitData structure with an error message that indicates
 ** that the database is corrupt.
 */
@@ -1335,4 +1341,3 @@
   sqlite3VdbeMakeReady((Vdbe*)pStmt, -1, 0);
   return rc;
 }
-
diff --git a/src/os.c b/src/os.c
deleted file mode 100644
index 157b4cf..0000000
--- a/src/os.c
+++ /dev/null
@@ -1,1821 +0,0 @@
-/*
-** 2001 September 16
-**
-** 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 particular operating
-** systems.  The purpose of this file is to provide a uniform abstraction
-** on which the rest of SQLite can operate.
-*/
-#include "os.h"          /* Must be first to enable large file support */
-#include "sqliteInt.h"
-
-#if OS_UNIX
-# include <time.h>
-# include <errno.h>
-# include <unistd.h>
-# ifndef O_LARGEFILE
-#  define O_LARGEFILE 0
-# endif
-# ifdef SQLITE_DISABLE_LFS
-#  undef O_LARGEFILE
-#  define O_LARGEFILE 0
-# endif
-# ifndef O_NOFOLLOW
-#  define O_NOFOLLOW 0
-# endif
-# ifndef O_BINARY
-#  define O_BINARY 0
-# endif
-#endif
-
-
-#if OS_WIN
-# include <winbase.h>
-#endif
-
-#if OS_MAC
-# include <extras.h>
-# include <path2fss.h>
-# include <TextUtils.h>
-# include <FinderRegistry.h>
-# include <Folders.h>
-# include <Timer.h>
-# include <OSUtils.h>
-#endif
-
-/*
-** The DJGPP compiler environment looks mostly like Unix, but it
-** lacks the fcntl() system call.  So redefine fcntl() to be something
-** that always succeeds.  This means that locking does not occur under
-** DJGPP.  But its DOS - what did you expect?
-*/
-#ifdef __DJGPP__
-# define fcntl(A,B,C) 0
-#endif
-
-/*
-** Macros used to determine whether or not to use threads.  The
-** SQLITE_UNIX_THREADS macro is defined if we are synchronizing for
-** Posix threads and SQLITE_W32_THREADS is defined if we are
-** synchronizing using Win32 threads.
-*/
-#if OS_UNIX && defined(THREADSAFE) && THREADSAFE
-# include <pthread.h>
-# define SQLITE_UNIX_THREADS 1
-#endif
-#if OS_WIN && defined(THREADSAFE) && THREADSAFE
-# define SQLITE_W32_THREADS 1
-#endif
-#if OS_MAC && defined(THREADSAFE) && THREADSAFE
-# include <Multiprocessing.h>
-# define SQLITE_MACOS_MULTITASKING 1
-#endif
-
-/*
-** Macros for performance tracing.  Normally turned off
-*/
-#if 0
-static int last_page = 0;
-__inline__ unsigned long long int hwtime(void){
-  unsigned long long int x;
-  __asm__("rdtsc\n\t"
-          "mov %%edx, %%ecx\n\t"
-          :"=A" (x));
-  return x;
-}
-static unsigned long long int g_start;
-static unsigned int elapse;
-#define TIMER_START       g_start=hwtime()
-#define TIMER_END         elapse=hwtime()-g_start
-#define SEEK(X)           last_page=(X)
-#define TRACE1(X)         fprintf(stderr,X)
-#define TRACE2(X,Y)       fprintf(stderr,X,Y)
-#define TRACE3(X,Y,Z)     fprintf(stderr,X,Y,Z)
-#define TRACE4(X,Y,Z,A)   fprintf(stderr,X,Y,Z,A)
-#define TRACE5(X,Y,Z,A,B) fprintf(stderr,X,Y,Z,A,B)
-#else
-#define TIMER_START
-#define TIMER_END
-#define SEEK(X)
-#define TRACE1(X)
-#define TRACE2(X,Y)
-#define TRACE3(X,Y,Z)
-#define TRACE4(X,Y,Z,A)
-#define TRACE5(X,Y,Z,A,B)
-#endif
-
-
-#if OS_UNIX
-/*
-** Here is the dirt on POSIX advisory locks:  ANSI STD 1003.1 (1996)
-** section 6.5.2.2 lines 483 through 490 specify that when a process
-** sets or clears a lock, that operation overrides any prior locks set
-** by the same process.  It does not explicitly say so, but this implies
-** that it overrides locks set by the same process using a different
-** file descriptor.  Consider this test case:
-**
-**       int fd1 = open("./file1", O_RDWR|O_CREAT, 0644);
-**       int fd2 = open("./file2", O_RDWR|O_CREAT, 0644);
-**
-** Suppose ./file1 and ./file2 are really the same file (because
-** one is a hard or symbolic link to the other) then if you set
-** an exclusive lock on fd1, then try to get an exclusive lock
-** on fd2, it works.  I would have expected the second lock to
-** fail since there was already a lock on the file due to fd1.
-** But not so.  Since both locks came from the same process, the
-** second overrides the first, even though they were on different
-** file descriptors opened on different file names.
-**
-** Bummer.  If you ask me, this is broken.  Badly broken.  It means
-** that we cannot use POSIX locks to synchronize file access among
-** competing threads of the same process.  POSIX locks will work fine
-** to synchronize access for threads in separate processes, but not
-** threads within the same process.
-**
-** To work around the problem, SQLite has to manage file locks internally
-** on its own.  Whenever a new database is opened, we have to find the
-** specific inode of the database file (the inode is determined by the
-** st_dev and st_ino fields of the stat structure that fstat() fills in)
-** and check for locks already existing on that inode.  When locks are
-** created or removed, we have to look at our own internal record of the
-** locks to see if another thread has previously set a lock on that same
-** inode.
-**
-** The OsFile structure for POSIX is no longer just an integer file
-** descriptor.  It is now a structure that holds the integer file
-** descriptor and a pointer to a structure that describes the internal
-** locks on the corresponding inode.  There is one locking structure
-** per inode, so if the same inode is opened twice, both OsFile structures
-** point to the same locking structure.  The locking structure keeps
-** a reference count (so we will know when to delete it) and a "cnt"
-** field that tells us its internal lock status.  cnt==0 means the
-** file is unlocked.  cnt==-1 means the file has an exclusive lock.
-** cnt>0 means there are cnt shared locks on the file.
-**
-** Any attempt to lock or unlock a file first checks the locking
-** structure.  The fcntl() system call is only invoked to set a 
-** POSIX lock if the internal lock structure transitions between
-** a locked and an unlocked state.
-**
-** 2004-Jan-11:
-** More recent discoveries about POSIX advisory locks.  (The more
-** I discover, the more I realize the a POSIX advisory locks are
-** an abomination.)
-**
-** If you close a file descriptor that points to a file that has locks,
-** all locks on that file that are owned by the current process are
-** released.  To work around this problem, each OsFile structure contains
-** a pointer to an openCnt structure.  There is one openCnt structure
-** per open inode, which means that multiple OsFiles can point to a single
-** openCnt.  When an attempt is made to close an OsFile, if there are
-** other OsFiles open on the same inode that are holding locks, the call
-** to close() the file descriptor is deferred until all of the locks clear.
-** The openCnt structure keeps a list of file descriptors that need to
-** be closed and that list is walked (and cleared) when the last lock
-** clears.
-**
-** First, under Linux threads, because each thread has a separate
-** process ID, lock operations in one thread do not override locks
-** to the same file in other threads.  Linux threads behave like
-** separate processes in this respect.  But, if you close a file
-** descriptor in linux threads, all locks are cleared, even locks
-** on other threads and even though the other threads have different
-** process IDs.  Linux threads is inconsistent in this respect.
-** (I'm beginning to think that linux threads is an abomination too.)
-** The consequence of this all is that the hash table for the lockInfo
-** structure has to include the process id as part of its key because
-** locks in different threads are treated as distinct.  But the 
-** openCnt structure should not include the process id in its
-** key because close() clears lock on all threads, not just the current
-** thread.  Were it not for this goofiness in linux threads, we could
-** combine the lockInfo and openCnt structures into a single structure.
-*/
-
-/*
-** An instance of the following structure serves as the key used
-** to locate a particular lockInfo structure given its inode.  Note
-** that we have to include the process ID as part of the key.  On some
-** threading implementations (ex: linux), each thread has a separate
-** process ID.
-*/
-struct lockKey {
-  dev_t dev;   /* Device number */
-  ino_t ino;   /* Inode number */
-  pid_t pid;   /* Process ID */
-};
-
-/*
-** An instance of the following structure is allocated for each open
-** inode on each thread with a different process ID.  (Threads have
-** different process IDs on linux, but not on most other unixes.)
-**
-** A single inode can have multiple file descriptors, so each OsFile
-** structure contains a pointer to an instance of this object and this
-** object keeps a count of the number of OsFiles pointing to it.
-*/
-struct lockInfo {
-  struct lockKey key;  /* The lookup key */
-  int cnt;             /* 0: unlocked.  -1: write lock.  1...: read lock. */
-  int nRef;            /* Number of pointers to this structure */
-};
-
-/*
-** An instance of the following structure serves as the key used
-** to locate a particular openCnt structure given its inode.  This
-** is the same as the lockKey except that the process ID is omitted.
-*/
-struct openKey {
-  dev_t dev;   /* Device number */
-  ino_t ino;   /* Inode number */
-};
-
-/*
-** An instance of the following structure is allocated for each open
-** inode.  This structure keeps track of the number of locks on that
-** inode.  If a close is attempted against an inode that is holding
-** locks, the close is deferred until all locks clear by adding the
-** file descriptor to be closed to the pending list.
-*/
-struct openCnt {
-  struct openKey key;   /* The lookup key */
-  int nRef;             /* Number of pointers to this structure */
-  int nLock;            /* Number of outstanding locks */
-  int nPending;         /* Number of pending close() operations */
-  int *aPending;        /* Malloced space holding fd's awaiting a close() */
-};
-
-/* 
-** These hash table maps inodes and process IDs into lockInfo and openCnt
-** structures.  Access to these hash tables must be protected by a mutex.
-*/
-static Hash lockHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 };
-static Hash openHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 };
-
-/*
-** Release a lockInfo structure previously allocated by findLockInfo().
-*/
-static void releaseLockInfo(struct lockInfo *pLock){
-  pLock->nRef--;
-  if( pLock->nRef==0 ){
-    sqlite3HashInsert(&lockHash, &pLock->key, sizeof(pLock->key), 0);
-    sqliteFree(pLock);
-  }
-}
-
-/*
-** Release a openCnt structure previously allocated by findLockInfo().
-*/
-static void releaseOpenCnt(struct openCnt *pOpen){
-  pOpen->nRef--;
-  if( pOpen->nRef==0 ){
-    sqlite3HashInsert(&openHash, &pOpen->key, sizeof(pOpen->key), 0);
-    sqliteFree(pOpen->aPending);
-    sqliteFree(pOpen);
-  }
-}
-
-/*
-** Given a file descriptor, locate lockInfo and openCnt structures that
-** describes that file descriptor.  Create a new ones if necessary.  The
-** return values might be unset if an error occurs.
-**
-** Return the number of errors.
-*/
-int findLockInfo(
-  int fd,                      /* The file descriptor used in the key */
-  struct lockInfo **ppLock,    /* Return the lockInfo structure here */
-  struct openCnt **ppOpen   /* Return the openCnt structure here */
-){
-  int rc;
-  struct lockKey key1;
-  struct openKey key2;
-  struct stat statbuf;
-  struct lockInfo *pLock;
-  struct openCnt *pOpen;
-  rc = fstat(fd, &statbuf);
-  if( rc!=0 ) return 1;
-  memset(&key1, 0, sizeof(key1));
-  key1.dev = statbuf.st_dev;
-  key1.ino = statbuf.st_ino;
-  key1.pid = getpid();
-  memset(&key2, 0, sizeof(key2));
-  key2.dev = statbuf.st_dev;
-  key2.ino = statbuf.st_ino;
-  pLock = (struct lockInfo*)sqlite3HashFind(&lockHash, &key1, sizeof(key1));
-  if( pLock==0 ){
-    struct lockInfo *pOld;
-    pLock = sqliteMallocRaw( sizeof(*pLock) );
-    if( pLock==0 ) return 1;
-    pLock->key = key1;
-    pLock->nRef = 1;
-    pLock->cnt = 0;
-    pOld = sqlite3HashInsert(&lockHash, &pLock->key, sizeof(key1), pLock);
-    if( pOld!=0 ){
-      assert( pOld==pLock );
-      sqliteFree(pLock);
-      return 1;
-    }
-  }else{
-    pLock->nRef++;
-  }
-  *ppLock = pLock;
-  pOpen = (struct openCnt*)sqlite3HashFind(&openHash, &key2, sizeof(key2));
-  if( pOpen==0 ){
-    struct openCnt *pOld;
-    pOpen = sqliteMallocRaw( sizeof(*pOpen) );
-    if( pOpen==0 ){
-      releaseLockInfo(pLock);
-      return 1;
-    }
-    pOpen->key = key2;
-    pOpen->nRef = 1;
-    pOpen->nLock = 0;
-    pOpen->nPending = 0;
-    pOpen->aPending = 0;
-    pOld = sqlite3HashInsert(&openHash, &pOpen->key, sizeof(key2), pOpen);
-    if( pOld!=0 ){
-      assert( pOld==pOpen );
-      sqliteFree(pOpen);
-      releaseLockInfo(pLock);
-      return 1;
-    }
-  }else{
-    pOpen->nRef++;
-  }
-  *ppOpen = pOpen;
-  return 0;
-}
-
-#endif  /** POSIX advisory lock work-around **/
-
-/*
-** If we compile with the SQLITE_TEST macro set, then the following block
-** of code will give us the ability to simulate a disk I/O error.  This
-** is used for testing the I/O recovery logic.
-*/
-#ifdef SQLITE_TEST
-int sqlite3_io_error_pending = 0;
-#define SimulateIOError(A)  \
-   if( sqlite3_io_error_pending ) \
-     if( sqlite3_io_error_pending-- == 1 ){ local_ioerr(); return A; }
-static void local_ioerr(){
-  sqlite3_io_error_pending = 0;  /* Really just a place to set a breakpoint */
-}
-#else
-#define SimulateIOError(A)
-#endif
-
-/*
-** When testing, keep a count of the number of open files.
-*/
-#ifdef SQLITE_TEST
-int sqlite3_open_file_count = 0;
-#define OpenCounter(X)  sqlite3_open_file_count+=(X)
-#else
-#define OpenCounter(X)
-#endif
-
-
-/*
-** Delete the named file
-*/
-int sqlite3OsDelete(const char *zFilename){
-#if OS_UNIX
-  unlink(zFilename);
-#endif
-#if OS_WIN
-  DeleteFile(zFilename);
-#endif
-#if OS_MAC
-  unlink(zFilename);
-#endif
-  return SQLITE_OK;
-}
-
-/*
-** Return TRUE if the named file exists.
-*/
-int sqlite3OsFileExists(const char *zFilename){
-#if OS_UNIX
-  return access(zFilename, 0)==0;
-#endif
-#if OS_WIN
-  return GetFileAttributes(zFilename) != 0xffffffff;
-#endif
-#if OS_MAC
-  return access(zFilename, 0)==0;
-#endif
-}
-
-
-#if 0 /* NOT USED */
-/*
-** Change the name of an existing file.
-*/
-int sqliteOsFileRename(const char *zOldName, const char *zNewName){
-#if OS_UNIX
-  if( link(zOldName, zNewName) ){
-    return SQLITE_ERROR;
-  }
-  unlink(zOldName);
-  return SQLITE_OK;
-#endif
-#if OS_WIN
-  if( !MoveFile(zOldName, zNewName) ){
-    return SQLITE_ERROR;
-  }
-  return SQLITE_OK;
-#endif
-#if OS_MAC
-  /**** FIX ME ***/
-  return SQLITE_ERROR;
-#endif
-}
-#endif /* NOT USED */
-
-/*
-** 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 sqlite3OsOpenReadWrite(
-  const char *zFilename,
-  OsFile *id,
-  int *pReadonly
-){
-#if OS_UNIX
-  int rc;
-  id->dirfd = -1;
-  id->fd = open(zFilename, O_RDWR|O_CREAT|O_LARGEFILE|O_BINARY, 0644);
-  if( id->fd<0 ){
-    id->fd = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY);
-    if( id->fd<0 ){
-      return SQLITE_CANTOPEN; 
-    }
-    *pReadonly = 1;
-  }else{
-    *pReadonly = 0;
-  }
-  sqlite3OsEnterMutex();
-  rc = findLockInfo(id->fd, &id->pLock, &id->pOpen);
-  sqlite3OsLeaveMutex();
-  if( rc ){
-    close(id->fd);
-    return SQLITE_NOMEM;
-  }
-  id->locked = 0;
-  TRACE3("OPEN    %-3d %s\n", id->fd, zFilename);
-  OpenCounter(+1);
-  return SQLITE_OK;
-#endif
-#if OS_WIN
-  HANDLE h = CreateFile(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 = CreateFile(zFilename,
-       GENERIC_READ,
-       FILE_SHARE_READ,
-       NULL,
-       OPEN_ALWAYS,
-       FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
-       NULL
-    );
-    if( h==INVALID_HANDLE_VALUE ){
-      return SQLITE_CANTOPEN;
-    }
-    *pReadonly = 1;
-  }else{
-    *pReadonly = 0;
-  }
-  id->h = h;
-  id->locked = 0;
-  OpenCounter(+1);
-  return SQLITE_OK;
-#endif
-#if OS_MAC
-  FSSpec fsSpec;
-# ifdef _LARGE_FILE
-  HFSUniStr255 dfName;
-  FSRef fsRef;
-  if( __path2fss(zFilename, &fsSpec) != noErr ){
-    if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr )
-      return SQLITE_CANTOPEN;
-  }
-  if( FSpMakeFSRef(&fsSpec, &fsRef) != noErr )
-    return SQLITE_CANTOPEN;
-  FSGetDataForkName(&dfName);
-  if( FSOpenFork(&fsRef, dfName.length, dfName.unicode,
-                 fsRdWrShPerm, &(id->refNum)) != noErr ){
-    if( FSOpenFork(&fsRef, dfName.length, dfName.unicode,
-                   fsRdWrPerm, &(id->refNum)) != noErr ){
-      if (FSOpenFork(&fsRef, dfName.length, dfName.unicode,
-                   fsRdPerm, &(id->refNum)) != noErr )
-        return SQLITE_CANTOPEN;
-      else
-        *pReadonly = 1;
-    } else
-      *pReadonly = 0;
-  } else
-    *pReadonly = 0;
-# else
-  __path2fss(zFilename, &fsSpec);
-  if( !sqlite3OsFileExists(zFilename) ){
-    if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr )
-      return SQLITE_CANTOPEN;
-  }
-  if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrShPerm, &(id->refNum)) != noErr ){
-    if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrPerm, &(id->refNum)) != noErr ){
-      if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdPerm, &(id->refNum)) != noErr )
-        return SQLITE_CANTOPEN;
-      else
-        *pReadonly = 1;
-    } else
-      *pReadonly = 0;
-  } else
-    *pReadonly = 0;
-# endif
-  if( HOpenRF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrShPerm, &(id->refNumRF)) != noErr){
-    id->refNumRF = -1;
-  }
-  id->locked = 0;
-  id->delOnClose = 0;
-  OpenCounter(+1);
-  return SQLITE_OK;
-#endif
-}
-
-
-/*
-** 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 sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
-#if OS_UNIX
-  int rc;
-  if( access(zFilename, 0)==0 ){
-    return SQLITE_CANTOPEN;
-  }
-  id->dirfd = -1;
-  id->fd = open(zFilename,
-                O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_LARGEFILE|O_BINARY, 0600);
-  if( id->fd<0 ){
-    return SQLITE_CANTOPEN;
-  }
-  sqlite3OsEnterMutex();
-  rc = findLockInfo(id->fd, &id->pLock, &id->pOpen);
-  sqlite3OsLeaveMutex();
-  if( rc ){
-    close(id->fd);
-    unlink(zFilename);
-    return SQLITE_NOMEM;
-  }
-  id->locked = 0;
-  if( delFlag ){
-    unlink(zFilename);
-  }
-  TRACE3("OPEN-EX %-3d %s\n", id->fd, zFilename);
-  OpenCounter(+1);
-  return SQLITE_OK;
-#endif
-#if OS_WIN
-  HANDLE h;
-  int fileflags;
-  if( delFlag ){
-    fileflags = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_RANDOM_ACCESS 
-                     | FILE_FLAG_DELETE_ON_CLOSE;
-  }else{
-    fileflags = FILE_FLAG_RANDOM_ACCESS;
-  }
-  h = CreateFile(zFilename,
-     GENERIC_READ | GENERIC_WRITE,
-     0,
-     NULL,
-     CREATE_ALWAYS,
-     fileflags,
-     NULL
-  );
-  if( h==INVALID_HANDLE_VALUE ){
-    return SQLITE_CANTOPEN;
-  }
-  id->h = h;
-  id->locked = 0;
-  OpenCounter(+1);
-  return SQLITE_OK;
-#endif
-#if OS_MAC
-  FSSpec fsSpec;
-# ifdef _LARGE_FILE
-  HFSUniStr255 dfName;
-  FSRef fsRef;
-  __path2fss(zFilename, &fsSpec);
-  if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr )
-    return SQLITE_CANTOPEN;
-  if( FSpMakeFSRef(&fsSpec, &fsRef) != noErr )
-    return SQLITE_CANTOPEN;
-  FSGetDataForkName(&dfName);
-  if( FSOpenFork(&fsRef, dfName.length, dfName.unicode,
-                 fsRdWrPerm, &(id->refNum)) != noErr )
-    return SQLITE_CANTOPEN;
-# else
-  __path2fss(zFilename, &fsSpec);
-  if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr )
-    return SQLITE_CANTOPEN;
-  if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrPerm, &(id->refNum)) != noErr )
-    return SQLITE_CANTOPEN;
-# endif
-  id->refNumRF = -1;
-  id->locked = 0;
-  id->delOnClose = delFlag;
-  if (delFlag)
-    id->pathToDel = sqlite3OsFullPathname(zFilename);
-  OpenCounter(+1);
-  return SQLITE_OK;
-#endif
-}
-
-/*
-** 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 sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
-#if OS_UNIX
-  int rc;
-  id->dirfd = -1;
-  id->fd = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY);
-  if( id->fd<0 ){
-    return SQLITE_CANTOPEN;
-  }
-  sqlite3OsEnterMutex();
-  rc = findLockInfo(id->fd, &id->pLock, &id->pOpen);
-  sqlite3OsLeaveMutex();
-  if( rc ){
-    close(id->fd);
-    return SQLITE_NOMEM;
-  }
-  id->locked = 0;
-  TRACE3("OPEN-RO %-3d %s\n", id->fd, zFilename);
-  OpenCounter(+1);
-  return SQLITE_OK;
-#endif
-#if OS_WIN
-  HANDLE h = CreateFile(zFilename,
-     GENERIC_READ,
-     0,
-     NULL,
-     OPEN_EXISTING,
-     FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
-     NULL
-  );
-  if( h==INVALID_HANDLE_VALUE ){
-    return SQLITE_CANTOPEN;
-  }
-  id->h = h;
-  id->locked = 0;
-  OpenCounter(+1);
-  return SQLITE_OK;
-#endif
-#if OS_MAC
-  FSSpec fsSpec;
-# ifdef _LARGE_FILE
-  HFSUniStr255 dfName;
-  FSRef fsRef;
-  if( __path2fss(zFilename, &fsSpec) != noErr )
-    return SQLITE_CANTOPEN;
-  if( FSpMakeFSRef(&fsSpec, &fsRef) != noErr )
-    return SQLITE_CANTOPEN;
-  FSGetDataForkName(&dfName);
-  if( FSOpenFork(&fsRef, dfName.length, dfName.unicode,
-                 fsRdPerm, &(id->refNum)) != noErr )
-    return SQLITE_CANTOPEN;
-# else
-  __path2fss(zFilename, &fsSpec);
-  if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdPerm, &(id->refNum)) != noErr )
-    return SQLITE_CANTOPEN;
-# endif
-  if( HOpenRF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrShPerm, &(id->refNumRF)) != noErr){
-    id->refNumRF = -1;
-  }
-  id->locked = 0;
-  id->delOnClose = 0;
-  OpenCounter(+1);
-  return SQLITE_OK;
-#endif
-}
-
-/*
-** 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.
-*/
-int sqlite3OsOpenDirectory(
-  const char *zDirname,
-  OsFile *id
-){
-#if OS_UNIX
-  if( id->fd<0 ){
-    /* Do not open the directory if the corresponding file is not already
-    ** open. */
-    return SQLITE_CANTOPEN;
-  }
-  assert( id->dirfd<0 );
-  id->dirfd = open(zDirname, O_RDONLY|O_BINARY, 0644);
-  if( id->dirfd<0 ){
-    return SQLITE_CANTOPEN; 
-  }
-  TRACE3("OPENDIR %-3d %s\n", id->dirfd, zDirname);
-#endif
-  return SQLITE_OK;
-}
-
-/*
-** Create a temporary file name in zBuf.  zBuf must be big enough to
-** hold at least SQLITE_TEMPNAME_SIZE characters.
-*/
-int sqlite3OsTempFileName(char *zBuf){
-#if OS_UNIX
-  static const char *azDirs[] = {
-     "/var/tmp",
-     "/usr/tmp",
-     "/tmp",
-     ".",
-  };
-  static unsigned char zChars[] =
-    "abcdefghijklmnopqrstuvwxyz"
-    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-    "0123456789";
-  int i, j;
-  struct stat buf;
-  const char *zDir = ".";
-  for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); i++){
-    if( stat(azDirs[i], &buf) ) continue;
-    if( !S_ISDIR(buf.st_mode) ) continue;
-    if( access(azDirs[i], 07) ) continue;
-    zDir = azDirs[i];
-    break;
-  }
-  do{
-    sprintf(zBuf, "%s/"TEMP_FILE_PREFIX, zDir);
-    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;
-  }while( access(zBuf,0)==0 );
-#endif
-#if OS_WIN
-  static char zChars[] =
-    "abcdefghijklmnopqrstuvwxyz"
-    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-    "0123456789";
-  int i, j;
-  char zTempPath[SQLITE_TEMPNAME_SIZE];
-  GetTempPath(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;
-  }
-#endif
-#if OS_MAC
-  static char zChars[] =
-    "abcdefghijklmnopqrstuvwxyz"
-    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-    "0123456789";
-  int i, j;
-  char zTempPath[SQLITE_TEMPNAME_SIZE];
-  char zdirName[32];
-  CInfoPBRec infoRec;
-  Str31 dirName;
-  memset(&infoRec, 0, sizeof(infoRec));
-  memset(zTempPath, 0, SQLITE_TEMPNAME_SIZE);
-  if( FindFolder(kOnSystemDisk, kTemporaryFolderType,  kCreateFolder,
-       &(infoRec.dirInfo.ioVRefNum), &(infoRec.dirInfo.ioDrParID)) == noErr ){
-    infoRec.dirInfo.ioNamePtr = dirName;
-    do{
-      infoRec.dirInfo.ioFDirIndex = -1;
-      infoRec.dirInfo.ioDrDirID = infoRec.dirInfo.ioDrParID;
-      if( PBGetCatInfoSync(&infoRec) == noErr ){
-        CopyPascalStringToC(dirName, zdirName);
-        i = strlen(zdirName);
-        memmove(&(zTempPath[i+1]), zTempPath, strlen(zTempPath));
-        strcpy(zTempPath, zdirName);
-        zTempPath[i] = ':';
-      }else{
-        *zTempPath = 0;
-        break;
-      }
-    } while( infoRec.dirInfo.ioDrDirID != fsRtDirID );
-  }
-  if( *zTempPath == 0 )
-    getcwd(zTempPath, SQLITE_TEMPNAME_SIZE-24);
-  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;
-  }
-#endif
-  return SQLITE_OK; 
-}
-
-/*
-** Close a file.
-*/
-int sqlite3OsClose(OsFile *id){
-#if OS_UNIX
-  sqlite3OsUnlock(id);
-  if( id->dirfd>=0 ) close(id->dirfd);
-  id->dirfd = -1;
-  sqlite3OsEnterMutex();
-  if( id->pOpen->nLock ){
-    /* If there are outstanding locks, do not actually close the file just
-    ** yet because that would clear those locks.  Instead, add the file
-    ** descriptor to pOpen->aPending.  It will be automatically closed when
-    ** the last lock is cleared.
-    */
-    int *aNew;
-    struct openCnt *pOpen = id->pOpen;
-    pOpen->nPending++;
-    aNew = sqliteRealloc( pOpen->aPending, pOpen->nPending*sizeof(int) );
-    if( aNew==0 ){
-      /* If a malloc fails, just leak the file descriptor */
-    }else{
-      pOpen->aPending = aNew;
-      pOpen->aPending[pOpen->nPending-1] = id->fd;
-    }
-  }else{
-    /* There are no outstanding locks so we can close the file immediately */
-    close(id->fd);
-  }
-  releaseLockInfo(id->pLock);
-  releaseOpenCnt(id->pOpen);
-  sqlite3OsLeaveMutex();
-  TRACE2("CLOSE   %-3d\n", id->fd);
-  OpenCounter(-1);
-  return SQLITE_OK;
-#endif
-#if OS_WIN
-  CloseHandle(id->h);
-  OpenCounter(-1);
-  return SQLITE_OK;
-#endif
-#if OS_MAC
-  if( id->refNumRF!=-1 )
-    FSClose(id->refNumRF);
-# ifdef _LARGE_FILE
-  FSCloseFork(id->refNum);
-# else
-  FSClose(id->refNum);
-# endif
-  if( id->delOnClose ){
-    unlink(id->pathToDel);
-    sqliteFree(id->pathToDel);
-  }
-  OpenCounter(-1);
-  return SQLITE_OK;
-#endif
-}
-
-/*
-** 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 sqlite3OsRead(OsFile *id, void *pBuf, int amt){
-#if OS_UNIX
-  int got;
-  SimulateIOError(SQLITE_IOERR);
-  TIMER_START;
-  got = read(id->fd, pBuf, amt);
-  TIMER_END;
-  TRACE4("READ    %-3d %7d %d\n", id->fd, last_page, elapse);
-  SEEK(0);
-  /* if( got<0 ) got = 0; */
-  if( got==amt ){
-    return SQLITE_OK;
-  }else{
-    return SQLITE_IOERR;
-  }
-#endif
-#if OS_WIN
-  DWORD got;
-  SimulateIOError(SQLITE_IOERR);
-  TRACE2("READ %d\n", last_page);
-  if( !ReadFile(id->h, pBuf, amt, &got, 0) ){
-    got = 0;
-  }
-  if( got==(DWORD)amt ){
-    return SQLITE_OK;
-  }else{
-    return SQLITE_IOERR;
-  }
-#endif
-#if OS_MAC
-  int got;
-  SimulateIOError(SQLITE_IOERR);
-  TRACE2("READ %d\n", last_page);
-# ifdef _LARGE_FILE
-  FSReadFork(id->refNum, fsAtMark, 0, (ByteCount)amt, pBuf, (ByteCount*)&got);
-# else
-  got = amt;
-  FSRead(id->refNum, &got, pBuf);
-# endif
-  if( got==amt ){
-    return SQLITE_OK;
-  }else{
-    return SQLITE_IOERR;
-  }
-#endif
-}
-
-/*
-** Write data from a buffer into a file.  Return SQLITE_OK on success
-** or some other error code on failure.
-*/
-int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
-#if OS_UNIX
-  int wrote = 0;
-  SimulateIOError(SQLITE_IOERR);
-  TIMER_START;
-  while( amt>0 && (wrote = write(id->fd, pBuf, amt))>0 ){
-    amt -= wrote;
-    pBuf = &((char*)pBuf)[wrote];
-  }
-  TIMER_END;
-  TRACE4("WRITE   %-3d %7d %d\n", id->fd, last_page, elapse);
-  SEEK(0);
-  if( amt>0 ){
-    return SQLITE_FULL;
-  }
-  return SQLITE_OK;
-#endif
-#if OS_WIN
-  int rc;
-  DWORD wrote;
-  SimulateIOError(SQLITE_IOERR);
-  TRACE2("WRITE %d\n", last_page);
-  while( amt>0 && (rc = WriteFile(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;
-#endif
-#if OS_MAC
-  OSErr oserr;
-  int wrote = 0;
-  SimulateIOError(SQLITE_IOERR);
-  TRACE2("WRITE %d\n", last_page);
-  while( amt>0 ){
-# ifdef _LARGE_FILE
-    oserr = FSWriteFork(id->refNum, fsAtMark, 0,
-                        (ByteCount)amt, pBuf, (ByteCount*)&wrote);
-# else
-    wrote = amt;
-    oserr = FSWrite(id->refNum, &wrote, pBuf);
-# endif
-    if( wrote == 0 || oserr != noErr)
-      break;
-    amt -= wrote;
-    pBuf = &((char*)pBuf)[wrote];
-  }
-  if( oserr != noErr || amt>wrote ){
-    return SQLITE_FULL;
-  }
-  return SQLITE_OK;
-#endif
-}
-
-/*
-** Move the read/write pointer in a file.
-*/
-int sqlite3OsSeek(OsFile *id, off_t offset){
-  SEEK(offset/1024 + 1);
-#if OS_UNIX
-  lseek(id->fd, offset, SEEK_SET);
-  return SQLITE_OK;
-#endif
-#if OS_WIN
-  {
-    LONG upperBits = offset>>32;
-    LONG lowerBits = offset & 0xffffffff;
-    DWORD rc;
-    rc = SetFilePointer(id->h, lowerBits, &upperBits, FILE_BEGIN);
-    /* TRACE3("SEEK rc=0x%x upper=0x%x\n", rc, upperBits); */
-  }
-  return SQLITE_OK;
-#endif
-#if OS_MAC
-  {
-    off_t curSize;
-    if( sqlite3OsFileSize(id, &curSize) != SQLITE_OK ){
-      return SQLITE_IOERR;
-    }
-    if( offset >= curSize ){
-      if( sqlite3OsTruncate(id, offset+1) != SQLITE_OK ){
-        return SQLITE_IOERR;
-      }
-    }
-# ifdef _LARGE_FILE
-    if( FSSetForkPosition(id->refNum, fsFromStart, offset) != noErr ){
-# else
-    if( SetFPos(id->refNum, fsFromStart, offset) != noErr ){
-# endif
-      return SQLITE_IOERR;
-    }else{
-      return SQLITE_OK;
-    }
-  }
-#endif
-}
-
-/*
-** Make sure all writes to a particular file are committed to disk.
-**
-** Under Unix, 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.
-*/
-int sqlite3OsSync(OsFile *id){
-#if OS_UNIX
-  SimulateIOError(SQLITE_IOERR);
-  TRACE2("SYNC    %-3d\n", id->fd);
-  if( fsync(id->fd) ){
-    return SQLITE_IOERR;
-  }else{
-    if( id->dirfd>=0 ){
-      TRACE2("DIRSYNC %-3d\n", id->dirfd);
-      fsync(id->dirfd);
-      close(id->dirfd);  /* Only need to sync once, so close the directory */
-      id->dirfd = -1;    /* when we are done. */
-    }
-    return SQLITE_OK;
-  }
-#endif
-#if OS_WIN
-  if( FlushFileBuffers(id->h) ){
-    return SQLITE_OK;
-  }else{
-    return SQLITE_IOERR;
-  }
-#endif
-#if OS_MAC
-# ifdef _LARGE_FILE
-  if( FSFlushFork(id->refNum) != noErr ){
-# else
-  ParamBlockRec params;
-  memset(&params, 0, sizeof(ParamBlockRec));
-  params.ioParam.ioRefNum = id->refNum;
-  if( PBFlushFileSync(&params) != noErr ){
-# endif
-    return SQLITE_IOERR;
-  }else{
-    return SQLITE_OK;
-  }
-#endif
-}
-
-/*
-** Truncate an open file to a specified size
-*/
-int sqlite3OsTruncate(OsFile *id, off_t nByte){
-  SimulateIOError(SQLITE_IOERR);
-#if OS_UNIX
-  return ftruncate(id->fd, nByte)==0 ? SQLITE_OK : SQLITE_IOERR;
-#endif
-#if OS_WIN
-  {
-    LONG upperBits = nByte>>32;
-    SetFilePointer(id->h, nByte, &upperBits, FILE_BEGIN);
-    SetEndOfFile(id->h);
-  }
-  return SQLITE_OK;
-#endif
-#if OS_MAC
-# ifdef _LARGE_FILE
-  if( FSSetForkSize(id->refNum, fsFromStart, nByte) != noErr){
-# else
-  if( SetEOF(id->refNum, nByte) != noErr ){
-# endif
-    return SQLITE_IOERR;
-  }else{
-    return SQLITE_OK;
-  }
-#endif
-}
-
-/*
-** Determine the current size of a file in bytes
-*/
-int sqlite3OsFileSize(OsFile *id, off_t *pSize){
-#if OS_UNIX
-  struct stat buf;
-  SimulateIOError(SQLITE_IOERR);
-  if( fstat(id->fd, &buf)!=0 ){
-    return SQLITE_IOERR;
-  }
-  *pSize = buf.st_size;
-  return SQLITE_OK;
-#endif
-#if OS_WIN
-  DWORD upperBits, lowerBits;
-  SimulateIOError(SQLITE_IOERR);
-  lowerBits = GetFileSize(id->h, &upperBits);
-  *pSize = (((off_t)upperBits)<<32) + lowerBits;
-  return SQLITE_OK;
-#endif
-#if OS_MAC
-# ifdef _LARGE_FILE
-  if( FSGetForkSize(id->refNum, pSize) != noErr){
-# else
-  if( GetEOF(id->refNum, pSize) != noErr ){
-# endif
-    return SQLITE_IOERR;
-  }else{
-    return SQLITE_OK;
-  }
-#endif
-}
-
-#if OS_WIN
-/*
-** Return true (non-zero) if we are running under WinNT, Win2K or WinXP.
-** Return false (zero) for Win95, Win98, or WinME.
-**
-** Here is an interesting observation:  Win95, Win98, and WinME lack
-** the LockFileEx() API.  But we can still statically link against that
-** API as long as we don't call it win running Win95/98/ME.  A call to
-** this routine is used to determine if the host is Win95/98/ME or
-** WinNT/2K/XP so that we will know whether or not we can safely call
-** the LockFileEx() API.
-*/
-int isNT(void){
-  static int osType = 0;   /* 0=unknown 1=win95 2=winNT */
-  if( osType==0 ){
-    OSVERSIONINFO sInfo;
-    sInfo.dwOSVersionInfoSize = sizeof(sInfo);
-    GetVersionEx(&sInfo);
-    osType = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1;
-  }
-  return osType==2;
-}
-#endif
-
-/*
-** Windows file locking notes:  [similar issues apply to MacOS]
-**
-** We cannot use LockFileEx() or UnlockFileEx() on Win95/98/ME because
-** those functions are not available.  So we use only LockFile() and
-** UnlockFile().
-**
-** LockFile() prevents not just writing but also reading by other processes.
-** (This is a design error on the part of Windows, but there is nothing
-** we can do about that.)  So the region used for locking is at the
-** end of the file where it is unlikely to ever interfere with an
-** actual read attempt.
-**
-** A database read lock is obtained by locking a single randomly-chosen 
-** byte out of a specific range of bytes. The lock byte is obtained at 
-** random so two separate readers can probably access the file at the 
-** same time, unless they are unlucky and choose the same lock byte.
-** A database write lock is obtained by locking all bytes in the range.
-** There can only be one writer.
-**
-** A lock is obtained on the first byte of the lock range before acquiring
-** either a read lock or a write lock.  This prevents two processes from
-** attempting to get a lock at a same time.  The semantics of 
-** sqlite3OsReadLock() require that if there is already a write lock, that
-** lock is converted into a read lock atomically.  The lock on the first
-** byte allows us to drop the old write lock and get the read lock without
-** another process jumping into the middle and messing us up.  The same
-** argument applies to sqlite3OsWriteLock().
-**
-** On WinNT/2K/XP systems, LockFileEx() and UnlockFileEx() are available,
-** which means we can use reader/writer locks.  When reader writer locks
-** are used, the lock is placed on the same range of bytes that is used
-** for probabilistic locking in Win95/98/ME.  Hence, the locking scheme
-** will support two or more Win95 readers or two or more WinNT readers.
-** But a single Win95 reader will lock out all WinNT readers and a single
-** WinNT reader will lock out all other Win95 readers.
-**
-** Note: On MacOS we use the resource fork for locking.
-**
-** The following #defines specify the range of bytes used for locking.
-** N_LOCKBYTE is the number of bytes available for doing the locking.
-** The first byte used to hold the lock while the lock is changing does
-** not count toward this number.  FIRST_LOCKBYTE is the address of
-** the first byte in the range of bytes used for locking.
-*/
-#define N_LOCKBYTE       10239
-#if OS_MAC
-# define FIRST_LOCKBYTE   (0x000fffff - N_LOCKBYTE)
-#else
-# define FIRST_LOCKBYTE   (0xffffffff - N_LOCKBYTE)
-#endif
-
-/*
-** Change the status of the lock on the file "id" to be a readlock.
-** If the file was write locked, then this reduces the lock to a read.
-** If the file was read locked, then this acquires a new read lock.
-**
-** Return SQLITE_OK on success and SQLITE_BUSY on failure.  If this
-** library was compiled with large file support (LFS) but LFS is not
-** available on the host, then an SQLITE_NOLFS is returned.
-*/
-int sqlite3OsReadLock(OsFile *id){
-#if OS_UNIX
-  int rc;
-  sqlite3OsEnterMutex();
-  if( id->pLock->cnt>0 ){
-    if( !id->locked ){
-      id->pLock->cnt++;
-      id->locked = 1;
-      id->pOpen->nLock++;
-    }
-    rc = SQLITE_OK;
-  }else if( id->locked || id->pLock->cnt==0 ){
-    struct flock lock;
-    int s;
-    lock.l_type = F_RDLCK;
-    lock.l_whence = SEEK_SET;
-    lock.l_start = lock.l_len = 0L;
-    s = fcntl(id->fd, F_SETLK, &lock);
-    if( s!=0 ){
-      rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
-    }else{
-      rc = SQLITE_OK;
-      if( !id->locked ){
-        id->pOpen->nLock++;
-        id->locked = 1;
-      }
-      id->pLock->cnt = 1;
-    }
-  }else{
-    rc = SQLITE_BUSY;
-  }
-  sqlite3OsLeaveMutex();
-  return rc;
-#endif
-#if OS_WIN
-  int rc;
-  if( id->locked>0 ){
-    rc = SQLITE_OK;
-  }else{
-    int lk;
-    int res;
-    int cnt = 100;
-    sqlite3Randomness(sizeof(lk), &lk);
-    lk = (lk & 0x7fffffff)%N_LOCKBYTE + 1;
-    while( cnt-->0 && (res = LockFile(id->h, FIRST_LOCKBYTE, 0, 1, 0))==0 ){
-      Sleep(1);
-    }
-    if( res ){
-      UnlockFile(id->h, FIRST_LOCKBYTE+1, 0, N_LOCKBYTE, 0);
-      if( isNT() ){
-        OVERLAPPED ovlp;
-        ovlp.Offset = FIRST_LOCKBYTE+1;
-        ovlp.OffsetHigh = 0;
-        ovlp.hEvent = 0;
-        res = LockFileEx(id->h, LOCKFILE_FAIL_IMMEDIATELY, 
-                          0, N_LOCKBYTE, 0, &ovlp);
-      }else{
-        res = LockFile(id->h, FIRST_LOCKBYTE+lk, 0, 1, 0);
-      }
-      UnlockFile(id->h, FIRST_LOCKBYTE, 0, 1, 0);
-    }
-    if( res ){
-      id->locked = lk;
-      rc = SQLITE_OK;
-    }else{
-      rc = SQLITE_BUSY;
-    }
-  }
-  return rc;
-#endif
-#if OS_MAC
-  int rc;
-  if( id->locked>0 || id->refNumRF == -1 ){
-    rc = SQLITE_OK;
-  }else{
-    int lk;
-    OSErr res;
-    int cnt = 5;
-    ParamBlockRec params;
-    sqlite3Randomness(sizeof(lk), &lk);
-    lk = (lk & 0x7fffffff)%N_LOCKBYTE + 1;
-    memset(&params, 0, sizeof(params));
-    params.ioParam.ioRefNum = id->refNumRF;
-    params.ioParam.ioPosMode = fsFromStart;
-    params.ioParam.ioPosOffset = FIRST_LOCKBYTE;
-    params.ioParam.ioReqCount = 1;
-    while( cnt-->0 && (res = PBLockRangeSync(&params))!=noErr ){
-      UInt32 finalTicks;
-      Delay(1, &finalTicks); /* 1/60 sec */
-    }
-    if( res == noErr ){
-      params.ioParam.ioPosOffset = FIRST_LOCKBYTE+1;
-      params.ioParam.ioReqCount = N_LOCKBYTE;
-      PBUnlockRangeSync(&params);
-      params.ioParam.ioPosOffset = FIRST_LOCKBYTE+lk;
-      params.ioParam.ioReqCount = 1;
-      res = PBLockRangeSync(&params);
-      params.ioParam.ioPosOffset = FIRST_LOCKBYTE;
-      params.ioParam.ioReqCount = 1;
-      PBUnlockRangeSync(&params);
-    }
-    if( res == noErr ){
-      id->locked = lk;
-      rc = SQLITE_OK;
-    }else{
-      rc = SQLITE_BUSY;
-    }
-  }
-  return rc;
-#endif
-}
-
-/*
-** Change the lock status to be an exclusive or write lock.  Return
-** SQLITE_OK on success and SQLITE_BUSY on a failure.  If this
-** library was compiled with large file support (LFS) but LFS is not
-** available on the host, then an SQLITE_NOLFS is returned.
-*/
-int sqlite3OsWriteLock(OsFile *id){
-#if OS_UNIX
-  int rc;
-  sqlite3OsEnterMutex();
-  if( id->pLock->cnt==0 || (id->pLock->cnt==1 && id->locked==1) ){
-    struct flock lock;
-    int s;
-    lock.l_type = F_WRLCK;
-    lock.l_whence = SEEK_SET;
-    lock.l_start = lock.l_len = 0L;
-    s = fcntl(id->fd, F_SETLK, &lock);
-    if( s!=0 ){
-      rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
-    }else{
-      rc = SQLITE_OK;
-      if( !id->locked ){
-        id->pOpen->nLock++;
-        id->locked = 1;
-      }
-      id->pLock->cnt = -1;
-    }
-  }else{
-    rc = SQLITE_BUSY;
-  }
-  sqlite3OsLeaveMutex();
-  return rc;
-#endif
-#if OS_WIN
-  int rc;
-  if( id->locked<0 ){
-    rc = SQLITE_OK;
-  }else{
-    int res;
-    int cnt = 100;
-    while( cnt-->0 && (res = LockFile(id->h, FIRST_LOCKBYTE, 0, 1, 0))==0 ){
-      Sleep(1);
-    }
-    if( res ){
-      if( id->locked>0 ){
-        if( isNT() ){
-          UnlockFile(id->h, FIRST_LOCKBYTE+1, 0, N_LOCKBYTE, 0);
-        }else{
-          res = UnlockFile(id->h, FIRST_LOCKBYTE + id->locked, 0, 1, 0);
-        }
-      }
-      if( res ){
-        res = LockFile(id->h, FIRST_LOCKBYTE+1, 0, N_LOCKBYTE, 0);
-      }else{
-        res = 0;
-      }
-      UnlockFile(id->h, FIRST_LOCKBYTE, 0, 1, 0);
-    }
-    if( res ){
-      id->locked = -1;
-      rc = SQLITE_OK;
-    }else{
-      rc = SQLITE_BUSY;
-    }
-  }
-  return rc;
-#endif
-#if OS_MAC
-  int rc;
-  if( id->locked<0 || id->refNumRF == -1 ){
-    rc = SQLITE_OK;
-  }else{
-    OSErr res;
-    int cnt = 5;
-    ParamBlockRec params;
-    memset(&params, 0, sizeof(params));
-    params.ioParam.ioRefNum = id->refNumRF;
-    params.ioParam.ioPosMode = fsFromStart;
-    params.ioParam.ioPosOffset = FIRST_LOCKBYTE;
-    params.ioParam.ioReqCount = 1;
-    while( cnt-->0 && (res = PBLockRangeSync(&params))!=noErr ){
-      UInt32 finalTicks;
-      Delay(1, &finalTicks); /* 1/60 sec */
-    }
-    if( res == noErr ){
-      params.ioParam.ioPosOffset = FIRST_LOCKBYTE + id->locked;
-      params.ioParam.ioReqCount = 1;
-      if( id->locked==0 
-            || PBUnlockRangeSync(&params)==noErr ){
-        params.ioParam.ioPosOffset = FIRST_LOCKBYTE+1;
-        params.ioParam.ioReqCount = N_LOCKBYTE;
-        res = PBLockRangeSync(&params);
-      }else{
-        res = afpRangeNotLocked;
-      }
-      params.ioParam.ioPosOffset = FIRST_LOCKBYTE;
-      params.ioParam.ioReqCount = 1;
-      PBUnlockRangeSync(&params);
-    }
-    if( res == noErr ){
-      id->locked = -1;
-      rc = SQLITE_OK;
-    }else{
-      rc = SQLITE_BUSY;
-    }
-  }
-  return rc;
-#endif
-}
-
-/*
-** Unlock the given file descriptor.  If the file descriptor was
-** not previously locked, then this routine is a no-op.  If this
-** library was compiled with large file support (LFS) but LFS is not
-** available on the host, then an SQLITE_NOLFS is returned.
-*/
-int sqlite3OsUnlock(OsFile *id){
-#if OS_UNIX
-  int rc;
-  if( !id->locked ) return SQLITE_OK;
-  sqlite3OsEnterMutex();
-  assert( id->pLock->cnt!=0 );
-  if( id->pLock->cnt>1 ){
-    id->pLock->cnt--;
-    rc = SQLITE_OK;
-  }else{
-    struct flock lock;
-    int s;
-    lock.l_type = F_UNLCK;
-    lock.l_whence = SEEK_SET;
-    lock.l_start = lock.l_len = 0L;
-    s = fcntl(id->fd, F_SETLK, &lock);
-    if( s!=0 ){
-      rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
-    }else{
-      rc = SQLITE_OK;
-      id->pLock->cnt = 0;
-    }
-  }
-  if( rc==SQLITE_OK ){
-    /* Decrement the count of locks against this same file.  When the
-    ** count reaches zero, close any other file descriptors whose close
-    ** was deferred because of outstanding locks.
-    */
-    struct openCnt *pOpen = id->pOpen;
-    pOpen->nLock--;
-    assert( pOpen->nLock>=0 );
-    if( pOpen->nLock==0 && pOpen->nPending>0 ){
-      int i;
-      for(i=0; i<pOpen->nPending; i++){
-        close(pOpen->aPending[i]);
-      }
-      sqliteFree(pOpen->aPending);
-      pOpen->nPending = 0;
-      pOpen->aPending = 0;
-    }
-  }
-  sqlite3OsLeaveMutex();
-  id->locked = 0;
-  return rc;
-#endif
-#if OS_WIN
-  int rc;
-  if( id->locked==0 ){
-    rc = SQLITE_OK;
-  }else if( isNT() || id->locked<0 ){
-    UnlockFile(id->h, FIRST_LOCKBYTE+1, 0, N_LOCKBYTE, 0);
-    rc = SQLITE_OK;
-    id->locked = 0;
-  }else{
-    UnlockFile(id->h, FIRST_LOCKBYTE+id->locked, 0, 1, 0);
-    rc = SQLITE_OK;
-    id->locked = 0;
-  }
-  return rc;
-#endif
-#if OS_MAC
-  int rc;
-  ParamBlockRec params;
-  memset(&params, 0, sizeof(params));
-  params.ioParam.ioRefNum = id->refNumRF;
-  params.ioParam.ioPosMode = fsFromStart;
-  if( id->locked==0 || id->refNumRF == -1 ){
-    rc = SQLITE_OK;
-  }else if( id->locked<0 ){
-    params.ioParam.ioPosOffset = FIRST_LOCKBYTE+1;
-    params.ioParam.ioReqCount = N_LOCKBYTE;
-    PBUnlockRangeSync(&params);
-    rc = SQLITE_OK;
-    id->locked = 0;
-  }else{
-    params.ioParam.ioPosOffset = FIRST_LOCKBYTE+id->locked;
-    params.ioParam.ioReqCount = 1;
-    PBUnlockRangeSync(&params);
-    rc = SQLITE_OK;
-    id->locked = 0;
-  }
-  return rc;
-#endif
-}
-
-/*
-** Get information to seed the random number generator.  The seed
-** is written into the buffer zBuf[256].  The calling function must
-** supply a sufficiently large buffer.
-*/
-int sqlite3OsRandomSeed(char *zBuf){
-  /* 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, 256);
-#if OS_UNIX && !defined(SQLITE_TEST)
-  {
-    int pid;
-    time((time_t*)zBuf);
-    pid = getpid();
-    memcpy(&zBuf[sizeof(time_t)], &pid, sizeof(pid));
-  }
-#endif
-#if OS_WIN && !defined(SQLITE_TEST)
-  GetSystemTime((LPSYSTEMTIME)zBuf);
-#endif
-#if OS_MAC
-  {
-    int pid;
-    Microseconds((UnsignedWide*)zBuf);
-    pid = getpid();
-    memcpy(&zBuf[sizeof(UnsignedWide)], &pid, sizeof(pid));
-  }
-#endif
-  return SQLITE_OK;
-}
-
-/*
-** Sleep for a little while.  Return the amount of time slept.
-*/
-int sqlite3OsSleep(int ms){
-#if OS_UNIX
-#if defined(HAVE_USLEEP) && HAVE_USLEEP
-  usleep(ms*1000);
-  return ms;
-#else
-  sleep((ms+999)/1000);
-  return 1000*((ms+999)/1000);
-#endif
-#endif
-#if OS_WIN
-  Sleep(ms);
-  return ms;
-#endif
-#if OS_MAC
-  UInt32 finalTicks;
-  UInt32 ticks = (((UInt32)ms+16)*3)/50;  /* 1/60 sec per tick */
-  Delay(ticks, &finalTicks);
-  return (int)((ticks*50)/3);
-#endif
-}
-
-/*
-** Static variables used for thread synchronization
-*/
-static int inMutex = 0;
-#ifdef SQLITE_UNIX_THREADS
-  static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-#endif
-#ifdef SQLITE_W32_THREADS
-  static CRITICAL_SECTION cs;
-#endif
-#ifdef SQLITE_MACOS_MULTITASKING
-  static MPCriticalRegionID criticalRegion;
-#endif
-
-/*
-** The following pair of routine implement mutual exclusion for
-** multi-threaded processes.  Only a single thread is allowed to
-** executed code that is surrounded by EnterMutex() and LeaveMutex().
-**
-** SQLite uses only a single Mutex.  There is not much critical
-** code and what little there is executes quickly and without blocking.
-*/
-void sqlite3OsEnterMutex(){
-#ifdef SQLITE_UNIX_THREADS
-  pthread_mutex_lock(&mutex);
-#endif
-#ifdef SQLITE_W32_THREADS
-  static int isInit = 0;
-  while( !isInit ){
-    static long lock = 0;
-    if( InterlockedIncrement(&lock)==1 ){
-      InitializeCriticalSection(&cs);
-      isInit = 1;
-    }else{
-      Sleep(1);
-    }
-  }
-  EnterCriticalSection(&cs);
-#endif
-#ifdef SQLITE_MACOS_MULTITASKING
-  static volatile int notInit = 1;
-  if( notInit ){
-    if( notInit == 2 ) /* as close as you can get to thread safe init */
-      MPYield();
-    else{
-      notInit = 2;
-      MPCreateCriticalRegion(&criticalRegion);
-      notInit = 0;
-    }
-  }
-  MPEnterCriticalRegion(criticalRegion, kDurationForever);
-#endif
-  assert( !inMutex );
-  inMutex = 1;
-}
-void sqlite3OsLeaveMutex(){
-  assert( inMutex );
-  inMutex = 0;
-#ifdef SQLITE_UNIX_THREADS
-  pthread_mutex_unlock(&mutex);
-#endif
-#ifdef SQLITE_W32_THREADS
-  LeaveCriticalSection(&cs);
-#endif
-#ifdef SQLITE_MACOS_MULTITASKING
-  MPExitCriticalRegion(criticalRegion);
-#endif
-}
-
-/*
-** Turn a relative pathname into a full pathname.  Return a pointer
-** to the full pathname stored in space obtained from sqliteMalloc().
-** The calling function is responsible for freeing this space once it
-** is no longer needed.
-*/
-char *sqlite3OsFullPathname(const char *zRelative){
-#if OS_UNIX
-  char *zFull = 0;
-  if( zRelative[0]=='/' ){
-    sqlite3SetString(&zFull, zRelative, (char*)0);
-  }else{
-    char zBuf[5000];
-    sqlite3SetString(&zFull, getcwd(zBuf, sizeof(zBuf)), "/", zRelative,
-                    (char*)0);
-  }
-  return zFull;
-#endif
-#if OS_WIN
-  char *zNotUsed;
-  char *zFull;
-  int nByte;
-  nByte = GetFullPathName(zRelative, 0, 0, &zNotUsed) + 1;
-  zFull = sqliteMalloc( nByte );
-  if( zFull==0 ) return 0;
-  GetFullPathName(zRelative, nByte, zFull, &zNotUsed);
-  return zFull;
-#endif
-#if OS_MAC
-  char *zFull = 0;
-  if( zRelative[0]==':' ){
-    char zBuf[_MAX_PATH+1];
-    sqlite3SetString(&zFull, getcwd(zBuf, sizeof(zBuf)), &(zRelative[1]),
-                    (char*)0);
-  }else{
-    if( strchr(zRelative, ':') ){
-      sqlite3SetString(&zFull, zRelative, (char*)0);
-    }else{
-    char zBuf[_MAX_PATH+1];
-      sqlite3SetString(&zFull, getcwd(zBuf, sizeof(zBuf)), zRelative, (char*)0);
-    }
-  }
-  return zFull;
-#endif
-}
-
-/*
-** The following variable, if set to a non-zero value, becomes the result
-** returned from sqlite3OsCurrentTime().  This is used for testing.
-*/
-#ifdef SQLITE_TEST
-int sqlite3_current_time = 0;
-#endif
-
-/*
-** 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.
-*/
-int sqlite3OsCurrentTime(double *prNow){
-#if OS_UNIX
-  time_t t;
-  time(&t);
-  *prNow = t/86400.0 + 2440587.5;
-#endif
-#if OS_WIN
-  FILETIME ft;
-  /* FILETIME structure is a 64-bit value representing the number of 
-     100-nanosecond intervals since January 1, 1601 (= JD 2305813.5). 
-  */
-  double now;
-  GetSystemTimeAsFileTime( &ft );
-  now = ((double)ft.dwHighDateTime) * 4294967296.0; 
-  *prNow = (now + ft.dwLowDateTime)/864000000000.0 + 2305813.5;
-#endif
-#ifdef SQLITE_TEST
-  if( sqlite3_current_time ){
-    *prNow = sqlite3_current_time/86400.0 + 2440587.5;
-  }
-#endif
-  return 0;
-}
-
-
-
diff --git a/src/os.h b/src/os.h
index a88756f..93fa535 100644
--- a/src/os.h
+++ b/src/os.h
@@ -18,47 +18,6 @@
 #define _SQLITE_OS_H_
 
 /*
-** Helpful hint:  To get this to compile on HP/UX, add -D_INCLUDE_POSIX_SOURCE
-** to the compiler command line.
-*/
-
-/*
-** These #defines should enable >2GB file support on Posix if the
-** underlying operating system supports it.  If the OS lacks
-** large file support, or if the OS is windows, these should be no-ops.
-**
-** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch
-** on the compiler command line.  This is necessary if you are compiling
-** on a recent machine (ex: RedHat 7.2) but you want your code to work
-** on an older machine (ex: RedHat 6.0).  If you compile on RedHat 7.2
-** without this option, LFS is enable.  But LFS does not exist in the kernel
-** in RedHat 6.0, so the code won't work.  Hence, for maximum binary
-** portability you should omit LFS.
-**
-** Similar is true for MacOS.  LFS is only supported on MacOS 9 and later.
-*/
-#ifndef SQLITE_DISABLE_LFS
-# define _LARGE_FILE       1
-# ifndef _FILE_OFFSET_BITS
-#   define _FILE_OFFSET_BITS 64
-# endif
-# define _LARGEFILE_SOURCE 1
-#endif
-
-/*
-** Temporary files are named starting with this prefix followed by 16 random
-** alphanumeric characters, and no file extension. They are stored in the
-** OS's standard temporary file directory, and are deleted prior to exit.
-** If sqlite is being embedded in another program, you may wish to change the
-** prefix to reflect your program's name, so that if your program exits
-** prematurely, old temporary files can be easily identified. This can be done
-** using -DTEMP_FILE_PREFIX=myprefix_ on the compiler command line.
-*/
-#ifndef TEMP_FILE_PREFIX
-# define TEMP_FILE_PREFIX "sqlite_"
-#endif
-
-/*
 ** Figure out if we are dealing with Unix, Windows or MacOS.
 **
 ** N.B. MacOS means Mac Classic (or Carbon). Treat Darwin (OS X) as Unix.
@@ -96,78 +55,31 @@
 #endif
 
 /*
-** A handle for an open file is stored in an OsFile object.
+** Invoke the appropriate operating-system specific header file.
 */
 #if OS_UNIX
-# include <sys/types.h>
-# include <sys/stat.h>
-# include <fcntl.h>
-# include <unistd.h>
-  typedef struct OsFile OsFile;
-  struct OsFile {
-    struct openCnt *pOpen;    /* Info about all open fd's on this inode */
-    struct lockInfo *pLock;   /* Info about locks on this inode */
-    int fd;                   /* The file descriptor */
-    int locked;               /* True if this instance holds the lock */
-    int dirfd;                /* File descriptor for the directory */
-  };
-# define SQLITE_TEMPNAME_SIZE 200
-# if defined(HAVE_USLEEP) && HAVE_USLEEP
-#  define SQLITE_MIN_SLEEP_MS 1
-# else
-#  define SQLITE_MIN_SLEEP_MS 1000
-# endif
+# include "os_unix.h"
 #endif
-
 #if OS_WIN
-#include <windows.h>
-#include <winbase.h>
-  typedef struct OsFile OsFile;
-  struct OsFile {
-    HANDLE h;               /* Handle for accessing the file */
-    int locked;             /* 0: unlocked, <0: write lock, >0: read lock */
-  };
-# if defined(_MSC_VER) || defined(__BORLANDC__)
-    typedef __int64 off_t;
-# else
-#  if !defined(_CYGWIN_TYPES_H)
-     typedef long long off_t;
-#    if defined(__MINGW32__)
-#      define	_OFF_T_
-#    endif
-#  endif
-# endif
-# define SQLITE_TEMPNAME_SIZE (MAX_PATH+50)
-# define SQLITE_MIN_SLEEP_MS 1
+# include "os_win.h"
 #endif
-
 #if OS_MAC
-# include <unistd.h>
-# include <Files.h>
-  typedef struct OsFile OsFile;
-  struct OsFile {
-    SInt16 refNum;           /* Data fork/file reference number */
-    SInt16 refNumRF;         /* Resource fork reference number (for locking) */
-    int locked;              /* 0: unlocked, <0: write lock, >0: read lock */
-    int delOnClose;          /* True if file is to be deleted on close */
-    char *pathToDel;         /* Name of file to delete on close */
-  };
-# ifdef _LARGE_FILE
-    typedef SInt64 off_t;
-# else
-    typedef SInt32 off_t;
-# endif
-# define SQLITE_TEMPNAME_SIZE _MAX_PATH
-# define SQLITE_MIN_SLEEP_MS 17
+# include "os_mac.h"
 #endif
 
 /*
-** Macros to determine whether the machine is big or little endian,
-** evaluated at runtime.
+** Temporary files are named starting with this prefix followed by 16 random
+** alphanumeric characters, and no file extension. They are stored in the
+** OS's standard temporary file directory, and are deleted prior to exit.
+** If sqlite is being embedded in another program, you may wish to change the
+** prefix to reflect your program's name, so that if your program exits
+** prematurely, old temporary files can be easily identified. This can be done
+** using -DTEMP_FILE_PREFIX=myprefix_ on the compiler command line.
 */
-static const int sqlite3_one = 1;
-#define SQLITE3_BIGENDIAN (*(char *)(&sqlite3_one)==0)
-#define SQLITE3_LITTLEENDIAN (*(char *)(&sqlite3_one)==1)
+#ifndef TEMP_FILE_PREFIX
+# define TEMP_FILE_PREFIX "sqlite_"
+#endif
+
 
 int sqlite3OsDelete(const char*);
 int sqlite3OsFileExists(const char*);
@@ -194,9 +106,4 @@
 void sqlite3OsLeaveMutex(void);
 char *sqlite3OsFullPathname(const char*);
 
-
-
 #endif /* _SQLITE_OS_H_ */
-
-
-
diff --git a/src/os_common.h b/src/os_common.h
new file mode 100644
index 0000000..70d0dd9
--- /dev/null
+++ b/src/os_common.h
@@ -0,0 +1,82 @@
+/*
+** 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 macros and a little bit of code that is common to
+** all of the platform-specific files (os_*.c) and is #included into those
+** files.
+**
+** This file should be #included by the os_*.c files only.  It is not a
+** general purpose header file.
+*/
+
+
+/*
+** Macros for performance tracing.  Normally turned off.  Only works
+** on i486 hardware.
+*/
+#if 0
+static int last_page = 0;
+__inline__ unsigned long long int hwtime(void){
+  unsigned long long int x;
+  __asm__("rdtsc\n\t"
+          "mov %%edx, %%ecx\n\t"
+          :"=A" (x));
+  return x;
+}
+static unsigned long long int g_start;
+static unsigned int elapse;
+#define TIMER_START       g_start=hwtime()
+#define TIMER_END         elapse=hwtime()-g_start
+#define SEEK(X)           last_page=(X)
+#define TRACE1(X)         fprintf(stderr,X)
+#define TRACE2(X,Y)       fprintf(stderr,X,Y)
+#define TRACE3(X,Y,Z)     fprintf(stderr,X,Y,Z)
+#define TRACE4(X,Y,Z,A)   fprintf(stderr,X,Y,Z,A)
+#define TRACE5(X,Y,Z,A,B) fprintf(stderr,X,Y,Z,A,B)
+#else
+#define TIMER_START
+#define TIMER_END
+#define SEEK(X)
+#define TRACE1(X)
+#define TRACE2(X,Y)
+#define TRACE3(X,Y,Z)
+#define TRACE4(X,Y,Z,A)
+#define TRACE5(X,Y,Z,A,B)
+#endif
+
+
+/*
+** If we compile with the SQLITE_TEST macro set, then the following block
+** of code will give us the ability to simulate a disk I/O error.  This
+** is used for testing the I/O recovery logic.
+*/
+#ifdef SQLITE_TEST
+int sqlite3_io_error_pending = 0;
+#define SimulateIOError(A)  \
+   if( sqlite3_io_error_pending ) \
+     if( sqlite3_io_error_pending-- == 1 ){ local_ioerr(); return A; }
+static void local_ioerr(){
+  sqlite3_io_error_pending = 0;  /* Really just a place to set a breakpoint */
+}
+#else
+#define SimulateIOError(A)
+#endif
+
+/*
+** When testing, keep a count of the number of open files.
+*/
+#ifdef SQLITE_TEST
+int sqlite3_open_file_count = 0;
+#define OpenCounter(X)  sqlite3_open_file_count+=(X)
+#else
+#define OpenCounter(X)
+#endif
diff --git a/src/os_mac.c b/src/os_mac.c
new file mode 100644
index 0000000..cd88d56
--- /dev/null
+++ b/src/os_mac.c
@@ -0,0 +1,729 @@
+/*
+** 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 classic mac.  Mac OS X
+** uses the os_unix.c file, not this one.
+*/
+#include "os.h"          /* Must be first to enable large file support */
+#if OS_MAC               /* This file used on classic mac only */
+#include "sqliteInt.h"
+
+#include <extras.h>
+#include <path2fss.h>
+#include <TextUtils.h>
+#include <FinderRegistry.h>
+#include <Folders.h>
+#include <Timer.h>
+#include <OSUtils.h>
+
+/*
+** Macros used to determine whether or not to use threads.
+*/
+#if defined(THREADSAFE) && THREADSAFE
+# include <Multiprocessing.h>
+# define SQLITE_MACOS_MULTITASKING 1
+#endif
+
+/*
+** Include code that is common to all os_*.c files
+*/
+#include "os_common.h"
+
+/*
+** Delete the named file
+*/
+int sqlite3OsDelete(const char *zFilename){
+  unlink(zFilename);
+  return SQLITE_OK;
+}
+
+/*
+** Return TRUE if the named file exists.
+*/
+int sqlite3OsFileExists(const char *zFilename){
+  return access(zFilename, 0)==0;
+}
+
+/*
+** 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 sqlite3OsOpenReadWrite(
+  const char *zFilename,
+  OsFile *id,
+  int *pReadonly
+){
+  FSSpec fsSpec;
+# ifdef _LARGE_FILE
+  HFSUniStr255 dfName;
+  FSRef fsRef;
+  if( __path2fss(zFilename, &fsSpec) != noErr ){
+    if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr )
+      return SQLITE_CANTOPEN;
+  }
+  if( FSpMakeFSRef(&fsSpec, &fsRef) != noErr )
+    return SQLITE_CANTOPEN;
+  FSGetDataForkName(&dfName);
+  if( FSOpenFork(&fsRef, dfName.length, dfName.unicode,
+                 fsRdWrShPerm, &(id->refNum)) != noErr ){
+    if( FSOpenFork(&fsRef, dfName.length, dfName.unicode,
+                   fsRdWrPerm, &(id->refNum)) != noErr ){
+      if (FSOpenFork(&fsRef, dfName.length, dfName.unicode,
+                   fsRdPerm, &(id->refNum)) != noErr )
+        return SQLITE_CANTOPEN;
+      else
+        *pReadonly = 1;
+    } else
+      *pReadonly = 0;
+  } else
+    *pReadonly = 0;
+# else
+  __path2fss(zFilename, &fsSpec);
+  if( !sqlite3OsFileExists(zFilename) ){
+    if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr )
+      return SQLITE_CANTOPEN;
+  }
+  if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrShPerm, &(id->refNum)) != noErr ){
+    if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrPerm, &(id->refNum)) != noErr ){
+      if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdPerm, &(id->refNum)) != noErr )
+        return SQLITE_CANTOPEN;
+      else
+        *pReadonly = 1;
+    } else
+      *pReadonly = 0;
+  } else
+    *pReadonly = 0;
+# endif
+  if( HOpenRF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrShPerm, &(id->refNumRF)) != noErr){
+    id->refNumRF = -1;
+  }
+  id->locked = 0;
+  id->delOnClose = 0;
+  OpenCounter(+1);
+  return SQLITE_OK;
+}
+
+
+/*
+** 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 sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
+  FSSpec fsSpec;
+# ifdef _LARGE_FILE
+  HFSUniStr255 dfName;
+  FSRef fsRef;
+  __path2fss(zFilename, &fsSpec);
+  if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr )
+    return SQLITE_CANTOPEN;
+  if( FSpMakeFSRef(&fsSpec, &fsRef) != noErr )
+    return SQLITE_CANTOPEN;
+  FSGetDataForkName(&dfName);
+  if( FSOpenFork(&fsRef, dfName.length, dfName.unicode,
+                 fsRdWrPerm, &(id->refNum)) != noErr )
+    return SQLITE_CANTOPEN;
+# else
+  __path2fss(zFilename, &fsSpec);
+  if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr )
+    return SQLITE_CANTOPEN;
+  if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrPerm, &(id->refNum)) != noErr )
+    return SQLITE_CANTOPEN;
+# endif
+  id->refNumRF = -1;
+  id->locked = 0;
+  id->delOnClose = delFlag;
+  if (delFlag)
+    id->pathToDel = sqlite3OsFullPathname(zFilename);
+  OpenCounter(+1);
+  return SQLITE_OK;
+}
+
+/*
+** 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 sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
+  FSSpec fsSpec;
+# ifdef _LARGE_FILE
+  HFSUniStr255 dfName;
+  FSRef fsRef;
+  if( __path2fss(zFilename, &fsSpec) != noErr )
+    return SQLITE_CANTOPEN;
+  if( FSpMakeFSRef(&fsSpec, &fsRef) != noErr )
+    return SQLITE_CANTOPEN;
+  FSGetDataForkName(&dfName);
+  if( FSOpenFork(&fsRef, dfName.length, dfName.unicode,
+                 fsRdPerm, &(id->refNum)) != noErr )
+    return SQLITE_CANTOPEN;
+# else
+  __path2fss(zFilename, &fsSpec);
+  if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdPerm, &(id->refNum)) != noErr )
+    return SQLITE_CANTOPEN;
+# endif
+  if( HOpenRF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrShPerm, &(id->refNumRF)) != noErr){
+    id->refNumRF = -1;
+  }
+  id->locked = 0;
+  id->delOnClose = 0;
+  OpenCounter(+1);
+  return SQLITE_OK;
+}
+
+/*
+** 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.
+*/
+int sqlite3OsOpenDirectory(
+  const char *zDirname,
+  OsFile *id
+){
+  return SQLITE_OK;
+}
+
+/*
+** Create a temporary file name in zBuf.  zBuf must be big enough to
+** hold at least SQLITE_TEMPNAME_SIZE characters.
+*/
+int sqlite3OsTempFileName(char *zBuf){
+  static char zChars[] =
+    "abcdefghijklmnopqrstuvwxyz"
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+    "0123456789";
+  int i, j;
+  char zTempPath[SQLITE_TEMPNAME_SIZE];
+  char zdirName[32];
+  CInfoPBRec infoRec;
+  Str31 dirName;
+  memset(&infoRec, 0, sizeof(infoRec));
+  memset(zTempPath, 0, SQLITE_TEMPNAME_SIZE);
+  if( FindFolder(kOnSystemDisk, kTemporaryFolderType,  kCreateFolder,
+       &(infoRec.dirInfo.ioVRefNum), &(infoRec.dirInfo.ioDrParID)) == noErr ){
+    infoRec.dirInfo.ioNamePtr = dirName;
+    do{
+      infoRec.dirInfo.ioFDirIndex = -1;
+      infoRec.dirInfo.ioDrDirID = infoRec.dirInfo.ioDrParID;
+      if( PBGetCatInfoSync(&infoRec) == noErr ){
+        CopyPascalStringToC(dirName, zdirName);
+        i = strlen(zdirName);
+        memmove(&(zTempPath[i+1]), zTempPath, strlen(zTempPath));
+        strcpy(zTempPath, zdirName);
+        zTempPath[i] = ':';
+      }else{
+        *zTempPath = 0;
+        break;
+      }
+    } while( infoRec.dirInfo.ioDrDirID != fsRtDirID );
+  }
+  if( *zTempPath == 0 )
+    getcwd(zTempPath, SQLITE_TEMPNAME_SIZE-24);
+  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;
+  }
+  return SQLITE_OK; 
+}
+
+/*
+** Close a file.
+*/
+int sqlite3OsClose(OsFile *id){
+  if( id->refNumRF!=-1 )
+    FSClose(id->refNumRF);
+# ifdef _LARGE_FILE
+  FSCloseFork(id->refNum);
+# else
+  FSClose(id->refNum);
+# endif
+  if( id->delOnClose ){
+    unlink(id->pathToDel);
+    sqliteFree(id->pathToDel);
+  }
+  OpenCounter(-1);
+  return SQLITE_OK;
+}
+
+/*
+** 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 sqlite3OsRead(OsFile *id, void *pBuf, int amt){
+  int got;
+  SimulateIOError(SQLITE_IOERR);
+  TRACE2("READ %d\n", last_page);
+# ifdef _LARGE_FILE
+  FSReadFork(id->refNum, fsAtMark, 0, (ByteCount)amt, pBuf, (ByteCount*)&got);
+# else
+  got = amt;
+  FSRead(id->refNum, &got, pBuf);
+# endif
+  if( got==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.
+*/
+int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
+  OSErr oserr;
+  int wrote = 0;
+  SimulateIOError(SQLITE_IOERR);
+  TRACE2("WRITE %d\n", last_page);
+  while( amt>0 ){
+# ifdef _LARGE_FILE
+    oserr = FSWriteFork(id->refNum, fsAtMark, 0,
+                        (ByteCount)amt, pBuf, (ByteCount*)&wrote);
+# else
+    wrote = amt;
+    oserr = FSWrite(id->refNum, &wrote, pBuf);
+# endif
+    if( wrote == 0 || oserr != noErr)
+      break;
+    amt -= wrote;
+    pBuf = &((char*)pBuf)[wrote];
+  }
+  if( oserr != noErr || amt>wrote ){
+    return SQLITE_FULL;
+  }
+  return SQLITE_OK;
+}
+
+/*
+** Move the read/write pointer in a file.
+*/
+int sqlite3OsSeek(OsFile *id, off_t offset){
+  off_t curSize;
+  SEEK(offset/1024 + 1);
+  if( sqlite3OsFileSize(id, &curSize) != SQLITE_OK ){
+    return SQLITE_IOERR;
+  }
+  if( offset >= curSize ){
+    if( sqlite3OsTruncate(id, offset+1) != SQLITE_OK ){
+      return SQLITE_IOERR;
+    }
+  }
+# ifdef _LARGE_FILE
+  if( FSSetForkPosition(id->refNum, fsFromStart, offset) != noErr ){
+# else
+  if( SetFPos(id->refNum, fsFromStart, offset) != noErr ){
+# endif
+    return SQLITE_IOERR;
+  }else{
+    return SQLITE_OK;
+  }
+}
+
+/*
+** Make sure all writes to a particular file are committed to disk.
+**
+** Under Unix, 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.
+*/
+int sqlite3OsSync(OsFile *id){
+# ifdef _LARGE_FILE
+  if( FSFlushFork(id->refNum) != noErr ){
+# else
+  ParamBlockRec params;
+  memset(&params, 0, sizeof(ParamBlockRec));
+  params.ioParam.ioRefNum = id->refNum;
+  if( PBFlushFileSync(&params) != noErr ){
+# endif
+    return SQLITE_IOERR;
+  }else{
+    return SQLITE_OK;
+  }
+}
+
+/*
+** Truncate an open file to a specified size
+*/
+int sqlite3OsTruncate(OsFile *id, off_t nByte){
+  SimulateIOError(SQLITE_IOERR);
+# ifdef _LARGE_FILE
+  if( FSSetForkSize(id->refNum, fsFromStart, nByte) != noErr){
+# else
+  if( SetEOF(id->refNum, nByte) != noErr ){
+# endif
+    return SQLITE_IOERR;
+  }else{
+    return SQLITE_OK;
+  }
+}
+
+/*
+** Determine the current size of a file in bytes
+*/
+int sqlite3OsFileSize(OsFile *id, off_t *pSize){
+# ifdef _LARGE_FILE
+  if( FSGetForkSize(id->refNum, pSize) != noErr){
+# else
+  if( GetEOF(id->refNum, pSize) != noErr ){
+# endif
+    return SQLITE_IOERR;
+  }else{
+    return SQLITE_OK;
+  }
+}
+
+/*
+** Windows file locking notes:  [similar issues apply to MacOS]
+**
+** We cannot use LockFileEx() or UnlockFileEx() on Win95/98/ME because
+** those functions are not available.  So we use only LockFile() and
+** UnlockFile().
+**
+** LockFile() prevents not just writing but also reading by other processes.
+** (This is a design error on the part of Windows, but there is nothing
+** we can do about that.)  So the region used for locking is at the
+** end of the file where it is unlikely to ever interfere with an
+** actual read attempt.
+**
+** A database read lock is obtained by locking a single randomly-chosen 
+** byte out of a specific range of bytes. The lock byte is obtained at 
+** random so two separate readers can probably access the file at the 
+** same time, unless they are unlucky and choose the same lock byte.
+** A database write lock is obtained by locking all bytes in the range.
+** There can only be one writer.
+**
+** A lock is obtained on the first byte of the lock range before acquiring
+** either a read lock or a write lock.  This prevents two processes from
+** attempting to get a lock at a same time.  The semantics of 
+** sqlite3OsReadLock() require that if there is already a write lock, that
+** lock is converted into a read lock atomically.  The lock on the first
+** byte allows us to drop the old write lock and get the read lock without
+** another process jumping into the middle and messing us up.  The same
+** argument applies to sqlite3OsWriteLock().
+**
+** On WinNT/2K/XP systems, LockFileEx() and UnlockFileEx() are available,
+** which means we can use reader/writer locks.  When reader writer locks
+** are used, the lock is placed on the same range of bytes that is used
+** for probabilistic locking in Win95/98/ME.  Hence, the locking scheme
+** will support two or more Win95 readers or two or more WinNT readers.
+** But a single Win95 reader will lock out all WinNT readers and a single
+** WinNT reader will lock out all other Win95 readers.
+**
+** Note: On MacOS we use the resource fork for locking.
+**
+** The following #defines specify the range of bytes used for locking.
+** N_LOCKBYTE is the number of bytes available for doing the locking.
+** The first byte used to hold the lock while the lock is changing does
+** not count toward this number.  FIRST_LOCKBYTE is the address of
+** the first byte in the range of bytes used for locking.
+*/
+#define N_LOCKBYTE       10239
+#define FIRST_LOCKBYTE   (0x000fffff - N_LOCKBYTE)
+
+/*
+** Change the status of the lock on the file "id" to be a readlock.
+** If the file was write locked, then this reduces the lock to a read.
+** If the file was read locked, then this acquires a new read lock.
+**
+** Return SQLITE_OK on success and SQLITE_BUSY on failure.  If this
+** library was compiled with large file support (LFS) but LFS is not
+** available on the host, then an SQLITE_NOLFS is returned.
+*/
+int sqlite3OsReadLock(OsFile *id){
+  int rc;
+  if( id->locked>0 || id->refNumRF == -1 ){
+    rc = SQLITE_OK;
+  }else{
+    int lk;
+    OSErr res;
+    int cnt = 5;
+    ParamBlockRec params;
+    sqlite3Randomness(sizeof(lk), &lk);
+    lk = (lk & 0x7fffffff)%N_LOCKBYTE + 1;
+    memset(&params, 0, sizeof(params));
+    params.ioParam.ioRefNum = id->refNumRF;
+    params.ioParam.ioPosMode = fsFromStart;
+    params.ioParam.ioPosOffset = FIRST_LOCKBYTE;
+    params.ioParam.ioReqCount = 1;
+    while( cnt-->0 && (res = PBLockRangeSync(&params))!=noErr ){
+      UInt32 finalTicks;
+      Delay(1, &finalTicks); /* 1/60 sec */
+    }
+    if( res == noErr ){
+      params.ioParam.ioPosOffset = FIRST_LOCKBYTE+1;
+      params.ioParam.ioReqCount = N_LOCKBYTE;
+      PBUnlockRangeSync(&params);
+      params.ioParam.ioPosOffset = FIRST_LOCKBYTE+lk;
+      params.ioParam.ioReqCount = 1;
+      res = PBLockRangeSync(&params);
+      params.ioParam.ioPosOffset = FIRST_LOCKBYTE;
+      params.ioParam.ioReqCount = 1;
+      PBUnlockRangeSync(&params);
+    }
+    if( res == noErr ){
+      id->locked = lk;
+      rc = SQLITE_OK;
+    }else{
+      rc = SQLITE_BUSY;
+    }
+  }
+  return rc;
+}
+
+/*
+** Change the lock status to be an exclusive or write lock.  Return
+** SQLITE_OK on success and SQLITE_BUSY on a failure.  If this
+** library was compiled with large file support (LFS) but LFS is not
+** available on the host, then an SQLITE_NOLFS is returned.
+*/
+int sqlite3OsWriteLock(OsFile *id){
+  int rc;
+  if( id->locked<0 || id->refNumRF == -1 ){
+    rc = SQLITE_OK;
+  }else{
+    OSErr res;
+    int cnt = 5;
+    ParamBlockRec params;
+    memset(&params, 0, sizeof(params));
+    params.ioParam.ioRefNum = id->refNumRF;
+    params.ioParam.ioPosMode = fsFromStart;
+    params.ioParam.ioPosOffset = FIRST_LOCKBYTE;
+    params.ioParam.ioReqCount = 1;
+    while( cnt-->0 && (res = PBLockRangeSync(&params))!=noErr ){
+      UInt32 finalTicks;
+      Delay(1, &finalTicks); /* 1/60 sec */
+    }
+    if( res == noErr ){
+      params.ioParam.ioPosOffset = FIRST_LOCKBYTE + id->locked;
+      params.ioParam.ioReqCount = 1;
+      if( id->locked==0 
+            || PBUnlockRangeSync(&params)==noErr ){
+        params.ioParam.ioPosOffset = FIRST_LOCKBYTE+1;
+        params.ioParam.ioReqCount = N_LOCKBYTE;
+        res = PBLockRangeSync(&params);
+      }else{
+        res = afpRangeNotLocked;
+      }
+      params.ioParam.ioPosOffset = FIRST_LOCKBYTE;
+      params.ioParam.ioReqCount = 1;
+      PBUnlockRangeSync(&params);
+    }
+    if( res == noErr ){
+      id->locked = -1;
+      rc = SQLITE_OK;
+    }else{
+      rc = SQLITE_BUSY;
+    }
+  }
+  return rc;
+}
+
+/*
+** Unlock the given file descriptor.  If the file descriptor was
+** not previously locked, then this routine is a no-op.  If this
+** library was compiled with large file support (LFS) but LFS is not
+** available on the host, then an SQLITE_NOLFS is returned.
+*/
+int sqlite3OsUnlock(OsFile *id){
+  int rc;
+  ParamBlockRec params;
+  memset(&params, 0, sizeof(params));
+  params.ioParam.ioRefNum = id->refNumRF;
+  params.ioParam.ioPosMode = fsFromStart;
+  if( id->locked==0 || id->refNumRF == -1 ){
+    rc = SQLITE_OK;
+  }else if( id->locked<0 ){
+    params.ioParam.ioPosOffset = FIRST_LOCKBYTE+1;
+    params.ioParam.ioReqCount = N_LOCKBYTE;
+    PBUnlockRangeSync(&params);
+    rc = SQLITE_OK;
+    id->locked = 0;
+  }else{
+    params.ioParam.ioPosOffset = FIRST_LOCKBYTE+id->locked;
+    params.ioParam.ioReqCount = 1;
+    PBUnlockRangeSync(&params);
+    rc = SQLITE_OK;
+    id->locked = 0;
+  }
+  return rc;
+}
+
+/*
+** Get information to seed the random number generator.  The seed
+** is written into the buffer zBuf[256].  The calling function must
+** supply a sufficiently large buffer.
+*/
+int sqlite3OsRandomSeed(char *zBuf){
+  /* 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, 256);
+#if !defined(SQLITE_TEST)
+  {
+    int pid;
+    Microseconds((UnsignedWide*)zBuf);
+    pid = getpid();
+    memcpy(&zBuf[sizeof(UnsignedWide)], &pid, sizeof(pid));
+  }
+#endif
+  return SQLITE_OK;
+}
+
+/*
+** Sleep for a little while.  Return the amount of time slept.
+*/
+int sqlite3OsSleep(int ms){
+  UInt32 finalTicks;
+  UInt32 ticks = (((UInt32)ms+16)*3)/50;  /* 1/60 sec per tick */
+  Delay(ticks, &finalTicks);
+  return (int)((ticks*50)/3);
+}
+
+/*
+** Static variables used for thread synchronization
+*/
+static int inMutex = 0;
+#ifdef SQLITE_MACOS_MULTITASKING
+  static MPCriticalRegionID criticalRegion;
+#endif
+
+/*
+** The following pair of routine implement mutual exclusion for
+** multi-threaded processes.  Only a single thread is allowed to
+** executed code that is surrounded by EnterMutex() and LeaveMutex().
+**
+** SQLite uses only a single Mutex.  There is not much critical
+** code and what little there is executes quickly and without blocking.
+*/
+void sqlite3OsEnterMutex(){
+#ifdef SQLITE_MACOS_MULTITASKING
+  static volatile int notInit = 1;
+  if( notInit ){
+    if( notInit == 2 ) /* as close as you can get to thread safe init */
+      MPYield();
+    else{
+      notInit = 2;
+      MPCreateCriticalRegion(&criticalRegion);
+      notInit = 0;
+    }
+  }
+  MPEnterCriticalRegion(criticalRegion, kDurationForever);
+#endif
+  assert( !inMutex );
+  inMutex = 1;
+}
+void sqlite3OsLeaveMutex(){
+  assert( inMutex );
+  inMutex = 0;
+#ifdef SQLITE_MACOS_MULTITASKING
+  MPExitCriticalRegion(criticalRegion);
+#endif
+}
+
+/*
+** Turn a relative pathname into a full pathname.  Return a pointer
+** to the full pathname stored in space obtained from sqliteMalloc().
+** The calling function is responsible for freeing this space once it
+** is no longer needed.
+*/
+char *sqlite3OsFullPathname(const char *zRelative){
+  char *zFull = 0;
+  if( zRelative[0]==':' ){
+    char zBuf[_MAX_PATH+1];
+    sqlite3SetString(&zFull, getcwd(zBuf, sizeof(zBuf)), &(zRelative[1]),
+                    (char*)0);
+  }else{
+    if( strchr(zRelative, ':') ){
+      sqlite3SetString(&zFull, zRelative, (char*)0);
+    }else{
+    char zBuf[_MAX_PATH+1];
+      sqlite3SetString(&zFull, getcwd(zBuf, sizeof(zBuf)), zRelative, (char*)0);
+    }
+  }
+  return zFull;
+}
+
+/*
+** The following variable, if set to a non-zero value, becomes the result
+** returned from sqlite3OsCurrentTime().  This is used for testing.
+*/
+#ifdef SQLITE_TEST
+int sqlite3_current_time = 0;
+#endif
+
+/*
+** 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.
+*/
+int sqlite3OsCurrentTime(double *prNow){
+  *prNow = 0.0;   /**** FIX ME *****/
+#ifdef SQLITE_TEST
+  if( sqlite3_current_time ){
+    *prNow = sqlite3_current_time/86400.0 + 2440587.5;
+  }
+#endif
+  return 0;
+}
+
+#endif /* OS_MAC */
diff --git a/src/os_mac.h b/src/os_mac.h
new file mode 100644
index 0000000..a5f5138
--- /dev/null
+++ b/src/os_mac.h
@@ -0,0 +1,46 @@
+/*
+** 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 header file defines OS-specific features of classic Mac.
+** OS X uses the os_unix.h file, not this one.
+*/
+#ifndef _SQLITE_OS_MAC_H_
+#define _SQLITE_OS_MAC_H_
+
+
+#include <unistd.h>
+#include <Files.h>
+#ifdef _LARGE_FILE
+    typedef SInt64 off_t;
+#else
+    typedef SInt32 off_t;
+#endif
+#define SQLITE_TEMPNAME_SIZE _MAX_PATH
+#define SQLITE_MIN_SLEEP_MS 17
+
+/*
+** The OsFile structure is a operating-system independing representation
+** of an open file handle.  It is defined differently for each architecture.
+**
+** This is the definition for class Mac.
+*/
+typedef struct OsFile OsFile;
+struct OsFile {
+  SInt16 refNum;           /* Data fork/file reference number */
+  SInt16 refNumRF;         /* Resource fork reference number (for locking) */
+  int locked;              /* 0: unlocked, <0: write lock, >0: read lock */
+  int delOnClose;          /* True if file is to be deleted on close */
+  char *pathToDel;         /* Name of file to delete on close */
+};
+
+
+#endif /* _SQLITE_OS_MAC_H_ */
diff --git a/src/os_unix.c b/src/os_unix.c
new file mode 100644
index 0000000..e6c6f31
--- /dev/null
+++ b/src/os_unix.c
@@ -0,0 +1,882 @@
+/*
+** 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 Unix systems.
+*/
+#include "os.h"          /* Must be first to enable large file support */
+#if OS_UNIX              /* This file is used on unix only */
+#include "sqliteInt.h"
+
+
+#include <time.h>
+#include <errno.h>
+#include <unistd.h>
+#ifndef O_LARGEFILE
+# define O_LARGEFILE 0
+#endif
+#ifdef SQLITE_DISABLE_LFS
+# undef O_LARGEFILE
+# define O_LARGEFILE 0
+#endif
+#ifndef O_NOFOLLOW
+# define O_NOFOLLOW 0
+#endif
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif
+
+/*
+** The DJGPP compiler environment looks mostly like Unix, but it
+** lacks the fcntl() system call.  So redefine fcntl() to be something
+** that always succeeds.  This means that locking does not occur under
+** DJGPP.  But its DOS - what did you expect?
+*/
+#ifdef __DJGPP__
+# define fcntl(A,B,C) 0
+#endif
+
+/*
+** Macros used to determine whether or not to use threads.  The
+** SQLITE_UNIX_THREADS macro is defined if we are synchronizing for
+** Posix threads and SQLITE_W32_THREADS is defined if we are
+** synchronizing using Win32 threads.
+*/
+#if defined(THREADSAFE) && THREADSAFE
+# include <pthread.h>
+# define SQLITE_UNIX_THREADS 1
+#endif
+
+
+/*
+** Include code that is common to all os_*.c files
+*/
+#include "os_common.h"
+
+
+/*
+** Here is the dirt on POSIX advisory locks:  ANSI STD 1003.1 (1996)
+** section 6.5.2.2 lines 483 through 490 specify that when a process
+** sets or clears a lock, that operation overrides any prior locks set
+** by the same process.  It does not explicitly say so, but this implies
+** that it overrides locks set by the same process using a different
+** file descriptor.  Consider this test case:
+**
+**       int fd1 = open("./file1", O_RDWR|O_CREAT, 0644);
+**       int fd2 = open("./file2", O_RDWR|O_CREAT, 0644);
+**
+** Suppose ./file1 and ./file2 are really the same file (because
+** one is a hard or symbolic link to the other) then if you set
+** an exclusive lock on fd1, then try to get an exclusive lock
+** on fd2, it works.  I would have expected the second lock to
+** fail since there was already a lock on the file due to fd1.
+** But not so.  Since both locks came from the same process, the
+** second overrides the first, even though they were on different
+** file descriptors opened on different file names.
+**
+** Bummer.  If you ask me, this is broken.  Badly broken.  It means
+** that we cannot use POSIX locks to synchronize file access among
+** competing threads of the same process.  POSIX locks will work fine
+** to synchronize access for threads in separate processes, but not
+** threads within the same process.
+**
+** To work around the problem, SQLite has to manage file locks internally
+** on its own.  Whenever a new database is opened, we have to find the
+** specific inode of the database file (the inode is determined by the
+** st_dev and st_ino fields of the stat structure that fstat() fills in)
+** and check for locks already existing on that inode.  When locks are
+** created or removed, we have to look at our own internal record of the
+** locks to see if another thread has previously set a lock on that same
+** inode.
+**
+** The OsFile structure for POSIX is no longer just an integer file
+** descriptor.  It is now a structure that holds the integer file
+** descriptor and a pointer to a structure that describes the internal
+** locks on the corresponding inode.  There is one locking structure
+** per inode, so if the same inode is opened twice, both OsFile structures
+** point to the same locking structure.  The locking structure keeps
+** a reference count (so we will know when to delete it) and a "cnt"
+** field that tells us its internal lock status.  cnt==0 means the
+** file is unlocked.  cnt==-1 means the file has an exclusive lock.
+** cnt>0 means there are cnt shared locks on the file.
+**
+** Any attempt to lock or unlock a file first checks the locking
+** structure.  The fcntl() system call is only invoked to set a 
+** POSIX lock if the internal lock structure transitions between
+** a locked and an unlocked state.
+**
+** 2004-Jan-11:
+** More recent discoveries about POSIX advisory locks.  (The more
+** I discover, the more I realize the a POSIX advisory locks are
+** an abomination.)
+**
+** If you close a file descriptor that points to a file that has locks,
+** all locks on that file that are owned by the current process are
+** released.  To work around this problem, each OsFile structure contains
+** a pointer to an openCnt structure.  There is one openCnt structure
+** per open inode, which means that multiple OsFiles can point to a single
+** openCnt.  When an attempt is made to close an OsFile, if there are
+** other OsFiles open on the same inode that are holding locks, the call
+** to close() the file descriptor is deferred until all of the locks clear.
+** The openCnt structure keeps a list of file descriptors that need to
+** be closed and that list is walked (and cleared) when the last lock
+** clears.
+**
+** First, under Linux threads, because each thread has a separate
+** process ID, lock operations in one thread do not override locks
+** to the same file in other threads.  Linux threads behave like
+** separate processes in this respect.  But, if you close a file
+** descriptor in linux threads, all locks are cleared, even locks
+** on other threads and even though the other threads have different
+** process IDs.  Linux threads is inconsistent in this respect.
+** (I'm beginning to think that linux threads is an abomination too.)
+** The consequence of this all is that the hash table for the lockInfo
+** structure has to include the process id as part of its key because
+** locks in different threads are treated as distinct.  But the 
+** openCnt structure should not include the process id in its
+** key because close() clears lock on all threads, not just the current
+** thread.  Were it not for this goofiness in linux threads, we could
+** combine the lockInfo and openCnt structures into a single structure.
+*/
+
+/*
+** An instance of the following structure serves as the key used
+** to locate a particular lockInfo structure given its inode.  Note
+** that we have to include the process ID as part of the key.  On some
+** threading implementations (ex: linux), each thread has a separate
+** process ID.
+*/
+struct lockKey {
+  dev_t dev;   /* Device number */
+  ino_t ino;   /* Inode number */
+  pid_t pid;   /* Process ID */
+};
+
+/*
+** An instance of the following structure is allocated for each open
+** inode on each thread with a different process ID.  (Threads have
+** different process IDs on linux, but not on most other unixes.)
+**
+** A single inode can have multiple file descriptors, so each OsFile
+** structure contains a pointer to an instance of this object and this
+** object keeps a count of the number of OsFiles pointing to it.
+*/
+struct lockInfo {
+  struct lockKey key;  /* The lookup key */
+  int cnt;             /* 0: unlocked.  -1: write lock.  1...: read lock. */
+  int nRef;            /* Number of pointers to this structure */
+};
+
+/*
+** An instance of the following structure serves as the key used
+** to locate a particular openCnt structure given its inode.  This
+** is the same as the lockKey except that the process ID is omitted.
+*/
+struct openKey {
+  dev_t dev;   /* Device number */
+  ino_t ino;   /* Inode number */
+};
+
+/*
+** An instance of the following structure is allocated for each open
+** inode.  This structure keeps track of the number of locks on that
+** inode.  If a close is attempted against an inode that is holding
+** locks, the close is deferred until all locks clear by adding the
+** file descriptor to be closed to the pending list.
+*/
+struct openCnt {
+  struct openKey key;   /* The lookup key */
+  int nRef;             /* Number of pointers to this structure */
+  int nLock;            /* Number of outstanding locks */
+  int nPending;         /* Number of pending close() operations */
+  int *aPending;        /* Malloced space holding fd's awaiting a close() */
+};
+
+/* 
+** These hash table maps inodes and process IDs into lockInfo and openCnt
+** structures.  Access to these hash tables must be protected by a mutex.
+*/
+static Hash lockHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 };
+static Hash openHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 };
+
+/*
+** Release a lockInfo structure previously allocated by findLockInfo().
+*/
+static void releaseLockInfo(struct lockInfo *pLock){
+  pLock->nRef--;
+  if( pLock->nRef==0 ){
+    sqlite3HashInsert(&lockHash, &pLock->key, sizeof(pLock->key), 0);
+    sqliteFree(pLock);
+  }
+}
+
+/*
+** Release a openCnt structure previously allocated by findLockInfo().
+*/
+static void releaseOpenCnt(struct openCnt *pOpen){
+  pOpen->nRef--;
+  if( pOpen->nRef==0 ){
+    sqlite3HashInsert(&openHash, &pOpen->key, sizeof(pOpen->key), 0);
+    sqliteFree(pOpen->aPending);
+    sqliteFree(pOpen);
+  }
+}
+
+/*
+** Given a file descriptor, locate lockInfo and openCnt structures that
+** describes that file descriptor.  Create a new ones if necessary.  The
+** return values might be unset if an error occurs.
+**
+** Return the number of errors.
+*/
+int findLockInfo(
+  int fd,                      /* The file descriptor used in the key */
+  struct lockInfo **ppLock,    /* Return the lockInfo structure here */
+  struct openCnt **ppOpen   /* Return the openCnt structure here */
+){
+  int rc;
+  struct lockKey key1;
+  struct openKey key2;
+  struct stat statbuf;
+  struct lockInfo *pLock;
+  struct openCnt *pOpen;
+  rc = fstat(fd, &statbuf);
+  if( rc!=0 ) return 1;
+  memset(&key1, 0, sizeof(key1));
+  key1.dev = statbuf.st_dev;
+  key1.ino = statbuf.st_ino;
+  key1.pid = getpid();
+  memset(&key2, 0, sizeof(key2));
+  key2.dev = statbuf.st_dev;
+  key2.ino = statbuf.st_ino;
+  pLock = (struct lockInfo*)sqlite3HashFind(&lockHash, &key1, sizeof(key1));
+  if( pLock==0 ){
+    struct lockInfo *pOld;
+    pLock = sqliteMallocRaw( sizeof(*pLock) );
+    if( pLock==0 ) return 1;
+    pLock->key = key1;
+    pLock->nRef = 1;
+    pLock->cnt = 0;
+    pOld = sqlite3HashInsert(&lockHash, &pLock->key, sizeof(key1), pLock);
+    if( pOld!=0 ){
+      assert( pOld==pLock );
+      sqliteFree(pLock);
+      return 1;
+    }
+  }else{
+    pLock->nRef++;
+  }
+  *ppLock = pLock;
+  pOpen = (struct openCnt*)sqlite3HashFind(&openHash, &key2, sizeof(key2));
+  if( pOpen==0 ){
+    struct openCnt *pOld;
+    pOpen = sqliteMallocRaw( sizeof(*pOpen) );
+    if( pOpen==0 ){
+      releaseLockInfo(pLock);
+      return 1;
+    }
+    pOpen->key = key2;
+    pOpen->nRef = 1;
+    pOpen->nLock = 0;
+    pOpen->nPending = 0;
+    pOpen->aPending = 0;
+    pOld = sqlite3HashInsert(&openHash, &pOpen->key, sizeof(key2), pOpen);
+    if( pOld!=0 ){
+      assert( pOld==pOpen );
+      sqliteFree(pOpen);
+      releaseLockInfo(pLock);
+      return 1;
+    }
+  }else{
+    pOpen->nRef++;
+  }
+  *ppOpen = pOpen;
+  return 0;
+}
+
+/*
+** Delete the named file
+*/
+int sqlite3OsDelete(const char *zFilename){
+  unlink(zFilename);
+  return SQLITE_OK;
+}
+
+/*
+** Return TRUE if the named file exists.
+*/
+int sqlite3OsFileExists(const char *zFilename){
+  return access(zFilename, 0)==0;
+}
+
+/*
+** 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 sqlite3OsOpenReadWrite(
+  const char *zFilename,
+  OsFile *id,
+  int *pReadonly
+){
+  int rc;
+  id->dirfd = -1;
+  id->fd = open(zFilename, O_RDWR|O_CREAT|O_LARGEFILE|O_BINARY, 0644);
+  if( id->fd<0 ){
+    id->fd = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY);
+    if( id->fd<0 ){
+      return SQLITE_CANTOPEN; 
+    }
+    *pReadonly = 1;
+  }else{
+    *pReadonly = 0;
+  }
+  sqlite3OsEnterMutex();
+  rc = findLockInfo(id->fd, &id->pLock, &id->pOpen);
+  sqlite3OsLeaveMutex();
+  if( rc ){
+    close(id->fd);
+    return SQLITE_NOMEM;
+  }
+  id->locked = 0;
+  TRACE3("OPEN    %-3d %s\n", id->fd, zFilename);
+  OpenCounter(+1);
+  return SQLITE_OK;
+}
+
+
+/*
+** 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 sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
+  int rc;
+  if( access(zFilename, 0)==0 ){
+    return SQLITE_CANTOPEN;
+  }
+  id->dirfd = -1;
+  id->fd = open(zFilename,
+                O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_LARGEFILE|O_BINARY, 0600);
+  if( id->fd<0 ){
+    return SQLITE_CANTOPEN;
+  }
+  sqlite3OsEnterMutex();
+  rc = findLockInfo(id->fd, &id->pLock, &id->pOpen);
+  sqlite3OsLeaveMutex();
+  if( rc ){
+    close(id->fd);
+    unlink(zFilename);
+    return SQLITE_NOMEM;
+  }
+  id->locked = 0;
+  if( delFlag ){
+    unlink(zFilename);
+  }
+  TRACE3("OPEN-EX %-3d %s\n", id->fd, zFilename);
+  OpenCounter(+1);
+  return SQLITE_OK;
+}
+
+/*
+** 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 sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
+  int rc;
+  id->dirfd = -1;
+  id->fd = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY);
+  if( id->fd<0 ){
+    return SQLITE_CANTOPEN;
+  }
+  sqlite3OsEnterMutex();
+  rc = findLockInfo(id->fd, &id->pLock, &id->pOpen);
+  sqlite3OsLeaveMutex();
+  if( rc ){
+    close(id->fd);
+    return SQLITE_NOMEM;
+  }
+  id->locked = 0;
+  TRACE3("OPEN-RO %-3d %s\n", id->fd, zFilename);
+  OpenCounter(+1);
+  return SQLITE_OK;
+}
+
+/*
+** 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.
+*/
+int sqlite3OsOpenDirectory(
+  const char *zDirname,
+  OsFile *id
+){
+  if( id->fd<0 ){
+    /* Do not open the directory if the corresponding file is not already
+    ** open. */
+    return SQLITE_CANTOPEN;
+  }
+  assert( id->dirfd<0 );
+  id->dirfd = open(zDirname, O_RDONLY|O_BINARY, 0644);
+  if( id->dirfd<0 ){
+    return SQLITE_CANTOPEN; 
+  }
+  TRACE3("OPENDIR %-3d %s\n", id->dirfd, 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 sqlite3OsTempFileName(char *zBuf){
+  static const char *azDirs[] = {
+     "/var/tmp",
+     "/usr/tmp",
+     "/tmp",
+     ".",
+  };
+  static unsigned char zChars[] =
+    "abcdefghijklmnopqrstuvwxyz"
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+    "0123456789";
+  int i, j;
+  struct stat buf;
+  const char *zDir = ".";
+  for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); i++){
+    if( stat(azDirs[i], &buf) ) continue;
+    if( !S_ISDIR(buf.st_mode) ) continue;
+    if( access(azDirs[i], 07) ) continue;
+    zDir = azDirs[i];
+    break;
+  }
+  do{
+    sprintf(zBuf, "%s/"TEMP_FILE_PREFIX, zDir);
+    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;
+  }while( access(zBuf,0)==0 );
+  return SQLITE_OK; 
+}
+
+/*
+** Close a file.
+*/
+int sqlite3OsClose(OsFile *id){
+  sqlite3OsUnlock(id);
+  if( id->dirfd>=0 ) close(id->dirfd);
+  id->dirfd = -1;
+  sqlite3OsEnterMutex();
+  if( id->pOpen->nLock ){
+    /* If there are outstanding locks, do not actually close the file just
+    ** yet because that would clear those locks.  Instead, add the file
+    ** descriptor to pOpen->aPending.  It will be automatically closed when
+    ** the last lock is cleared.
+    */
+    int *aNew;
+    struct openCnt *pOpen = id->pOpen;
+    pOpen->nPending++;
+    aNew = sqliteRealloc( pOpen->aPending, pOpen->nPending*sizeof(int) );
+    if( aNew==0 ){
+      /* If a malloc fails, just leak the file descriptor */
+    }else{
+      pOpen->aPending = aNew;
+      pOpen->aPending[pOpen->nPending-1] = id->fd;
+    }
+  }else{
+    /* There are no outstanding locks so we can close the file immediately */
+    close(id->fd);
+  }
+  releaseLockInfo(id->pLock);
+  releaseOpenCnt(id->pOpen);
+  sqlite3OsLeaveMutex();
+  TRACE2("CLOSE   %-3d\n", id->fd);
+  OpenCounter(-1);
+  return SQLITE_OK;
+}
+
+/*
+** 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 sqlite3OsRead(OsFile *id, void *pBuf, int amt){
+  int got;
+  SimulateIOError(SQLITE_IOERR);
+  TIMER_START;
+  got = read(id->fd, pBuf, amt);
+  TIMER_END;
+  TRACE4("READ    %-3d %7d %d\n", id->fd, last_page, elapse);
+  SEEK(0);
+  /* if( got<0 ) got = 0; */
+  if( got==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.
+*/
+int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
+  int wrote = 0;
+  SimulateIOError(SQLITE_IOERR);
+  TIMER_START;
+  while( amt>0 && (wrote = write(id->fd, pBuf, amt))>0 ){
+    amt -= wrote;
+    pBuf = &((char*)pBuf)[wrote];
+  }
+  TIMER_END;
+  TRACE4("WRITE   %-3d %7d %d\n", id->fd, last_page, elapse);
+  SEEK(0);
+  if( amt>0 ){
+    return SQLITE_FULL;
+  }
+  return SQLITE_OK;
+}
+
+/*
+** Move the read/write pointer in a file.
+*/
+int sqlite3OsSeek(OsFile *id, off_t offset){
+  SEEK(offset/1024 + 1);
+  lseek(id->fd, offset, SEEK_SET);
+  return SQLITE_OK;
+}
+
+/*
+** Make sure all writes to a particular file are committed to disk.
+**
+** Under Unix, 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.
+*/
+int sqlite3OsSync(OsFile *id){
+  SimulateIOError(SQLITE_IOERR);
+  TRACE2("SYNC    %-3d\n", id->fd);
+  if( fsync(id->fd) ){
+    return SQLITE_IOERR;
+  }else{
+    if( id->dirfd>=0 ){
+      TRACE2("DIRSYNC %-3d\n", id->dirfd);
+      fsync(id->dirfd);
+      close(id->dirfd);  /* Only need to sync once, so close the directory */
+      id->dirfd = -1;    /* when we are done. */
+    }
+    return SQLITE_OK;
+  }
+}
+
+/*
+** Truncate an open file to a specified size
+*/
+int sqlite3OsTruncate(OsFile *id, off_t nByte){
+  SimulateIOError(SQLITE_IOERR);
+  return ftruncate(id->fd, nByte)==0 ? SQLITE_OK : SQLITE_IOERR;
+}
+
+/*
+** Determine the current size of a file in bytes
+*/
+int sqlite3OsFileSize(OsFile *id, off_t *pSize){
+  struct stat buf;
+  SimulateIOError(SQLITE_IOERR);
+  if( fstat(id->fd, &buf)!=0 ){
+    return SQLITE_IOERR;
+  }
+  *pSize = buf.st_size;
+  return SQLITE_OK;
+}
+
+
+/*
+** Change the status of the lock on the file "id" to be a readlock.
+** If the file was write locked, then this reduces the lock to a read.
+** If the file was read locked, then this acquires a new read lock.
+**
+** Return SQLITE_OK on success and SQLITE_BUSY on failure.  If this
+** library was compiled with large file support (LFS) but LFS is not
+** available on the host, then an SQLITE_NOLFS is returned.
+*/
+int sqlite3OsReadLock(OsFile *id){
+  int rc;
+  sqlite3OsEnterMutex();
+  if( id->pLock->cnt>0 ){
+    if( !id->locked ){
+      id->pLock->cnt++;
+      id->locked = 1;
+      id->pOpen->nLock++;
+    }
+    rc = SQLITE_OK;
+  }else if( id->locked || id->pLock->cnt==0 ){
+    struct flock lock;
+    int s;
+    lock.l_type = F_RDLCK;
+    lock.l_whence = SEEK_SET;
+    lock.l_start = lock.l_len = 0L;
+    s = fcntl(id->fd, F_SETLK, &lock);
+    if( s!=0 ){
+      rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
+    }else{
+      rc = SQLITE_OK;
+      if( !id->locked ){
+        id->pOpen->nLock++;
+        id->locked = 1;
+      }
+      id->pLock->cnt = 1;
+    }
+  }else{
+    rc = SQLITE_BUSY;
+  }
+  sqlite3OsLeaveMutex();
+  return rc;
+}
+
+/*
+** Change the lock status to be an exclusive or write lock.  Return
+** SQLITE_OK on success and SQLITE_BUSY on a failure.  If this
+** library was compiled with large file support (LFS) but LFS is not
+** available on the host, then an SQLITE_NOLFS is returned.
+*/
+int sqlite3OsWriteLock(OsFile *id){
+  int rc;
+  sqlite3OsEnterMutex();
+  if( id->pLock->cnt==0 || (id->pLock->cnt==1 && id->locked==1) ){
+    struct flock lock;
+    int s;
+    lock.l_type = F_WRLCK;
+    lock.l_whence = SEEK_SET;
+    lock.l_start = lock.l_len = 0L;
+    s = fcntl(id->fd, F_SETLK, &lock);
+    if( s!=0 ){
+      rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
+    }else{
+      rc = SQLITE_OK;
+      if( !id->locked ){
+        id->pOpen->nLock++;
+        id->locked = 1;
+      }
+      id->pLock->cnt = -1;
+    }
+  }else{
+    rc = SQLITE_BUSY;
+  }
+  sqlite3OsLeaveMutex();
+  return rc;
+}
+
+/*
+** Unlock the given file descriptor.  If the file descriptor was
+** not previously locked, then this routine is a no-op.  If this
+** library was compiled with large file support (LFS) but LFS is not
+** available on the host, then an SQLITE_NOLFS is returned.
+*/
+int sqlite3OsUnlock(OsFile *id){
+  int rc;
+  if( !id->locked ) return SQLITE_OK;
+  sqlite3OsEnterMutex();
+  assert( id->pLock->cnt!=0 );
+  if( id->pLock->cnt>1 ){
+    id->pLock->cnt--;
+    rc = SQLITE_OK;
+  }else{
+    struct flock lock;
+    int s;
+    lock.l_type = F_UNLCK;
+    lock.l_whence = SEEK_SET;
+    lock.l_start = lock.l_len = 0L;
+    s = fcntl(id->fd, F_SETLK, &lock);
+    if( s!=0 ){
+      rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
+    }else{
+      rc = SQLITE_OK;
+      id->pLock->cnt = 0;
+    }
+  }
+  if( rc==SQLITE_OK ){
+    /* Decrement the count of locks against this same file.  When the
+    ** count reaches zero, close any other file descriptors whose close
+    ** was deferred because of outstanding locks.
+    */
+    struct openCnt *pOpen = id->pOpen;
+    pOpen->nLock--;
+    assert( pOpen->nLock>=0 );
+    if( pOpen->nLock==0 && pOpen->nPending>0 ){
+      int i;
+      for(i=0; i<pOpen->nPending; i++){
+        close(pOpen->aPending[i]);
+      }
+      sqliteFree(pOpen->aPending);
+      pOpen->nPending = 0;
+      pOpen->aPending = 0;
+    }
+  }
+  sqlite3OsLeaveMutex();
+  id->locked = 0;
+  return rc;
+}
+
+/*
+** Get information to seed the random number generator.  The seed
+** is written into the buffer zBuf[256].  The calling function must
+** supply a sufficiently large buffer.
+*/
+int sqlite3OsRandomSeed(char *zBuf){
+  /* 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, 256);
+#if !defined(SQLITE_TEST)
+  {
+    int pid;
+    time((time_t*)zBuf);
+    pid = getpid();
+    memcpy(&zBuf[sizeof(time_t)], &pid, sizeof(pid));
+  }
+#endif
+  return SQLITE_OK;
+}
+
+/*
+** Sleep for a little while.  Return the amount of time slept.
+*/
+int sqlite3OsSleep(int ms){
+#if defined(HAVE_USLEEP) && HAVE_USLEEP
+  usleep(ms*1000);
+  return ms;
+#else
+  sleep((ms+999)/1000);
+  return 1000*((ms+999)/1000);
+#endif
+}
+
+/*
+** Static variables used for thread synchronization
+*/
+static int inMutex = 0;
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/*
+** The following pair of routine implement mutual exclusion for
+** multi-threaded processes.  Only a single thread is allowed to
+** executed code that is surrounded by EnterMutex() and LeaveMutex().
+**
+** SQLite uses only a single Mutex.  There is not much critical
+** code and what little there is executes quickly and without blocking.
+*/
+void sqlite3OsEnterMutex(){
+#ifdef SQLITE_UNIX_THREADS
+  pthread_mutex_lock(&mutex);
+#endif
+  assert( !inMutex );
+  inMutex = 1;
+}
+void sqlite3OsLeaveMutex(){
+  assert( inMutex );
+  inMutex = 0;
+#ifdef SQLITE_UNIX_THREADS
+  pthread_mutex_unlock(&mutex);
+#endif
+}
+
+/*
+** Turn a relative pathname into a full pathname.  Return a pointer
+** to the full pathname stored in space obtained from sqliteMalloc().
+** The calling function is responsible for freeing this space once it
+** is no longer needed.
+*/
+char *sqlite3OsFullPathname(const char *zRelative){
+  char *zFull = 0;
+  if( zRelative[0]=='/' ){
+    sqlite3SetString(&zFull, zRelative, (char*)0);
+  }else{
+    char zBuf[5000];
+    sqlite3SetString(&zFull, getcwd(zBuf, sizeof(zBuf)), "/", zRelative,
+                    (char*)0);
+  }
+  return zFull;
+}
+
+/*
+** The following variable, if set to a non-zero value, becomes the result
+** returned from sqlite3OsCurrentTime().  This is used for testing.
+*/
+#ifdef SQLITE_TEST
+int sqlite3_current_time = 0;
+#endif
+
+/*
+** 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.
+*/
+int sqlite3OsCurrentTime(double *prNow){
+  time_t t;
+  time(&t);
+  *prNow = t/86400.0 + 2440587.5;
+#ifdef SQLITE_TEST
+  if( sqlite3_current_time ){
+    *prNow = sqlite3_current_time/86400.0 + 2440587.5;
+  }
+#endif
+  return 0;
+}
+
+#endif /* OS_UNIX */
diff --git a/src/os_unix.h b/src/os_unix.h
new file mode 100644
index 0000000..9dab737
--- /dev/null
+++ b/src/os_unix.h
@@ -0,0 +1,84 @@
+/*
+** 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 header file defined OS-specific features for Unix.
+*/
+#ifndef _SQLITE_OS_UNIX_H_
+#define _SQLITE_OS_UNIX_H_
+
+/*
+** Helpful hint:  To get this to compile on HP/UX, add -D_INCLUDE_POSIX_SOURCE
+** to the compiler command line.
+*/
+
+/*
+** These #defines should enable >2GB file support on Posix if the
+** underlying operating system supports it.  If the OS lacks
+** large file support, or if the OS is windows, these should be no-ops.
+**
+** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch
+** on the compiler command line.  This is necessary if you are compiling
+** on a recent machine (ex: RedHat 7.2) but you want your code to work
+** on an older machine (ex: RedHat 6.0).  If you compile on RedHat 7.2
+** without this option, LFS is enable.  But LFS does not exist in the kernel
+** in RedHat 6.0, so the code won't work.  Hence, for maximum binary
+** portability you should omit LFS.
+**
+** Similar is true for MacOS.  LFS is only supported on MacOS 9 and later.
+*/
+#ifndef SQLITE_DISABLE_LFS
+# define _LARGE_FILE       1
+# ifndef _FILE_OFFSET_BITS
+#   define _FILE_OFFSET_BITS 64
+# endif
+# define _LARGEFILE_SOURCE 1
+#endif
+
+/*
+** standard include files.
+*/
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+/*
+** The OsFile structure is a operating-system independing representation
+** of an open file handle.  It is defined differently for each architecture.
+**
+** This is the definition for Unix.
+*/
+typedef struct OsFile OsFile;
+struct OsFile {
+  struct openCnt *pOpen;    /* Info about all open fd's on this inode */
+  struct lockInfo *pLock;   /* Info about locks on this inode */
+  int fd;                   /* The file descriptor */
+  int locked;               /* True if this instance holds the lock */
+  int dirfd;                /* File descriptor for the directory */
+};
+
+/*
+** Maximum number of characters in a temporary file name
+*/
+#define SQLITE_TEMPNAME_SIZE 200
+
+/*
+** Minimum interval supported by sqlite3OsSleep().
+*/
+#if defined(HAVE_USLEEP) && HAVE_USLEEP
+# define SQLITE_MIN_SLEEP_MS 1
+#else
+# define SQLITE_MIN_SLEEP_MS 1000
+#endif
+
+
+#endif /* _SQLITE_OS_UNIX_H_ */
diff --git a/src/os_win.c b/src/os_win.c
new file mode 100644
index 0000000..9c21f7c
--- /dev/null
+++ b/src/os_win.c
@@ -0,0 +1,601 @@
+/*
+** 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 "os.h"          /* Must be first to enable large file support */
+#if OS_WIN               /* This file is used for windows only */
+#include "sqliteInt.h"
+
+#include <winbase.h>
+
+/*
+** Macros used to determine whether or not to use threads.
+*/
+#if defined(THREADSAFE) && THREADSAFE
+# define SQLITE_W32_THREADS 1
+#endif
+
+/*
+** Include code that is common to all os_*.c files
+*/
+#include "os_common.h"
+
+/*
+** Delete the named file
+*/
+int sqlite3OsDelete(const char *zFilename){
+  DeleteFile(zFilename);
+  return SQLITE_OK;
+}
+
+/*
+** Return TRUE if the named file exists.
+*/
+int sqlite3OsFileExists(const char *zFilename){
+  return GetFileAttributes(zFilename) != 0xffffffff;
+}
+
+/*
+** 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 sqlite3OsOpenReadWrite(
+  const char *zFilename,
+  OsFile *id,
+  int *pReadonly
+){
+  HANDLE h = CreateFile(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 = CreateFile(zFilename,
+       GENERIC_READ,
+       FILE_SHARE_READ,
+       NULL,
+       OPEN_ALWAYS,
+       FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
+       NULL
+    );
+    if( h==INVALID_HANDLE_VALUE ){
+      return SQLITE_CANTOPEN;
+    }
+    *pReadonly = 1;
+  }else{
+    *pReadonly = 0;
+  }
+  id->h = h;
+  id->locked = 0;
+  OpenCounter(+1);
+  return SQLITE_OK;
+}
+
+
+/*
+** 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 sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
+  HANDLE h;
+  int fileflags;
+  if( delFlag ){
+    fileflags = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_RANDOM_ACCESS 
+                     | FILE_FLAG_DELETE_ON_CLOSE;
+  }else{
+    fileflags = FILE_FLAG_RANDOM_ACCESS;
+  }
+  h = CreateFile(zFilename,
+     GENERIC_READ | GENERIC_WRITE,
+     0,
+     NULL,
+     CREATE_ALWAYS,
+     fileflags,
+     NULL
+  );
+  if( h==INVALID_HANDLE_VALUE ){
+    return SQLITE_CANTOPEN;
+  }
+  id->h = h;
+  id->locked = 0;
+  OpenCounter(+1);
+  return SQLITE_OK;
+}
+
+/*
+** 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 sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
+  HANDLE h = CreateFile(zFilename,
+     GENERIC_READ,
+     0,
+     NULL,
+     OPEN_EXISTING,
+     FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
+     NULL
+  );
+  if( h==INVALID_HANDLE_VALUE ){
+    return SQLITE_CANTOPEN;
+  }
+  id->h = h;
+  id->locked = 0;
+  OpenCounter(+1);
+  return SQLITE_OK;
+}
+
+/*
+** 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.
+*/
+int sqlite3OsOpenDirectory(
+  const char *zDirname,
+  OsFile *id
+){
+  return SQLITE_OK;
+}
+
+/*
+** Create a temporary file name in zBuf.  zBuf must be big enough to
+** hold at least SQLITE_TEMPNAME_SIZE characters.
+*/
+int sqlite3OsTempFileName(char *zBuf){
+  static char zChars[] =
+    "abcdefghijklmnopqrstuvwxyz"
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+    "0123456789";
+  int i, j;
+  char zTempPath[SQLITE_TEMPNAME_SIZE];
+  GetTempPath(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;
+  }
+  return SQLITE_OK; 
+}
+
+/*
+** Close a file.
+*/
+int sqlite3OsClose(OsFile *id){
+  CloseHandle(id->h);
+  OpenCounter(-1);
+  return SQLITE_OK;
+}
+
+/*
+** 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 sqlite3OsRead(OsFile *id, void *pBuf, int amt){
+  DWORD got;
+  SimulateIOError(SQLITE_IOERR);
+  TRACE2("READ %d\n", last_page);
+  if( !ReadFile(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.
+*/
+int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
+  int rc;
+  DWORD wrote;
+  SimulateIOError(SQLITE_IOERR);
+  TRACE2("WRITE %d\n", last_page);
+  while( amt>0 && (rc = WriteFile(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;
+}
+
+/*
+** Move the read/write pointer in a file.
+*/
+int sqlite3OsSeek(OsFile *id, off_t offset){
+  LONG upperBits = offset>>32;
+  LONG lowerBits = offset & 0xffffffff;
+  DWORD rc;
+  SEEK(offset/1024 + 1);
+  rc = SetFilePointer(id->h, lowerBits, &upperBits, FILE_BEGIN);
+  /* TRACE3("SEEK rc=0x%x upper=0x%x\n", rc, upperBits); */
+  return SQLITE_OK;
+}
+
+/*
+** Make sure all writes to a particular file are committed to disk.
+*/
+int sqlite3OsSync(OsFile *id){
+  if( FlushFileBuffers(id->h) ){
+    return SQLITE_OK;
+  }else{
+    return SQLITE_IOERR;
+  }
+}
+
+/*
+** Truncate an open file to a specified size
+*/
+int sqlite3OsTruncate(OsFile *id, off_t nByte){
+  LONG upperBits = nByte>>32;
+  SimulateIOError(SQLITE_IOERR);
+  SetFilePointer(id->h, nByte, &upperBits, FILE_BEGIN);
+  SetEndOfFile(id->h);
+  return SQLITE_OK;
+}
+
+/*
+** Determine the current size of a file in bytes
+*/
+int sqlite3OsFileSize(OsFile *id, off_t *pSize){
+  DWORD upperBits, lowerBits;
+  SimulateIOError(SQLITE_IOERR);
+  lowerBits = GetFileSize(id->h, &upperBits);
+  *pSize = (((off_t)upperBits)<<32) + lowerBits;
+  return SQLITE_OK;
+}
+
+/*
+** Return true (non-zero) if we are running under WinNT, Win2K or WinXP.
+** Return false (zero) for Win95, Win98, or WinME.
+**
+** Here is an interesting observation:  Win95, Win98, and WinME lack
+** the LockFileEx() API.  But we can still statically link against that
+** API as long as we don't call it win running Win95/98/ME.  A call to
+** this routine is used to determine if the host is Win95/98/ME or
+** WinNT/2K/XP so that we will know whether or not we can safely call
+** the LockFileEx() API.
+*/
+int isNT(void){
+  static int osType = 0;   /* 0=unknown 1=win95 2=winNT */
+  if( osType==0 ){
+    OSVERSIONINFO sInfo;
+    sInfo.dwOSVersionInfoSize = sizeof(sInfo);
+    GetVersionEx(&sInfo);
+    osType = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1;
+  }
+  return osType==2;
+}
+
+/*
+** Windows file locking notes:
+**
+** We cannot use LockFileEx() or UnlockFileEx() on Win95/98/ME because
+** those functions are not available.  So we use only LockFile() and
+** UnlockFile().
+**
+** LockFile() prevents not just writing but also reading by other processes.
+** (This is a design error on the part of Windows, but there is nothing
+** we can do about that.)  So the region used for locking is at the
+** end of the file where it is unlikely to ever interfere with an
+** actual read attempt.
+**
+** A database read lock is obtained by locking a single randomly-chosen 
+** byte out of a specific range of bytes. The lock byte is obtained at 
+** random so two separate readers can probably access the file at the 
+** same time, unless they are unlucky and choose the same lock byte.
+** A database write lock is obtained by locking all bytes in the range.
+** There can only be one writer.
+**
+** A lock is obtained on the first byte of the lock range before acquiring
+** either a read lock or a write lock.  This prevents two processes from
+** attempting to get a lock at a same time.  The semantics of 
+** sqlite3OsReadLock() require that if there is already a write lock, that
+** lock is converted into a read lock atomically.  The lock on the first
+** byte allows us to drop the old write lock and get the read lock without
+** another process jumping into the middle and messing us up.  The same
+** argument applies to sqlite3OsWriteLock().
+**
+** On WinNT/2K/XP systems, LockFileEx() and UnlockFileEx() are available,
+** which means we can use reader/writer locks.  When reader writer locks
+** are used, the lock is placed on the same range of bytes that is used
+** for probabilistic locking in Win95/98/ME.  Hence, the locking scheme
+** will support two or more Win95 readers or two or more WinNT readers.
+** But a single Win95 reader will lock out all WinNT readers and a single
+** WinNT reader will lock out all other Win95 readers.
+**
+** The following #defines specify the range of bytes used for locking.
+** N_LOCKBYTE is the number of bytes available for doing the locking.
+** The first byte used to hold the lock while the lock is changing does
+** not count toward this number.  FIRST_LOCKBYTE is the address of
+** the first byte in the range of bytes used for locking.
+*/
+#define N_LOCKBYTE       10239
+#define FIRST_LOCKBYTE   (0xffffffff - N_LOCKBYTE)
+
+/*
+** Change the status of the lock on the file "id" to be a readlock.
+** If the file was write locked, then this reduces the lock to a read.
+** If the file was read locked, then this acquires a new read lock.
+**
+** Return SQLITE_OK on success and SQLITE_BUSY on failure.  If this
+** library was compiled with large file support (LFS) but LFS is not
+** available on the host, then an SQLITE_NOLFS is returned.
+*/
+int sqlite3OsReadLock(OsFile *id){
+  int rc;
+  if( id->locked>0 ){
+    rc = SQLITE_OK;
+  }else{
+    int lk;
+    int res;
+    int cnt = 100;
+    sqlite3Randomness(sizeof(lk), &lk);
+    lk = (lk & 0x7fffffff)%N_LOCKBYTE + 1;
+    while( cnt-->0 && (res = LockFile(id->h, FIRST_LOCKBYTE, 0, 1, 0))==0 ){
+      Sleep(1);
+    }
+    if( res ){
+      UnlockFile(id->h, FIRST_LOCKBYTE+1, 0, N_LOCKBYTE, 0);
+      if( isNT() ){
+        OVERLAPPED ovlp;
+        ovlp.Offset = FIRST_LOCKBYTE+1;
+        ovlp.OffsetHigh = 0;
+        ovlp.hEvent = 0;
+        res = LockFileEx(id->h, LOCKFILE_FAIL_IMMEDIATELY, 
+                          0, N_LOCKBYTE, 0, &ovlp);
+      }else{
+        res = LockFile(id->h, FIRST_LOCKBYTE+lk, 0, 1, 0);
+      }
+      UnlockFile(id->h, FIRST_LOCKBYTE, 0, 1, 0);
+    }
+    if( res ){
+      id->locked = lk;
+      rc = SQLITE_OK;
+    }else{
+      rc = SQLITE_BUSY;
+    }
+  }
+  return rc;
+}
+
+/*
+** Change the lock status to be an exclusive or write lock.  Return
+** SQLITE_OK on success and SQLITE_BUSY on a failure.  If this
+** library was compiled with large file support (LFS) but LFS is not
+** available on the host, then an SQLITE_NOLFS is returned.
+*/
+int sqlite3OsWriteLock(OsFile *id){
+  int rc;
+  if( id->locked<0 ){
+    rc = SQLITE_OK;
+  }else{
+    int res;
+    int cnt = 100;
+    while( cnt-->0 && (res = LockFile(id->h, FIRST_LOCKBYTE, 0, 1, 0))==0 ){
+      Sleep(1);
+    }
+    if( res ){
+      if( id->locked>0 ){
+        if( isNT() ){
+          UnlockFile(id->h, FIRST_LOCKBYTE+1, 0, N_LOCKBYTE, 0);
+        }else{
+          res = UnlockFile(id->h, FIRST_LOCKBYTE + id->locked, 0, 1, 0);
+        }
+      }
+      if( res ){
+        res = LockFile(id->h, FIRST_LOCKBYTE+1, 0, N_LOCKBYTE, 0);
+      }else{
+        res = 0;
+      }
+      UnlockFile(id->h, FIRST_LOCKBYTE, 0, 1, 0);
+    }
+    if( res ){
+      id->locked = -1;
+      rc = SQLITE_OK;
+    }else{
+      rc = SQLITE_BUSY;
+    }
+  }
+  return rc;
+}
+
+/*
+** Unlock the given file descriptor.  If the file descriptor was
+** not previously locked, then this routine is a no-op.  If this
+** library was compiled with large file support (LFS) but LFS is not
+** available on the host, then an SQLITE_NOLFS is returned.
+*/
+int sqlite3OsUnlock(OsFile *id){
+  int rc;
+  if( id->locked==0 ){
+    rc = SQLITE_OK;
+  }else if( isNT() || id->locked<0 ){
+    UnlockFile(id->h, FIRST_LOCKBYTE+1, 0, N_LOCKBYTE, 0);
+    rc = SQLITE_OK;
+    id->locked = 0;
+  }else{
+    UnlockFile(id->h, FIRST_LOCKBYTE+id->locked, 0, 1, 0);
+    rc = SQLITE_OK;
+    id->locked = 0;
+  }
+  return rc;
+}
+
+/*
+** Get information to seed the random number generator.  The seed
+** is written into the buffer zBuf[256].  The calling function must
+** supply a sufficiently large buffer.
+*/
+int sqlite3OsRandomSeed(char *zBuf){
+  /* 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, 256);
+  GetSystemTime((LPSYSTEMTIME)zBuf);
+  return SQLITE_OK;
+}
+
+/*
+** Sleep for a little while.  Return the amount of time slept.
+*/
+int sqlite3OsSleep(int ms){
+  Sleep(ms);
+  return ms;
+}
+
+/*
+** Static variables used for thread synchronization
+*/
+static int inMutex = 0;
+#ifdef SQLITE_W32_THREADS
+  static CRITICAL_SECTION cs;
+#endif
+
+/*
+** The following pair of routine implement mutual exclusion for
+** multi-threaded processes.  Only a single thread is allowed to
+** executed code that is surrounded by EnterMutex() and LeaveMutex().
+**
+** SQLite uses only a single Mutex.  There is not much critical
+** code and what little there is executes quickly and without blocking.
+*/
+void sqlite3OsEnterMutex(){
+#ifdef SQLITE_W32_THREADS
+  static int isInit = 0;
+  while( !isInit ){
+    static long lock = 0;
+    if( InterlockedIncrement(&lock)==1 ){
+      InitializeCriticalSection(&cs);
+      isInit = 1;
+    }else{
+      Sleep(1);
+    }
+  }
+  EnterCriticalSection(&cs);
+#endif
+  assert( !inMutex );
+  inMutex = 1;
+}
+void sqlite3OsLeaveMutex(){
+  assert( inMutex );
+  inMutex = 0;
+#ifdef SQLITE_W32_THREADS
+  LeaveCriticalSection(&cs);
+#endif
+}
+
+/*
+** Turn a relative pathname into a full pathname.  Return a pointer
+** to the full pathname stored in space obtained from sqliteMalloc().
+** The calling function is responsible for freeing this space once it
+** is no longer needed.
+*/
+char *sqlite3OsFullPathname(const char *zRelative){
+  char *zNotUsed;
+  char *zFull;
+  int nByte;
+  nByte = GetFullPathName(zRelative, 0, 0, &zNotUsed) + 1;
+  zFull = sqliteMalloc( nByte );
+  if( zFull==0 ) return 0;
+  GetFullPathName(zRelative, nByte, zFull, &zNotUsed);
+  return zFull;
+}
+
+/*
+** The following variable, if set to a non-zero value, becomes the result
+** returned from sqlite3OsCurrentTime().  This is used for testing.
+*/
+#ifdef SQLITE_TEST
+int sqlite3_current_time = 0;
+#endif
+
+/*
+** 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.
+*/
+int sqlite3OsCurrentTime(double *prNow){
+  FILETIME ft;
+  /* FILETIME structure is a 64-bit value representing the number of 
+     100-nanosecond intervals since January 1, 1601 (= JD 2305813.5). 
+  */
+  double now;
+  GetSystemTimeAsFileTime( &ft );
+  now = ((double)ft.dwHighDateTime) * 4294967296.0; 
+  *prNow = (now + ft.dwLowDateTime)/864000000000.0 + 2305813.5;
+#ifdef SQLITE_TEST
+  if( sqlite3_current_time ){
+    *prNow = sqlite3_current_time/86400.0 + 2440587.5;
+  }
+#endif
+  return 0;
+}
+
+#endif /* OS_WIN */
diff --git a/src/os_win.h b/src/os_win.h
new file mode 100644
index 0000000..35f7740
--- /dev/null
+++ b/src/os_win.h
@@ -0,0 +1,49 @@
+/*
+** 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 header file defines OS-specific features for Win32
+*/
+#ifndef _SQLITE_OS_WIN_H_
+#define _SQLITE_OS_WIN_H_
+
+#include <windows.h>
+#include <winbase.h>
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+  typedef __int64 off_t;
+#else
+# if !defined(_CYGWIN_TYPES_H)
+  typedef long long off_t;
+#   if defined(__MINGW32__)
+#     define	_OFF_T_
+#   endif
+# endif
+#endif
+
+/*
+** The OsFile structure is a operating-system independing representation
+** of an open file handle.  It is defined differently for each architecture.
+**
+** This is the definition for Win32.
+*/
+typedef struct OsFile OsFile;
+struct OsFile {
+  HANDLE h;               /* Handle for accessing the file */
+  int locked;             /* 0: unlocked, <0: write lock, >0: read lock */
+};
+
+
+#define SQLITE_TEMPNAME_SIZE (MAX_PATH+50)
+#define SQLITE_MIN_SLEEP_MS 1
+
+
+#endif /* _SQLITE_OS_WIN_H_ */
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 5e3153b..5c233e9 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.245 2004/05/22 03:05:34 danielk1977 Exp $
+** @(#) $Id: sqliteInt.h,v 1.246 2004/05/22 17:41:59 drh Exp $
 */
 #include "config.h"
 #include "sqlite.h"
@@ -130,6 +130,14 @@
 typedef unsigned INTPTR_TYPE uptr; /* Big enough to hold a pointer */
 
 /*
+** Macros to determine whether the machine is big or little endian,
+** evaluated at runtime.
+*/
+extern const int sqlite3one;
+#define SQLITE3_BIGENDIAN    (*(char *)(&sqlite3one)==0)
+#define SQLITE3_LITTLEENDIAN (*(char *)(&sqlite3one)==1)
+
+/*
 ** Defer sourcing vdbe.h until after the "u8" typedef is defined.
 */
 #include "vdbe.h"
diff --git a/src/utf.c b/src/utf.c
index 5e77967..5548de2 100644
--- a/src/utf.c
+++ b/src/utf.c
@@ -12,7 +12,7 @@
 ** This file contains routines used to translate between UTF-8, 
 ** UTF-16, UTF-16BE, and UTF-16LE.
 **
-** $Id: utf.c,v 1.7 2004/05/22 03:05:34 danielk1977 Exp $
+** $Id: utf.c,v 1.8 2004/05/22 17:41:59 drh Exp $
 **
 ** Notes on UTF-8:
 **
@@ -49,11 +49,8 @@
 ** replacement character U+FFFD for each pair of bytes that cannot be
 ** interpeted as part of a valid unicode character.
 */
-
 #include <assert.h>
-#include <unistd.h>
 #include "sqliteInt.h"
-#include "os.h"
 
 typedef struct UtfString UtfString;
 struct UtfString {
@@ -590,5 +587,3 @@
   }
   return SQLITE_OK;
 }
- 
-