Further progress on migration to sqlite3_vfs. (CVS 4242)

FossilOrigin-Name: a258c4ec240f96bccfe493e98d0827ec7dd12e67
diff --git a/src/date.c b/src/date.c
index ec2d34a..4629eba 100644
--- a/src/date.c
+++ b/src/date.c
@@ -16,7 +16,7 @@
 ** sqlite3RegisterDateTimeFunctions() found at the bottom of the file.
 ** All other code has file scope.
 **
-** $Id: date.c,v 1.68 2007/08/16 10:09:03 danielk1977 Exp $
+** $Id: date.c,v 1.69 2007/08/18 10:59:20 danielk1977 Exp $
 **
 ** SQLite processes all times and dates as Julian Day numbers.  The
 ** dates and times are stored as the number of days since noon
@@ -303,7 +303,11 @@
 ** as there is a time string.  The time string can be omitted as long
 ** as there is a year and date.
 */
-static int parseDateOrTime(const char *zDate, DateTime *p){
+static int parseDateOrTime(
+  sqlite3_context *context, 
+  const char *zDate, 
+  DateTime *p
+){
   memset(p, 0, sizeof(*p));
   if( parseYyyyMmDd(zDate,p)==0 ){
     return 0;
@@ -311,7 +315,7 @@
     return 0;
   }else if( sqlite3StrICmp(zDate,"now")==0){
     double r;
-    sqlite3OsCurrentTime(&r);
+    sqlite3OsCurrentTime((sqlite3_vfs *)sqlite3_user_data(context), &r);
     p->rJD = r;
     p->validJD = 1;
     return 0;
@@ -423,7 +427,7 @@
 #else
   {
     struct tm *pTm;
-    sqlite3OsEnterMutex();
+    sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_GLOBAL));
     pTm = localtime(&t);
     y.Y = pTm->tm_year + 1900;
     y.M = pTm->tm_mon + 1;
@@ -431,7 +435,7 @@
     y.h = pTm->tm_hour;
     y.m = pTm->tm_min;
     y.s = pTm->tm_sec;
-    sqlite3OsLeaveMutex();
+    sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_GLOBAL));
   }
 #endif
   y.validYMD = 1;
@@ -651,11 +655,17 @@
 ** the resulting time into the DateTime structure p.  Return 0
 ** on success and 1 if there are any errors.
 */
-static int isDate(int argc, sqlite3_value **argv, DateTime *p){
+static int isDate(
+  sqlite3_context *context, 
+  int argc, 
+  sqlite3_value **argv, 
+  DateTime *p
+){
   int i;
   const unsigned char *z;
   if( argc==0 ) return 1;
-  if( (z = sqlite3_value_text(argv[0]))==0 || parseDateOrTime((char*)z, p) ){
+  z = sqlite3_value_text(argv[0]);
+  if( !z || parseDateOrTime(context, (char*)z, p) ){
     return 1;
   }
   for(i=1; i<argc; i++){
@@ -683,7 +693,7 @@
   sqlite3_value **argv
 ){
   DateTime x;
-  if( isDate(argc, argv, &x)==0 ){
+  if( isDate(context, argc, argv, &x)==0 ){
     computeJD(&x);
     sqlite3_result_double(context, x.rJD);
   }
@@ -700,7 +710,7 @@
   sqlite3_value **argv
 ){
   DateTime x;
-  if( isDate(argc, argv, &x)==0 ){
+  if( isDate(context, argc, argv, &x)==0 ){
     char zBuf[100];
     computeYMD_HMS(&x);
     sqlite3_snprintf(sizeof(zBuf), zBuf, "%04d-%02d-%02d %02d:%02d:%02d",
@@ -720,7 +730,7 @@
   sqlite3_value **argv
 ){
   DateTime x;
-  if( isDate(argc, argv, &x)==0 ){
+  if( isDate(context, argc, argv, &x)==0 ){
     char zBuf[100];
     computeHMS(&x);
     sqlite3_snprintf(sizeof(zBuf), zBuf, "%02d:%02d:%02d", x.h, x.m, (int)x.s);
@@ -739,7 +749,7 @@
   sqlite3_value **argv
 ){
   DateTime x;
-  if( isDate(argc, argv, &x)==0 ){
+  if( isDate(context, argc, argv, &x)==0 ){
     char zBuf[100];
     computeYMD(&x);
     sqlite3_snprintf(sizeof(zBuf), zBuf, "%04d-%02d-%02d", x.Y, x.M, x.D);
@@ -777,7 +787,7 @@
   char *z;
   const char *zFmt = (const char*)sqlite3_value_text(argv[0]);
   char zBuf[100];
-  if( zFmt==0 || isDate(argc-1, argv+1, &x) ) return;
+  if( zFmt==0 || isDate(context, argc-1, argv+1, &x) ) return;
   for(i=0, n=1; zFmt[i]; i++, n++){
     if( zFmt[i]=='%' ){
       switch( zFmt[i+1] ){
@@ -979,10 +989,10 @@
 #else
   {
     struct tm *pTm;
-    sqlite3OsEnterMutex();
+    sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_GLOBAL));
     pTm = gmtime(&t);
     strftime(zBuf, 20, zFormat, pTm);
-    sqlite3OsLeaveMutex();
+    sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_GLOBAL));
   }
 #endif
 
@@ -1015,7 +1025,7 @@
 
   for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
     sqlite3CreateFunc(db, aFuncs[i].zName, aFuncs[i].nArg,
-        SQLITE_UTF8, 0, aFuncs[i].xFunc, 0, 0);
+        SQLITE_UTF8, (void *)(db->pVfs), aFuncs[i].xFunc, 0, 0);
   }
 #else
   static const struct {
diff --git a/src/main.c b/src/main.c
index b3eab17..9db08c4 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.384 2007/08/17 15:53:36 danielk1977 Exp $
+** $Id: main.c,v 1.385 2007/08/18 10:59:20 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -1378,7 +1378,11 @@
 int sqlite3_sleep(int ms){
   sqlite3_vfs *pVfs;
   pVfs = sqlite3_find_vfs(0);
-  return sqlite3OsSleep(pVfs, 1000*ms);
+
+  /* This function works in milliseconds, but the underlying OsSleep() 
+  ** API uses microseconds. Hence the 1000's.
+  */
+  return (sqlite3OsSleep(pVfs, 1000*ms)/1000);
 }
 
 /*
diff --git a/src/os.c b/src/os.c
index ed5c98e..f7aedd7 100644
--- a/src/os.c
+++ b/src/os.c
@@ -83,8 +83,8 @@
 ){
   return pVfs->xOpen(pVfs->pAppData, zPath, pFile, flags, pFlagsOut);
 }
-int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath){
-  return pVfs->xDelete(pVfs->pAppData, zPath);
+int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
+  return pVfs->xDelete(pVfs->pAppData, zPath, dirSync);
 }
 int sqlite3OsAccess(sqlite3_vfs *pVfs, const char *zPath, int flags){
   return pVfs->xAccess(pVfs->pAppData, zPath, flags);
diff --git a/src/os.h b/src/os.h
index e37ac40..fadf1c8 100644
--- a/src/os.h
+++ b/src/os.h
@@ -243,7 +243,7 @@
 ** Functions for accessing sqlite3_vfs methods 
 */
 int sqlite3OsOpen(sqlite3_vfs *, const char *, sqlite3_file*, int, int *);
-int sqlite3OsDelete(sqlite3_vfs *, const char *);
+int sqlite3OsDelete(sqlite3_vfs *, const char *, int);
 int sqlite3OsAccess(sqlite3_vfs *, const char *, int);
 int sqlite3OsGetTempName(sqlite3_vfs *, char *);
 int sqlite3OsFullPathname(sqlite3_vfs *, const char *, char *);
diff --git a/src/os_unix.c b/src/os_unix.c
index 00eb2f2..6200ac1 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -2504,6 +2504,7 @@
 #else /* SQLITE_ENABLE_LOCKING_STYLE */
 static int fillInUnixFile(
   int h,                 /* Open file descriptor on file being opened */
+  int dirfd,
   sqlite3_file *pId,     /* Write to the unixFile structure here */
   const char *zFilename  /* Name of the file being opened */
 ){
@@ -2525,6 +2526,7 @@
   OSTRACE3("OPEN    %-3d %s\n", h, zFilename);
   pNew->dirfd = -1;
   pNew->h = h;
+  pNew->dirfd = dirfd;
   SET_THREADID(pNew);
 
   pNew->pMethod = &sqlite3UnixIoMethod;
@@ -2539,6 +2541,33 @@
 ** with other miscellanous aspects of the operating system interface
 ****************************************************************************/
 
+static int openDirectory(const char *zFilename, int *pFd){
+  char *zDirname;
+  int ii;
+  int fd;
+
+  zDirname = (char *)sqlite3_malloc(MAX_PATHNAME);
+  if( !zDirname ){
+    return SQLITE_NOMEM;
+  }
+  strncpy(zDirname, zFilename, MAX_PATHNAME);
+  zDirname[MAX_PATHNAME-1] = '\0';
+  for(ii=strlen(zDirname); ii>=0 && zDirname[ii]!='/'; ii--);
+  if( ii>0 ){
+    zDirname[ii] = '\0';
+    fd = open(zDirname, O_RDONLY|O_BINARY, 0);
+    if( fd>0 ){
+#ifdef FD_CLOEXEC
+      fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
+#endif
+      OSTRACE3("OPENDIR %-3d %s\n", fd, zDirname);
+    }
+  }
+  sqlite3_free(zDirname);
+  *pFd = fd;
+  return (fd>0?SQLITE_OK:SQLITE_CANTOPEN);
+}
+
 /*
 ** Previously, the SQLite OS layer used three functions in place of this
 ** one:
@@ -2566,8 +2595,10 @@
   int flags,
   int *pOutFlags
 ){
-  int fd = 0;
-  int oflags = 0;
+  int fd = 0;                    /* File descriptor returned by open() */
+  int dirfd = -1;                /* Directory file descriptor */
+  int oflags = 0;                /* Flags to pass to open() */
+  int eType = flags&0xFFFFFF00;  /* Type of file to open */
 
   int isExclusive  = (flags & SQLITE_OPEN_EXCLUSIVE);
   int isDelete     = (flags & SQLITE_OPEN_DELETEONCLOSE);
@@ -2575,15 +2606,30 @@
   int isReadonly   = (flags & SQLITE_OPEN_READONLY);
   int isReadWrite  = (flags & SQLITE_OPEN_READWRITE);
 
-  /* Exactly one of the READWRITE and READONLY flags must be set */
+  /* If creating a master or main-file journal, this function will open
+  ** a file-descriptor on the directory too. The first time unixSync()
+  ** is called the directory file descriptor will be fsync()ed and close()d.
+  */
+  int isOpenDirectory = (isCreate && 
+      (eType==SQLITE_OPEN_MASTER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL)
+  );
+
+  /* Check the following statements are true: 
+  **
+  **   (a) Exactly one of the READWRITE and READONLY flags must be set, and 
+  **   (b) if CREATE is set, then READWRITE must also be set, and
+  **   (c) if EXCLUSIVE is set, then CREATE must also be set.
+  */
   assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly));
-
-  /* If isCreate is true, then the file must be opened for read/write access. */
   assert(isCreate==0 || isReadWrite);
-
-  /* If isExclusive is true, then isCreate must also be true */
   assert(isExclusive==0 || isCreate);
 
+  /* Assert that the upper layer has set one of the "file-type" flags. */
+  assert( eType==SQLITE_OPEN_MAIN_DB      || eType==SQLITE_OPEN_TEMP_DB 
+       || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL 
+       || eType==SQLITE_OPEN_SUBJOURNAL   || eType==SQLITE_OPEN_MASTER_JOURNAL 
+  );
+
   if( isReadonly )  oflags |= O_RDONLY;
   if( isReadWrite ) oflags |= O_RDWR;
   if( isCreate )    oflags |= O_CREAT;
@@ -2609,16 +2655,35 @@
   }
 
   assert(fd!=0);
-  return fillInUnixFile(fd, pFile, zPath);
+  if( isOpenDirectory ){
+    int rc = openDirectory(zPath, &dirfd);
+    if( rc!=SQLITE_OK ){
+      close(fd);
+      return rc;
+    }
+  }
+  return fillInUnixFile(fd, dirfd, pFile, zPath);
 }
 
 /*
-** Delete the file at zPath.
+** Delete the file at zPath. If the dirSync argument is true, fsync()
+** the directory after deleting the file.
 */
-static int unixDelete(void *pNotUsed, const char *zPath){
+static int unixDelete(void *pNotUsed, const char *zPath, int dirSync){
+  int rc = SQLITE_OK;
   SimulateIOError(return SQLITE_IOERR_DELETE);
   unlink(zPath);
-  return SQLITE_OK;
+  if( dirSync ){
+    int fd;
+    rc = openDirectory(zPath, &fd);
+    if( rc==SQLITE_OK ){
+      if( fsync(fd) ){
+        rc = SQLITE_IOERR_DIR_FSYNC;
+      }
+      close(fd);
+    }
+  }
+  return rc;
 }
 
 /*
diff --git a/src/pager.c b/src/pager.c
index 5fbedba..8100de2 100644
--- a/src/pager.c
+++ b/src/pager.c
@@ -18,7 +18,7 @@
 ** file simultaneously, or one process from reading the database while
 ** another is writing.
 **
-** @(#) $Id: pager.c,v 1.359 2007/08/17 15:53:37 danielk1977 Exp $
+** @(#) $Id: pager.c,v 1.360 2007/08/18 10:59:20 danielk1977 Exp $
 */
 #ifndef SQLITE_OMIT_DISKIO
 #include "sqliteInt.h"
@@ -1024,7 +1024,7 @@
       sqlite3OsClose(pPager->jfd);
       pPager->journalOpen = 0;
       if( rc==SQLITE_OK ){
-        rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal);
+        rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
       }
     }
     sqlite3_free( pPager->aInJournal );
@@ -1239,11 +1239,12 @@
   ** is running this routine also. Not that it makes too much difference.
   */
   pMaster = (sqlite3_file *)sqlite3_malloc(pVfs->szOsFile * 2);
+  pJournal = (sqlite3_file *)(((u8 *)pMaster) + pVfs->szOsFile);
   if( !pMaster ){
     rc = SQLITE_NOMEM;
   }else{
-    pJournal = (sqlite3_file *)(((u8 *)pMaster) + pVfs->szOsFile);
-    rc = sqlite3OsOpen(pVfs, zMaster, pMaster, SQLITE_OPEN_READONLY, 0);
+    int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MASTER_JOURNAL);
+    rc = sqlite3OsOpen(pVfs, zMaster, pMaster, flags, 0);
   }
   if( rc!=SQLITE_OK ) goto delmaster_out;
   master_open = 1;
@@ -1274,8 +1275,8 @@
         ** so, return without deleting the master journal file.
         */
         int c;
-
-        rc = sqlite3OsOpen(pVfs, zJournal, pJournal, SQLITE_OPEN_READONLY, 0);
+        int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL);
+        rc = sqlite3OsOpen(pVfs, zJournal, pJournal, flags, 0);
         if( rc!=SQLITE_OK ){
           goto delmaster_out;
         }
@@ -1297,7 +1298,7 @@
     }
   }
   
-  rc = sqlite3OsDelete(pVfs, zMaster);
+  rc = sqlite3OsDelete(pVfs, zMaster, 0);
 
 delmaster_out:
   if( zMasterJournal ){
@@ -1687,10 +1688,11 @@
 ** Open a temporary file. 
 **
 ** Write the file descriptor into *fd.  Return SQLITE_OK on success or some
-** other error code if we fail.
+** other error code if we fail. The OS will automatically delete the temporary
+** file when it is closed.
 **
-** The OS will automatically delete the temporary file when it is
-** closed.
+** If zNameOut is 0, then SQLITE_OPEN_SUBJOURNAL is passed to the OS layer.
+** If zNameOut is not 0, SQLITE_OPEN_TEMP_DB is passed.
 */
 static int sqlite3PagerOpentemp(
   sqlite3_vfs *pVfs, 
@@ -1708,6 +1710,9 @@
       return SQLITE_NOMEM;
     }
     zNameOut = zFree;
+    flags |= SQLITE_OPEN_SUBJOURNAL;
+  }else{
+    flags |= SQLITE_OPEN_TEMP_DB;
   }
 
 #ifdef SQLITE_TEST
@@ -1811,9 +1816,10 @@
         if( strlen(pPager->zFilename)>(pVfs->mxPathname - strlen("-journal")) ){
           rc = SQLITE_CANTOPEN;
         }else{
-          int flag = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
+          int oflag = 
+              (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_MAIN_DB);
           int fout = 0;
-          rc = sqlite3OsOpen(pVfs, pPager->zFilename, pPager->fd, flag, &fout);
+          rc = sqlite3OsOpen(pVfs, pPager->zFilename, pPager->fd, oflag, &fout);
           readOnly = (fout&SQLITE_OPEN_READONLY);
         }
       }
@@ -2624,7 +2630,7 @@
     return 0;
   }
   if( sqlite3PagerPagecount(pPager)==0 ){
-    sqlite3OsDelete(pVfs, pPager->zJournal);
+    sqlite3OsDelete(pVfs, pPager->zJournal, 0);
     return 0;
   }else{
     return 1;
@@ -2906,7 +2912,7 @@
         rc = SQLITE_BUSY;
         if( sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS) ){
           int fout = 0;
-          int flags = SQLITE_OPEN_READWRITE;
+          int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_JOURNAL;
           assert( !pPager->tempFile );
           rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags, &fout);
           assert( rc!=SQLITE_OK || pPager->jfd->pMethods );
@@ -3352,7 +3358,9 @@
   }
 
   if( pPager->tempFile ){
-    flags |= SQLITE_OPEN_DELETEONCLOSE;
+    flags |= (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL);
+  }else{
+    flags |= (SQLITE_OPEN_MAIN_JOURNAL);
   }
   rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags, 0);
   assert( rc!=SQLITE_OK || pPager->jfd->pMethods );
@@ -3361,14 +3369,13 @@
   pPager->journalHdr = 0;
   if( rc!=SQLITE_OK ){
     if( rc==SQLITE_NOMEM ){
-      sqlite3OsDelete(pVfs, pPager->zJournal);
+      sqlite3OsDelete(pVfs, pPager->zJournal, 0);
     }
     goto failed_to_open_journal;
   }
 #if 0
   sqlite3OsSetFullSync(pPager->jfd, pPager->full_fsync);
   sqlite3OsSetFullSync(pPager->fd, pPager->full_fsync);
-  sqlite3OsOpenDirectory(pPager->jfd, pPager->zDirectory);
 #endif
   pPager->journalOpen = 1;
   pPager->journalStarted = 0;
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 02d6cd4..55f2a50 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -30,7 +30,7 @@
 ** the version number) and changes its name to "sqlite3.h" as
 ** part of the build process.
 **
-** @(#) $Id: sqlite.h.in,v 1.229 2007/08/17 16:50:38 danielk1977 Exp $
+** @(#) $Id: sqlite.h.in,v 1.230 2007/08/18 10:59:21 danielk1977 Exp $
 */
 #ifndef _SQLITE3_H_
 #define _SQLITE3_H_
@@ -641,7 +641,7 @@
   void *pAppData;          /* Application context */
   int (*xOpen)(void *pAppData, const char *zName, sqlite3_file*,
                int flags, int *pOutFlags);
-  int (*xDelete)(void *pAppData, const char *zName);
+  int (*xDelete)(void *pAppData, const char *zName, int syncDir);
   int (*xAccess)(void *pAppData, const char *zName, int flags);
   int (*xGetTempName)(void *pAppData, char *zOut);
   int (*xFullPathname)(void *pAppData, const char *zName, char *zOut);
diff --git a/src/test2.c b/src/test2.c
index a45d60c..d6dfa75 100644
--- a/src/test2.c
+++ b/src/test2.c
@@ -13,7 +13,7 @@
 ** is not included in the SQLite library.  It is used for automated
 ** testing of the SQLite library.
 **
-** $Id: test2.c,v 1.46 2007/08/17 15:53:37 danielk1977 Exp $
+** $Id: test2.c,v 1.47 2007/08/18 10:59:21 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -530,7 +530,6 @@
 ){
   sqlite3_vfs *pVfs;
   sqlite3_file *fd = 0;
-  int flags = SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE;
   int rc;
   int n;
   i64 offset;
@@ -542,7 +541,9 @@
   if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
 
   pVfs = sqlite3_find_vfs(0);
-  rc = sqlite3OsOpenMalloc(pVfs, argv[2], &fd, flags);
+  rc = sqlite3OsOpenMalloc(pVfs, argv[2], &fd, 
+      (SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB)
+  );
   if( rc ){
     Tcl_AppendResult(interp, "open failed: ", errorName(rc), 0);
     return TCL_ERROR;
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index 3771296..cfd234a 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -1133,7 +1133,6 @@
 #ifndef SQLITE_OMIT_DISKIO
   else{
     sqlite3_vfs *pVfs = db->pVfs;
-    int flag = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_EXCLUSIVE);
     int needSync = 0;
     char *zMaster = 0;   /* File-name for the master journal */
     char const *zMainFile = sqlite3BtreeGetFilename(db->aDb[0].pBt);
@@ -1152,11 +1151,12 @@
     }while( sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS) );
 
     /* Open the master journal. */
-    pMaster = sqlite3_malloc(pVfs->szOsFile);
-    rc = sqlite3OsOpen(pVfs, zMaster, pMaster, flag, 0);
+    rc = sqlite3OsOpenMalloc(pVfs, zMaster, &pMaster, 
+        SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|
+        SQLITE_OPEN_EXCLUSIVE|SQLITE_OPEN_MASTER_JOURNAL
+    );
     if( rc!=SQLITE_OK ){
       sqlite3_free(zMaster);
-      sqlite3_free(pMaster);
       return rc;
     }
  
@@ -1178,10 +1178,9 @@
         rc = sqlite3OsWrite(pMaster, zFile, strlen(zFile)+1, offset);
         offset += strlen(zFile)+1;
         if( rc!=SQLITE_OK ){
-          sqlite3OsClose(pMaster);
-          sqlite3OsDelete(pVfs, zMaster);
+          sqlite3OsCloseFree(pMaster);
+          sqlite3OsDelete(pVfs, zMaster, 0);
           sqlite3_free(zMaster);
-          sqlite3_free(pMaster);
           return rc;
         }
       }
@@ -1192,16 +1191,12 @@
     ** the master journal file is store in so that it gets synced too.
     */
     zMainFile = sqlite3BtreeGetDirname(db->aDb[0].pBt);
-#if 0
-    rc = sqlite3OsOpenDirectory(master, zMainFile);
-    if( rc!=SQLITE_OK ||
-          (needSync && (rc=sqlite3OsSync(master,0))!=SQLITE_OK) ){
-      sqlite3OsClose(&master);
-      sqlite3OsDelete(zMaster);
+    if( (needSync && (rc=sqlite3OsSync(pMaster,0))!=SQLITE_OK) ){
+      sqlite3OsCloseFree(pMaster);
+      sqlite3OsDelete(pVfs, zMaster, 0);
       sqlite3_free(zMaster);
       return rc;
     }
-#endif
 
     /* Sync all the db files involved in the transaction. The same call
     ** sets the master journal pointer in each individual journal. If
@@ -1219,10 +1214,9 @@
         rc = sqlite3BtreeCommitPhaseOne(pBt, zMaster);
       }
     }
-    sqlite3OsClose(pMaster);
+    sqlite3OsCloseFree(pMaster);
     if( rc!=SQLITE_OK ){
       sqlite3_free(zMaster);
-      sqlite3_free(pMaster);
       return rc;
     }
 
@@ -1230,27 +1224,12 @@
     ** doing this the directory is synced again before any individual
     ** transaction files are deleted.
     */
-    rc = sqlite3OsDelete(pVfs, zMaster);
+    rc = sqlite3OsDelete(pVfs, zMaster, 1);
     sqlite3_free(zMaster);
-    sqlite3_free(pMaster);
     zMaster = 0;
-    pMaster = 0;
     if( rc ){
       return rc;
     }
-#if 0
-    rc = sqlite3OsSyncDirectory(zMainFile);
-#endif
-    if( rc!=SQLITE_OK ){
-      /* This is not good. The master journal file has been deleted, but
-      ** the directory sync failed. There is no completely safe course of
-      ** action from here. The individual journals contain the name of the
-      ** master journal file, but there is no way of knowing if that
-      ** master journal exists now or if it will exist after the operating
-      ** system crash that may follow the fsync() failure.
-      */
-      return rc;
-    }
 
     /* All files and directories have already been synced, so the following
     ** calls to sqlite3BtreeCommitPhaseTwo() are only closing files and