diff --git a/manifest b/manifest index 3fdaf001f0..93d8d90723 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Make\ssure\sthe\sschema\sloader\scallback\scan\shandle\sEMPTY_RESULT_CALLBACKS\sbeing\non.\s\sTicket\s#406.\s(CVS\s1065) -D 2003-07-27T17:26:23 +C When\screating\sa\snew\sjournal\sfile,\sopen\sa\s(read-only)\sfile\sdescriptor\son\sthe\ndirectory\scontaining\sthe\sjournal\sand\ssync\sthat\sdirectory\sonce\sto\smake\ssure\nthat\sthe\sjournal\sfilename\sentry\sgets\sinto\sthe\sdirectory.\s\sTicket\s#410.\s(CVS\s1066) +D 2003-07-27T18:59:43 F Makefile.in 9ad23ed4ca97f9670c4496432e3fbd4b3760ebde F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -35,9 +35,9 @@ F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8 F src/insert.c fc4c26a0bb505fb802babfb9a7b7a1d4be2e3061 F src/main.c 2500392bad5629b6d70b06ac5a076958acb49b92 F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565 -F src/os.c 2f24ede4d3464ac38d24d113e0d44d3c7d460be4 -F src/os.h 9e5bbddff123187295e3d00d49af06192cd1cd49 -F src/pager.c 9512e789dbd5acaf91e74c4665e03c2734d3da25 +F src/os.c b0ae51da6e2ec7dd9f48f92ac88985d5fde8c1d5 +F src/os.h 8aed1c928449433acf19d30f76bc86d549041167 +F src/pager.c a4fd3a61d63879365f775875edfffaa8c6f3d7f8 F src/pager.h 5da62c83443f26b1792cfd72c96c422f91aadd31 F src/parse.y 16aed0e3ed05445fa7f6a4209cc054208c7083c0 F src/pragma.c 3b4f5a800e7a2145bc1930f323232e297d4eb782 @@ -168,7 +168,7 @@ F www/speed.tcl 2f6b1155b99d39adb185f900456d1d592c4832b3 F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331 F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1 -P 7514c3db165e8cc5c696b2b345844949a0e45a61 -R 85b9f91d179fe7af6d0cda86f9bcda89 +P 8c163fc0c7c721b7a5fa6727b0e90bff4484c782 +R 8fa888001788f8c7b2a2f5a0b6144c1c U drh -Z 4a83ca4578ca29e5406602c40689d847 +Z 5beb2c4636d8c2b6025132999d440be1 diff --git a/manifest.uuid b/manifest.uuid index 79e163d533..da11a89885 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8c163fc0c7c721b7a5fa6727b0e90bff4484c782 \ No newline at end of file +09c10fe3c99cffc64ed02c2929f206d99c8e3309 \ No newline at end of file diff --git a/src/os.c b/src/os.c index cca4ac48dc..2e3fdddbc6 100644 --- a/src/os.c +++ b/src/os.c @@ -326,6 +326,7 @@ int sqliteOsOpenReadWrite( int *pReadonly ){ #if OS_UNIX + 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); @@ -450,6 +451,7 @@ int sqliteOsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){ 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 ){ @@ -536,6 +538,7 @@ int sqliteOsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){ */ int sqliteOsOpenReadOnly(const char *zFilename, OsFile *id){ #if OS_UNIX + id->dirfd = -1; id->fd = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY); if( id->fd<0 ){ return SQLITE_CANTOPEN; @@ -597,6 +600,42 @@ int sqliteOsOpenReadOnly(const char *zFilename, OsFile *id){ #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 sqliteOsOpenDirectory( + 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. @@ -706,6 +745,8 @@ int sqliteOsTempFileName(char *zBuf){ int sqliteOsClose(OsFile *id){ #if OS_UNIX close(id->fd); + if( id->dirfd>=0 ) close(id->dirfd); + id->dirfd = -1; sqliteOsEnterMutex(); releaseLockInfo(id->pLock); sqliteOsLeaveMutex(); @@ -892,6 +933,14 @@ int sqliteOsSeek(OsFile *id, off_t offset){ /* ** 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 sqliteOsSync(OsFile *id){ #if OS_UNIX @@ -900,6 +949,12 @@ int sqliteOsSync(OsFile *id){ 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 diff --git a/src/os.h b/src/os.h index d7674267d7..f47046ce13 100644 --- a/src/os.h +++ b/src/os.h @@ -104,6 +104,7 @@ struct lockInfo *pLock; /* Information about locks on this inode */ int fd; /* The file descriptor */ int locked; /* True if this user holds the lock */ + int dirfd; /* File descriptor for the directory */ }; # define SQLITE_TEMPNAME_SIZE 200 # if defined(HAVE_USLEEP) && HAVE_USLEEP @@ -156,6 +157,7 @@ int sqliteOsFileRename(const char*, const char*); int sqliteOsOpenReadWrite(const char*, OsFile*, int*); int sqliteOsOpenExclusive(const char*, OsFile*, int); int sqliteOsOpenReadOnly(const char*, OsFile*); +int sqliteOsOpenDirectory(const char*, OsFile*); int sqliteOsTempFileName(char*); int sqliteOsClose(OsFile*); int sqliteOsRead(OsFile*, void*, int amt); diff --git a/src/pager.c b/src/pager.c index 66c3615973..f470c0dd66 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.86 2003/07/07 10:47:10 drh Exp $ +** @(#) $Id: pager.c,v 1.87 2003/07/27 18:59:43 drh Exp $ */ #include "os.h" /* Must be first to enable large file support */ #include "sqliteInt.h" @@ -129,6 +129,7 @@ struct PgHdr { struct Pager { char *zFilename; /* Name of the database file */ char *zJournal; /* Name of the journal file */ + char *zDirectory; /* Directory hold database and journal files */ OsFile fd, jfd; /* File descriptors for database and journal */ OsFile cpfd; /* File descriptor for the checkpoint journal */ int dbSize; /* Number of pages in the file */ @@ -828,7 +829,7 @@ int sqlitepager_open( char *zFullPathname; int nameLen; OsFile fd; - int rc; + int rc, i; int tempFile; int readOnly = 0; char zTemp[SQLITE_TEMPNAME_SIZE]; @@ -855,7 +856,7 @@ int sqlitepager_open( return SQLITE_CANTOPEN; } nameLen = strlen(zFullPathname); - pPager = sqliteMalloc( sizeof(*pPager) + nameLen*2 + 30 ); + pPager = sqliteMalloc( sizeof(*pPager) + nameLen*3 + 30 ); if( pPager==0 ){ sqliteOsClose(&fd); sqliteFree(zFullPathname); @@ -863,8 +864,12 @@ int sqlitepager_open( } SET_PAGER(pPager); pPager->zFilename = (char*)&pPager[1]; - pPager->zJournal = &pPager->zFilename[nameLen+1]; + pPager->zDirectory = &pPager->zFilename[nameLen+1]; + pPager->zJournal = &pPager->zDirectory[nameLen+1]; strcpy(pPager->zFilename, zFullPathname); + strcpy(pPager->zDirectory, zFullPathname); + for(i=nameLen; i>0 && pPager->zDirectory[i-1]!='/'; i--){} + if( i>0 ) pPager->zDirectory[i-1] = 0; strcpy(pPager->zJournal, zFullPathname); sqliteFree(zFullPathname); strcpy(&pPager->zJournal[nameLen], "-journal"); @@ -995,8 +1000,10 @@ int sqlitepager_close(Pager *pPager){ */ CLR_PAGER(pPager); if( pPager->zFilename!=(char*)&pPager[1] ){ + assert( 0 ); /* Cannot happen */ sqliteFree(pPager->zFilename); sqliteFree(pPager->zJournal); + sqliteFree(pPager->zDirectory); } sqliteFree(pPager); return SQLITE_OK; @@ -1535,6 +1542,7 @@ static int pager_open_journal(Pager *pPager){ pPager->state = SQLITE_READLOCK; return SQLITE_CANTOPEN; } + sqliteOsOpenDirectory(pPager->zDirectory, &pPager->jfd); pPager->journalOpen = 1; pPager->journalStarted = 0; pPager->needSync = 0;