From 60f21e4b6ee9964bd08ff65b4896adf6e39b36f9 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 1 Dec 2011 18:44:21 +0000 Subject: [PATCH 01/11] Add stdio-like I/O interfaces to the test_quota VFS. This is a prototype change for discussion and is mostly untested. This is an alternative to adding stdio-like I/O interfaces in the core. There is no guarantee that this code will make it into the trunk. If it does get to trunk, there could be many changes to the interface first. FossilOrigin-Name: bd3ce723f1b5be52be46ede8614ca316f56e7e6f --- manifest | 16 ++-- manifest.uuid | 2 +- src/test_quota.c | 206 ++++++++++++++++++++++++++++++++++++++++++----- src/test_quota.h | 158 ++++++++++++++++++++++++++++++++++++ 4 files changed, 354 insertions(+), 28 deletions(-) create mode 100644 src/test_quota.h diff --git a/manifest b/manifest index ef7ae4ea60..cade689e9a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\sunused\sfields\sfrom\sthe\sParse\sobject.\s\sDocumentation\sand\sformatting\nimprovements\son\sdata\sstructure\sdefinitions. -D 2011-11-29T15:40:32.491 +C Add\sstdio-like\sI/O\sinterfaces\sto\sthe\stest_quota\sVFS.\s\sThis\sis\sa\sprototype\nchange\sfor\sdiscussion\sand\sis\smostly\suntested.\s\sThis\sis\san\salternative\sto\nadding\sstdio-like\sI/O\sinterfaces\sin\sthe\score.\s\sThere\sis\sno\sguarantee\sthat\nthis\scode\swill\smake\sit\sinto\sthe\strunk.\s\sIf\sit\sdoes\sget\sto\strunk,\sthere\ncould\sbe\smany\schanges\sto\sthe\sinterface\sfirst. +D 2011-12-01T18:44:21.630 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5b4a3e12a850b021547e43daf886b25133b44c07 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -220,7 +220,8 @@ F src/test_mutex.c a6bd7b9cf6e19d989e31392b06ac8d189f0d573e F src/test_onefile.c 40cf9e212a377a6511469384a64b01e6e34b2eec F src/test_osinst.c 62b0b8ef21ce754cc94e17bb42377ed8795dba32 F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00 -F src/test_quota.c a391c866217e92986c6f523f05b08aa6956c8419 +F src/test_quota.c f3ed8e130fff8e824a320a80668cfaffd6cb55ff +F src/test_quota.h 118dba604ae5b6903acdd40d2b94a1f319047612 F src/test_rtree.c 6d06306e29946dc36f528a3a2cdc3add794656f1 F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0 F src/test_server.c 2f99eb2837dfa06a4aacf24af24c6affdf66a84f @@ -976,7 +977,10 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P b10d091ec02e94643e865743129e2a21147b3136 -R 7d0a9d11e01c28eaf1d831b1553005fb +P 431556cac0b2c86d7f6a60412ff1023feeaafedf +R e31672c1519f90c43111109b685a8ffb +T *branch * quota-stdio +T *sym-quota-stdio * +T -sym-trunk * U drh -Z fa710425b85d2a4b5e2c971fb970b087 +Z 0283eb6e7b14cfb0e1559cbc303ec8df diff --git a/manifest.uuid b/manifest.uuid index b014af186d..f43d772bdb 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -431556cac0b2c86d7f6a60412ff1023feeaafedf \ No newline at end of file +bd3ce723f1b5be52be46ede8614ca316f56e7e6f \ No newline at end of file diff --git a/src/test_quota.c b/src/test_quota.c index 74d1a6d3ba..1866e79986 100644 --- a/src/test_quota.c +++ b/src/test_quota.c @@ -27,7 +27,7 @@ ** files within the group is less than the new quota, then the write ** continues as if nothing had happened. */ -#include "sqlite3.h" +#include "test_quota.h" #include #include @@ -111,6 +111,18 @@ struct quotaConn { /* The underlying VFS sqlite3_file is appended to this object */ }; +/* +** An instance of the following object records the state of an +** open file. This object is opaque to all users - the internal +** structure is only visible to the functions below. +*/ +struct quota_FILE { + FILE *f; /* Open stdio file pointer */ + sqlite3_int64 iOfst; /* Current offset into the file */ + quotaFile *pFile; /* The file record in the quota system */ +}; + + /************************* Global Variables **********************************/ /* ** All global variables used by this file are containing within the following @@ -313,11 +325,29 @@ static sqlite3_file *quotaSubOpen(sqlite3_file *pConn){ /* Find a file in a quota group and return a pointer to that file. ** Return NULL if the file is not in the group. */ -static quotaFile *quotaFindFile(quotaGroup *pGroup, const char *zName){ +static quotaFile *quotaFindFile( + quotaGroup *pGroup, /* Group in which to look for the file */ + const char *zName, /* Full pathname of the file */ + int createFlag /* Try to create the file if not found */ +){ quotaFile *pFile = pGroup->pFiles; while( pFile && strcmp(pFile->zFilename, zName)!=0 ){ pFile = pFile->pNext; } + if( pFile==0 && createFlag ){ + int nName = strlen(zName); + pFile = (quotaFile *)sqlite3_malloc( sizeof(*pFile) + nName + 1 ); + if( pFile ){ + memset(pFile, 0, sizeof(*pFile)); + pFile->zFilename = (char*)&pFile[1]; + memcpy(pFile->zFilename, zName, nName+1); + pFile->pNext = pGroup->pFiles; + if( pGroup->pFiles ) pGroup->pFiles->ppPrev = &pFile->pNext; + pFile->ppPrev = &pGroup->pFiles; + pGroup->pFiles = pFile; + pFile->pGroup = pGroup; + } + } return pFile; } @@ -364,25 +394,13 @@ static int quotaOpen( pSubOpen = quotaSubOpen(pConn); rc = pOrigVfs->xOpen(pOrigVfs, zName, pSubOpen, flags, pOutFlags); if( rc==SQLITE_OK ){ - pFile = quotaFindFile(pGroup, zName); + pFile = quotaFindFile(pGroup, zName, 1); if( pFile==0 ){ - int nName = strlen(zName); - pFile = (quotaFile *)sqlite3_malloc( sizeof(*pFile) + nName + 1 ); - if( pFile==0 ){ - quotaLeave(); - pSubOpen->pMethods->xClose(pSubOpen); - return SQLITE_NOMEM; - } - memset(pFile, 0, sizeof(*pFile)); - pFile->zFilename = (char*)&pFile[1]; - memcpy(pFile->zFilename, zName, nName+1); - pFile->pNext = pGroup->pFiles; - if( pGroup->pFiles ) pGroup->pFiles->ppPrev = &pFile->pNext; - pFile->ppPrev = &pGroup->pFiles; - pGroup->pFiles = pFile; - pFile->pGroup = pGroup; - pFile->deleteOnClose = (flags & SQLITE_OPEN_DELETEONCLOSE)!=0; + quotaLeave(); + pSubOpen->pMethods->xClose(pSubOpen); + return SQLITE_NOMEM; } + pFile->deleteOnClose = (flags & SQLITE_OPEN_DELETEONCLOSE)!=0; pFile->nRef++; pQuotaOpen->pFile = pFile; if( pSubOpen->pMethods->iVersion==1 ){ @@ -423,7 +441,7 @@ static int quotaDelete( quotaEnter(); pGroup = quotaGroupFind(zName); if( pGroup ){ - pFile = quotaFindFile(pGroup, zName); + pFile = quotaFindFile(pGroup, zName, 0); if( pFile ){ if( pFile->nRef ){ pFile->deleteOnClose = 1; @@ -823,7 +841,7 @@ int sqlite3_quota_file(const char *zFilename){ quotaEnter(); pGroup = quotaGroupFind(zFull); if( pGroup ){ - pFile = quotaFindFile(pGroup, zFull); + pFile = quotaFindFile(pGroup, zFull, 0); if( pFile ) quotaRemoveFile(pFile); } quotaLeave(); @@ -832,6 +850,152 @@ int sqlite3_quota_file(const char *zFilename){ return rc; } +/* +** Open a potentially quotaed file for I/O. +*/ +quota_FILE *sqlite3_quota_fopen(const char *zFilename, const char *zMode){ + quota_FILE *p = 0; + char *zFull = 0; + int rc; + quotaGroup *pGroup; + quotaFile *pFile; + + p = sqlite3_malloc(gQuota.sThisVfs.mxPathname + 1); + if( p==0 ) return 0; + zFull = (char*)&p[1]; + rc = gQuota.pOrigVfs->xFullPathname(gQuota.pOrigVfs, zFilename, + gQuota.sThisVfs.mxPathname+1, zFull); + if( rc ) goto quota_fopen_error; + p = sqlite3_malloc(sizeof(*p)); + if( p==0 ) goto quota_fopen_error; + memset(p, 0, sizeof(*p)); + p->f = fopen(zFull, zMode); + if( p->f==0 ) goto quota_fopen_error; + quotaEnter(); + pGroup = quotaGroupFind(zFull); + if( pGroup ){ + pFile = quotaFindFile(pGroup, zFull, 1); + if( pFile==0 ){ + quotaLeave(); + goto quota_fopen_error; + } + pFile->nRef++; + p->pFile = pFile; + } + quotaLeave(); + sqlite3_free(zFull); + return p; + +quota_fopen_error: + sqlite3_free(zFull); + if( p && p->f ) fclose(p->f); + sqlite3_free(p); + return 0; +} + +/* +** Read content from a quota_FILE +*/ +size_t sqlite3_quota_fread( + void *pBuf, /* Store the content here */ + size_t size, /* Size of each element */ + size_t nmemb, /* Number of elements to read */ + quota_FILE *p /* Read from this quota_FILE object */ +){ + return fread(pBuf, size, nmemb, p->f); +} + +/* +** Write content into a quota_FILE. Invoke the quota callback and block +** the write if we exceed quota. +*/ +size_t sqlite3_quota_fwrite( + void *pBuf, /* Take content to write from here */ + size_t size, /* Size of each element */ + size_t nmemb, /* Number of elements */ + quota_FILE *p /* Write to this quota_FILE objecct */ +){ + sqlite3_int64 iOfst; + sqlite3_int64 iEnd; + sqlite3_int64 szNew; + quotaFile *pFile; + + iOfst = ftell(p->f); + iEnd = iOfst + size*nmemb; + pFile = p->pFile; + if( pFile->iSizepGroup; + quotaEnter(); + szNew = pGroup->iSize - pFile->iSize + iEnd; + if( szNew>pGroup->iLimit && pGroup->iLimit>0 ){ + if( pGroup->xCallback ){ + pGroup->xCallback(pFile->zFilename, &pGroup->iLimit, szNew, + pGroup->pArg); + } + if( szNew>pGroup->iLimit && pGroup->iLimit>0 ){ + iEnd = pGroup->iLimit - pGroup->iSize + pFile->iSize; + nmemb = (iEnd - iOfst)/size; + iEnd = iOfst + size*nmemb; + szNew = pGroup->iSize - pFile->iSize + iEnd; + } + } + pGroup->iSize = szNew; + pFile->iSize = iEnd; + quotaLeave(); + } + return fwrite(pBuf, size, nmemb, p->f); +} + +/* +** Close an open quota_FILE stream. +*/ +int sqlite3_quota_fclose(quota_FILE *p){ + int rc; + quotaFile *pFile; + rc = fclose(p->f); + pFile = p->pFile; + quotaEnter(); + pFile->nRef--; + if( pFile->nRef==0 ){ + quotaGroup *pGroup = pFile->pGroup; + if( pFile->deleteOnClose ) quotaRemoveFile(pFile); + quotaGroupDeref(pGroup); + } + quotaLeave(); + sqlite3_free(p); + return rc; +} + +/* +** Seek on a quota_FILE stream. +*/ +int sqlite3_quota_fseek(quota_FILE *p, long offset, int whence){ + return fseek(p->f, offset, whence); +} + +/* +** rewind a quota_FILE stream. +*/ +void sqlite3_quota_rewind(quota_FILE *p){ + rewind(p->f); +} + +/* +** Tell the current location of a quota_FILE stream. +*/ +long sqlite3_quota_ftell(quota_FILE *p){ + return ftell(p->f); +} + +/* +** Remove a file. Update quotas accordingly. +*/ +int sqlite3_quota_remove(const char *zFilename){ + int rc = remove(zFilename); + sqlite3_quota_file(zFilename); + return rc; +} + /***************************** Test Code ***********************************/ #ifdef SQLITE_TEST diff --git a/src/test_quota.h b/src/test_quota.h new file mode 100644 index 0000000000..df78e7eb71 --- /dev/null +++ b/src/test_quota.h @@ -0,0 +1,158 @@ +/* +** 2011 December 1 +** +** 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 the interface definition for the quota a VFS shim. +** +** This particular shim enforces a quota system on files. One or more +** database files are in a "quota group" that is defined by a GLOB +** pattern. A quota is set for the combined size of all files in the +** the group. A quota of zero means "no limit". If the total size +** of all files in the quota group is greater than the limit, then +** write requests that attempt to enlarge a file fail with SQLITE_FULL. +** +** However, before returning SQLITE_FULL, the write requests invoke +** a callback function that is configurable for each quota group. +** This callback has the opportunity to enlarge the quota. If the +** callback does enlarge the quota such that the total size of all +** files within the group is less than the new quota, then the write +** continues as if nothing had happened. +*/ +#ifndef _QUOTA_H_ +#include "sqlite3.h" +#include + +/* +** Initialize the quota VFS shim. Use the VFS named zOrigVfsName +** as the VFS that does the actual work. Use the default if +** zOrigVfsName==NULL. +** +** The quota VFS shim is named "quota". It will become the default +** VFS if makeDefault is non-zero. +** +** THIS ROUTINE IS NOT THREADSAFE. Call this routine exactly once +** during start-up. +*/ +int sqlite3_quota_initialize(const char *zOrigVfsName, int makeDefault); + +/* +** Shutdown the quota system. +** +** All SQLite database connections must be closed before calling this +** routine. +** +** THIS ROUTINE IS NOT THREADSAFE. Call this routine exactly once while +** shutting down in order to free all remaining quota groups. +*/ +int sqlite3_quota_shutdown(void); + +/* +** Create or destroy a quota group. +** +** The quota group is defined by the zPattern. When calling this routine +** with a zPattern for a quota group that already exists, this routine +** merely updates the iLimit, xCallback, and pArg values for that quota +** group. If zPattern is new, then a new quota group is created. +** +** The zPattern is always compared against the full pathname of the file. +** Even if APIs are called with relative pathnames, SQLite converts the +** name to a full pathname before comparing it against zPattern. zPattern +** is a standard glob pattern with the following matching rules: +** +** '*' Matches any sequence of zero or more characters. +** +** '?' Matches exactly one character. +** +** [...] Matches one character from the enclosed list of +** characters. +** +** [^...] Matches one character not in the enclosed list. +** +** Note that, unlike unix shell globbing, the directory separator "/" +** can match a wildcard. So, for example, the pattern "/abc/xyz/" "*" +** matches any files anywhere in the directory hierarchy beneath +** /abc/xyz +** +** If the iLimit for a quota group is set to zero, then the quota group +** is disabled and will be deleted when the last database connection using +** the quota group is closed. +** +** Calling this routine on a zPattern that does not exist and with a +** zero iLimit is a no-op. +** +** A quota group must exist with a non-zero iLimit prior to opening +** database connections if those connections are to participate in the +** quota group. Creating a quota group does not affect database connections +** that are already open. +*/ +int sqlite3_quota_set( + const char *zPattern, /* The filename pattern */ + sqlite3_int64 iLimit, /* New quota to set for this quota group */ + void (*xCallback)( /* Callback invoked when going over quota */ + const char *zFilename, /* Name of file whose size increases */ + sqlite3_int64 *piLimit, /* IN/OUT: The current limit */ + sqlite3_int64 iSize, /* Total size of all files in the group */ + void *pArg /* Client data */ + ), + void *pArg, /* client data passed thru to callback */ + void (*xDestroy)(void*) /* Optional destructor for pArg */ +); + +/* +** Bring the named file under quota management. Or if it is already under +** management, update its size. +*/ +int sqlite3_quota_file(const char *zFilename); + +/* +** The following object serves the same role as FILE in the standard C +** library. It represents an open connection to a file on disk for I/O. +*/ +typedef struct quota_FILE quota_FILE; + +/* +** Create a new quota_FILE object used to read and/or write to the +** file zFilename. The zMode parameter is as with standard library zMode. +*/ +quota_FILE *sqlite3_quota_fopen(const char *zFilename, const char *zMode); + +/* +** Perform I/O against a quota_FILE object. When doing writes, the +** quota mechanism may result in a short write, in order to prevent +** the sum of sizes of all files from going over quota. +*/ +size_t sqlite3_quota_fread(void*, size_t, size_t, quota_FILE*); +size_t sqlite3_quota_fwrite(void*, size_t, size_t, quota_FILE*); + +/* +** Close a quota_FILE object and free all associated resources. The +** file remains under quota management. +*/ +int sqlite3_quota_fclose(quota_FILE*); + +/* +** Move the read/write pointer for a quota_FILE object. Or tell the +** current location of the read/write pointer. +*/ +int sqlite3_quota_fseek(quota_FILE*, long, int); +void sqlite3_quota_rewind(quota_FILE*); +long sqlite3_quota_ftell(quota_FILE*); + +/* +** Delete a file from the disk. If that file is under quota management, +** then adjust quotas accordingly. +** +** The file being deleted must not be open for reading or writing or as +** a database when it is deleted. +*/ +int sqlite3_quota_remove(const char *zFilename); + +#endif /* _QUOTA_H_ */ From a76e85891777d1ff9b76103b1aa5ffc324e5d30c Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 1 Dec 2011 20:48:15 +0000 Subject: [PATCH 02/11] Add test logic and some test cases. FossilOrigin-Name: a4730586cc1f686ead956ccd1cc218b5931942c9 --- manifest | 18 ++- manifest.uuid | 2 +- src/test_quota.c | 319 +++++++++++++++++++++++++++++++++++++++++++++-- test/quota.test | 1 + test/quota2.test | 114 +++++++++++++++++ 5 files changed, 435 insertions(+), 19 deletions(-) create mode 100644 test/quota2.test diff --git a/manifest b/manifest index cade689e9a..f025539657 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sstdio-like\sI/O\sinterfaces\sto\sthe\stest_quota\sVFS.\s\sThis\sis\sa\sprototype\nchange\sfor\sdiscussion\sand\sis\smostly\suntested.\s\sThis\sis\san\salternative\sto\nadding\sstdio-like\sI/O\sinterfaces\sin\sthe\score.\s\sThere\sis\sno\sguarantee\sthat\nthis\scode\swill\smake\sit\sinto\sthe\strunk.\s\sIf\sit\sdoes\sget\sto\strunk,\sthere\ncould\sbe\smany\schanges\sto\sthe\sinterface\sfirst. -D 2011-12-01T18:44:21.630 +C Add\stest\slogic\sand\ssome\stest\scases. +D 2011-12-01T20:48:15.803 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5b4a3e12a850b021547e43daf886b25133b44c07 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -220,7 +220,7 @@ F src/test_mutex.c a6bd7b9cf6e19d989e31392b06ac8d189f0d573e F src/test_onefile.c 40cf9e212a377a6511469384a64b01e6e34b2eec F src/test_osinst.c 62b0b8ef21ce754cc94e17bb42377ed8795dba32 F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00 -F src/test_quota.c f3ed8e130fff8e824a320a80668cfaffd6cb55ff +F src/test_quota.c ed68398661b398f0ce213349eb1cac6b5c39f62e F src/test_quota.h 118dba604ae5b6903acdd40d2b94a1f319047612 F src/test_rtree.c 6d06306e29946dc36f528a3a2cdc3add794656f1 F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0 @@ -634,7 +634,8 @@ F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552 F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301 F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc F test/quick.test 1681febc928d686362d50057c642f77a02c62e57 -F test/quota.test 1c59a396e8f7b5d8466fa74b59f2aeb778d74f7a +F test/quota.test 46e6571b45c3c58ac131cc38f7d600aa9f75974d +F test/quota2.test 1372a399adcecc423396f51faec5de44ae236019 F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6 F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459 F test/randexpr1.test 1084050991e9ba22c1c10edd8d84673b501cc25a @@ -977,10 +978,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P 431556cac0b2c86d7f6a60412ff1023feeaafedf -R e31672c1519f90c43111109b685a8ffb -T *branch * quota-stdio -T *sym-quota-stdio * -T -sym-trunk * +P bd3ce723f1b5be52be46ede8614ca316f56e7e6f +R 137abcb878bf12767e2fb107dd20a728 U drh -Z 0283eb6e7b14cfb0e1559cbc303ec8df +Z 363de760bad75051e8a4f47a97fcd11d diff --git a/manifest.uuid b/manifest.uuid index f43d772bdb..c735789a39 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -bd3ce723f1b5be52be46ede8614ca316f56e7e6f \ No newline at end of file +a4730586cc1f686ead956ccd1cc218b5931942c9 \ No newline at end of file diff --git a/src/test_quota.c b/src/test_quota.c index 1866e79986..d435f88558 100644 --- a/src/test_quota.c +++ b/src/test_quota.c @@ -237,6 +237,8 @@ static void quotaGroupDeref(quotaGroup *pGroup){ ** ** [^...] Matches one character not in the enclosed list. ** +** / Matches "/" or "\\" +** */ static int quotaStrglob(const char *zGlob, const char *z){ int c, c2; @@ -295,6 +297,9 @@ static int quotaStrglob(const char *zGlob, const char *z){ c2 = *(zGlob++); } if( c2==0 || (seen ^ invert)==0 ) return 0; + }else if( c=='/' ){ + if( z[0]!='/' && z[0]!='\\' ) return 0; + z++; }else{ if( c!=(*(z++)) ) return 0; } @@ -351,6 +356,79 @@ static quotaFile *quotaFindFile( return pFile; } +/* +** Figure out if we are dealing with Unix, Windows, or some other +** operating system. After the following block of preprocess macros, +** all of SQLITE_OS_UNIX, SQLITE_OS_WIN, SQLITE_OS_OS2, and SQLITE_OS_OTHER +** will defined to either 1 or 0. One of the four will be 1. The other +** three will be 0. +*/ +#if defined(SQLITE_OS_OTHER) +# if SQLITE_OS_OTHER==1 +# undef SQLITE_OS_UNIX +# define SQLITE_OS_UNIX 0 +# undef SQLITE_OS_WIN +# define SQLITE_OS_WIN 0 +# undef SQLITE_OS_OS2 +# define SQLITE_OS_OS2 0 +# else +# undef SQLITE_OS_OTHER +# endif +#endif +#if !defined(SQLITE_OS_UNIX) && !defined(SQLITE_OS_OTHER) +# define SQLITE_OS_OTHER 0 +# ifndef SQLITE_OS_WIN +# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) \ + || defined(__MINGW32__) || defined(__BORLANDC__) +# define SQLITE_OS_WIN 1 +# define SQLITE_OS_UNIX 0 +# define SQLITE_OS_OS2 0 +# elif defined(__EMX__) || defined(_OS2) || defined(OS2) \ + || defined(_OS2_) || defined(__OS2__) +# define SQLITE_OS_WIN 0 +# define SQLITE_OS_UNIX 0 +# define SQLITE_OS_OS2 1 +# else +# define SQLITE_OS_WIN 0 +# define SQLITE_OS_UNIX 1 +# define SQLITE_OS_OS2 0 +# endif +# else +# define SQLITE_OS_UNIX 0 +# define SQLITE_OS_OS2 0 +# endif +#else +# ifndef SQLITE_OS_WIN +# define SQLITE_OS_WIN 0 +# endif +#endif + + +/* +** Translate UTF8 to MBCS for use in fopen() calls. Return a pointer to the +** translated text.. Call quota_mbcs_free() to deallocate any memory +** used to store the returned pointer when done. +*/ +static char *quota_utf8_to_mbcs(const char *zUtf8){ +#if SQLITE_OS_WIN + extern char *sqlite3_win32_utf8_to_mbcs(const char*); + return sqlite3_win32_utf8_to_mbcs(zUtf8); +#else + return (char*)zUtf8; /* No-op on unix */ +#endif +} + +/* +** Deallocate any memory allocated by quota_utf8_to_mbcs(). +*/ +static void quota_mbcs_free(char *zOld){ +#if SQLITE_OS_WIN + free(zOld); +#else + /* No-op on unix */ +#endif +} + /************************* VFS Method Wrappers *****************************/ /* ** This is the xOpen method used for the "quota" VFS. @@ -856,20 +934,23 @@ int sqlite3_quota_file(const char *zFilename){ quota_FILE *sqlite3_quota_fopen(const char *zFilename, const char *zMode){ quota_FILE *p = 0; char *zFull = 0; + char *zFullTranslated; int rc; quotaGroup *pGroup; quotaFile *pFile; - p = sqlite3_malloc(gQuota.sThisVfs.mxPathname + 1); - if( p==0 ) return 0; - zFull = (char*)&p[1]; + zFull = sqlite3_malloc(gQuota.sThisVfs.mxPathname + 1); + if( zFull==0 ) return 0; rc = gQuota.pOrigVfs->xFullPathname(gQuota.pOrigVfs, zFilename, gQuota.sThisVfs.mxPathname+1, zFull); if( rc ) goto quota_fopen_error; p = sqlite3_malloc(sizeof(*p)); if( p==0 ) goto quota_fopen_error; memset(p, 0, sizeof(*p)); - p->f = fopen(zFull, zMode); + zFullTranslated = quota_utf8_to_mbcs(zFull); + if( zFullTranslated==0 ) goto quota_fopen_error; + p->f = fopen(zFullTranslated, zMode); + quota_mbcs_free(zFullTranslated); if( p->f==0 ) goto quota_fopen_error; quotaEnter(); pGroup = quotaGroupFind(zFull); @@ -1242,6 +1323,220 @@ static int test_quota_dump( return TCL_OK; } +/* +** tclcmd: sqlite3_quota_fopen FILENAME MODE +*/ +static int test_quota_fopen( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + const char *zFilename; /* File pattern to configure */ + const char *zMode; /* Mode string */ + quota_FILE *p; /* Open string object */ + char zReturn[50]; /* Name of pointer to return */ + + /* Process arguments */ + if( objc!=3 ){ + Tcl_WrongNumArgs(interp, 1, objv, "FILENAME MODE"); + return TCL_ERROR; + } + zFilename = Tcl_GetString(objv[1]); + zMode = Tcl_GetString(objv[2]); + p = sqlite3_quota_fopen(zFilename, zMode); + sqlite3_snprintf(sizeof(zReturn), zReturn, "%p", p); + Tcl_SetResult(interp, zReturn, TCL_VOLATILE); + return TCL_OK; +} + +/* Defined in test1.c */ +extern void *sqlite3TestTextToPtr(const char*); + +/* +** tclcmd: sqlite3_quota_fread HANDLE SIZE NELEM +*/ +static int test_quota_fread( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + quota_FILE *p; + char *zBuf; + int sz; + int nElem; + int got; + + if( objc!=4 ){ + Tcl_WrongNumArgs(interp, 1, objv, "HANDLE SIZE NELEM"); + return TCL_ERROR; + } + p = sqlite3TestTextToPtr(Tcl_GetString(objv[1])); + if( Tcl_GetIntFromObj(interp, objv[2], &sz) ) return TCL_ERROR; + if( Tcl_GetIntFromObj(interp, objv[3], &nElem) ) return TCL_ERROR; + zBuf = sqlite3_malloc( sz*nElem + 1 ); + if( zBuf==0 ){ + Tcl_SetResult(interp, "out of memory", TCL_STATIC); + return TCL_ERROR; + } + got = sqlite3_quota_fread(zBuf, sz, nElem, p); + if( got<0 ) got = 0; + zBuf[got*sz] = 0; + Tcl_SetResult(interp, zBuf, TCL_VOLATILE); + sqlite3_free(zBuf); + return TCL_OK; +} + +/* +** tclcmd: sqlite3_quota_fwrite HANDLE SIZE NELEM CONTENT +*/ +static int test_quota_fwrite( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + quota_FILE *p; + char *zBuf; + int sz; + int nElem; + int got; + + if( objc!=5 ){ + Tcl_WrongNumArgs(interp, 1, objv, "HANDLE SIZE NELEM CONTENT"); + return TCL_ERROR; + } + p = sqlite3TestTextToPtr(Tcl_GetString(objv[1])); + if( Tcl_GetIntFromObj(interp, objv[2], &sz) ) return TCL_ERROR; + if( Tcl_GetIntFromObj(interp, objv[3], &nElem) ) return TCL_ERROR; + zBuf = Tcl_GetString(objv[4]); + got = sqlite3_quota_fwrite(zBuf, sz, nElem, p); + Tcl_SetObjResult(interp, Tcl_NewIntObj(got)); + return TCL_OK; +} + +/* +** tclcmd: sqlite3_quota_fclose HANDLE +*/ +static int test_quota_fclose( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + quota_FILE *p; + int rc; + + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "HANDLE"); + return TCL_ERROR; + } + p = sqlite3TestTextToPtr(Tcl_GetString(objv[1])); + rc = sqlite3_quota_fclose(p); + Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); + return TCL_OK; +} + +/* +** tclcmd: sqlite3_quota_fseek HANDLE OFFSET WHENCE +*/ +static int test_quota_fseek( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + quota_FILE *p; + int ofst; + const char *zWhence; + int whence; + int rc; + + if( objc!=4 ){ + Tcl_WrongNumArgs(interp, 1, objv, "HANDLE OFFSET WHENCE"); + return TCL_ERROR; + } + p = sqlite3TestTextToPtr(Tcl_GetString(objv[1])); + if( Tcl_GetIntFromObj(interp, objv[2], &ofst) ) return TCL_ERROR; + zWhence = Tcl_GetString(objv[3]); + if( strcmp(zWhence, "SEEK_SET")==0 ){ + whence = SEEK_SET; + }else if( strcmp(zWhence, "SEEK_CUR")==0 ){ + whence = SEEK_CUR; + }else if( strcmp(zWhence, "SEEK_END")==0 ){ + whence = SEEK_END; + }else{ + Tcl_AppendResult(interp, + "WHENCE should be SEEK_SET, SEEK_CUR, or SEEK_END", (char*)0); + return TCL_ERROR; + } + rc = sqlite3_quota_fseek(p, ofst, whence); + Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); + return TCL_OK; +} + +/* +** tclcmd: sqlite3_quota_rewind HANDLE +*/ +static int test_quota_rewind( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + quota_FILE *p; + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "HANDLE"); + return TCL_ERROR; + } + p = sqlite3TestTextToPtr(Tcl_GetString(objv[1])); + sqlite3_quota_rewind(p); + return TCL_OK; +} + +/* +** tclcmd: sqlite3_quota_ftell HANDLE +*/ +static int test_quota_ftell( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + quota_FILE *p; + sqlite3_int64 x; + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "HANDLE"); + return TCL_ERROR; + } + p = sqlite3TestTextToPtr(Tcl_GetString(objv[1])); + x = sqlite3_quota_ftell(p); + Tcl_SetObjResult(interp, Tcl_NewWideIntObj(x)); + return TCL_OK; +} + +/* +** tclcmd: sqlite3_quota_remove FILENAME +*/ +static int test_quota_remove( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + const char *zFilename; /* File pattern to configure */ + int rc; + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "FILENAME"); + return TCL_ERROR; + } + zFilename = Tcl_GetString(objv[1]); + rc = sqlite3_quota_remove(zFilename); + Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); + return TCL_OK; +} + /* ** This routine registers the custom TCL commands defined in this ** module. This should be the only procedure visible from outside @@ -1253,10 +1548,18 @@ int Sqlitequota_Init(Tcl_Interp *interp){ Tcl_ObjCmdProc *xProc; } aCmd[] = { { "sqlite3_quota_initialize", test_quota_initialize }, - { "sqlite3_quota_shutdown", test_quota_shutdown }, - { "sqlite3_quota_set", test_quota_set }, - { "sqlite3_quota_file", test_quota_file }, - { "sqlite3_quota_dump", test_quota_dump }, + { "sqlite3_quota_shutdown", test_quota_shutdown }, + { "sqlite3_quota_set", test_quota_set }, + { "sqlite3_quota_file", test_quota_file }, + { "sqlite3_quota_dump", test_quota_dump }, + { "sqlite3_quota_fopen", test_quota_fopen }, + { "sqlite3_quota_fread", test_quota_fread }, + { "sqlite3_quota_fwrite", test_quota_fwrite }, + { "sqlite3_quota_fclose", test_quota_fclose }, + { "sqlite3_quota_fseek", test_quota_fseek }, + { "sqlite3_quota_rewind", test_quota_rewind }, + { "sqlite3_quota_ftell", test_quota_ftell }, + { "sqlite3_quota_remove", test_quota_remove }, }; int i; diff --git a/test/quota.test b/test/quota.test index 49b403f1eb..8f01c4fde5 100644 --- a/test/quota.test +++ b/test/quota.test @@ -48,6 +48,7 @@ do_test quota-1.8 { sqlite3_quota_shutdown } {SQLITE_OK} # sqlite3_quota_initialize "" 1 +unset -nocomplain quota_request_ok proc quota_check {filename limitvar size} { upvar $limitvar limit diff --git a/test/quota2.test b/test/quota2.test new file mode 100644 index 0000000000..33968082dd --- /dev/null +++ b/test/quota2.test @@ -0,0 +1,114 @@ +# 2011 December 1 +# +# 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. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +source $testdir/malloc_common.tcl + +db close +sqlite3_quota_initialize "" 1 + +file delete -force quota2a +file delete -force quota2b +file mkdir quota2a +file mkdir quota2b + +# The quota_check procedure is a callback from the quota handler. +# It has three arguments which are (1) the full pathname of the file +# that has gone over quota, (2) the quota limit, (3) the requested +# new quota size to cover the last write. These three values are +# appended to the global variable $::quota. The filename is processed +# to convert every \ character into / and to change the name of the +# working directory to PWD. +# +# The quota is increased to the request if the ::quota_request_ok +# global variable is true. +# +set ::quota {} +set ::quota_request_ok 0 +proc quota_check {filename limitvar size} { + upvar $limitvar limit + set filename [string map [list [pwd] PWD \\ /] $filename] + lappend ::quota $filename [set limit] $size + if {$::quota_request_ok} {set limit $size} +} + +sqlite3_quota_set */quota2a/* 4000 quota_check +sqlite3_quota_set */quota2b/* 5000 quota_check + +unset -nocomplain bigtext +for {set i 1} {$i<=1000} {incr i} { + if {$i%10==0} { + append bigtext [format "%06d\n" $i] + } else { + append bigtext [format "%06d " $i] + } +} + +catch { unset h1 } +catch { unset x } +do_test quota2-1.1 { + set ::h1 [sqlite3_quota_fopen quota2a/xyz.txt w+] + sqlite3_quota_fwrite $::h1 1 7000 $bigtext +} {4000} +do_test quota2-1.2 { + set ::quota +} {PWD/quota2a/xyz.txt 4000 7000} +do_test quota2-1.3 { + sqlite3_quota_rewind $::h1 + set ::x [sqlite3_quota_fread $::h1 1001 7] + string length $::x +} {3003} +do_test quota2-1.4 { + string match $::x [string range $::bigtext 0 3002] +} {1} +do_test quota2-1.5 { + sqlite3_quota_fseek $::h1 0 SEEK_END + sqlite3_quota_ftell $::h1 +} {4000} +do_test quota2-1.6 { + sqlite3_quota_fseek $::h1 -100 SEEK_END + sqlite3_quota_ftell $::h1 +} {3900} +do_test quota2-1.7 { + sqlite3_quota_fseek $::h1 -100 SEEK_CUR + sqlite3_quota_ftell $::h1 +} {3800} +do_test quota2-1.8 { + sqlite3_quota_fseek $::h1 50 SEEK_CUR + sqlite3_quota_ftell $::h1 +} {3850} +do_test quota2-1.9 { + sqlite3_quota_fseek $::h1 50 SEEK_SET + sqlite3_quota_ftell $::h1 +} {50} +do_test quota2-1.10 { + sqlite3_quota_rewind $::h1 + sqlite3_quota_ftell $::h1 +} {0} +do_test quota2-1.11 { + string map [list [pwd] PWD \\ /] [sqlite3_quota_dump] +} {{*/quota2b/* 5000 0} {*/quota2a/* 4000 4000 {PWD/quota2a/xyz.txt 4000 1 0}}} +do_test quota1-1.12 { + sqlite3_quota_fclose $::h1 + string map [list [pwd] PWD \\ /] [sqlite3_quota_dump] +} {{*/quota2b/* 5000 0} {*/quota2a/* 4000 4000 {PWD/quota2a/xyz.txt 4000 0 0}}} +do_test quota1-1.13 { + sqlite3_quota_remove quota2a/xyz.txt + string map [list [pwd] PWD \\ /] [sqlite3_quota_dump] +} {{*/quota2b/* 5000 0} {*/quota2a/* 4000 0}} + + + +catch { sqlite3_quota_shutdown } +catch { unset quota_request_ok } +finish_test From c8ccda60761ef2bd75cb122f04135cb938459cda Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 1 Dec 2011 22:07:22 +0000 Subject: [PATCH 03/11] Progress toward getting things to work better on windows. FossilOrigin-Name: 253dd7072ef7f4e8742e5b6430658f8e5102e0bb --- manifest | 15 ++++++------ manifest.uuid | 2 +- src/test_quota.c | 58 +++++++++++++++++++++++++++++++++++--------- test/quota-glob.test | 50 ++++++++++++++++++++++++++++++++++++++ test/quota2.test | 21 ++++++++++++---- 5 files changed, 121 insertions(+), 25 deletions(-) create mode 100644 test/quota-glob.test diff --git a/manifest b/manifest index f025539657..66b7337e56 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\stest\slogic\sand\ssome\stest\scases. -D 2011-12-01T20:48:15.803 +C Progress\stoward\sgetting\sthings\sto\swork\sbetter\son\swindows. +D 2011-12-01T22:07:22.034 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5b4a3e12a850b021547e43daf886b25133b44c07 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -220,7 +220,7 @@ F src/test_mutex.c a6bd7b9cf6e19d989e31392b06ac8d189f0d573e F src/test_onefile.c 40cf9e212a377a6511469384a64b01e6e34b2eec F src/test_osinst.c 62b0b8ef21ce754cc94e17bb42377ed8795dba32 F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00 -F src/test_quota.c ed68398661b398f0ce213349eb1cac6b5c39f62e +F src/test_quota.c 38c23c0fcbc92e0f8fe6fc0a76e66680cdb1b5cb F src/test_quota.h 118dba604ae5b6903acdd40d2b94a1f319047612 F src/test_rtree.c 6d06306e29946dc36f528a3a2cdc3add794656f1 F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0 @@ -634,8 +634,9 @@ F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552 F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301 F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc F test/quick.test 1681febc928d686362d50057c642f77a02c62e57 +F test/quota-glob.test bb88e8da2f24f7f8413492967beb35d3222f52a4 F test/quota.test 46e6571b45c3c58ac131cc38f7d600aa9f75974d -F test/quota2.test 1372a399adcecc423396f51faec5de44ae236019 +F test/quota2.test 87b9c7a63e458706e528c661efa3955abc540fc5 F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6 F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459 F test/randexpr1.test 1084050991e9ba22c1c10edd8d84673b501cc25a @@ -978,7 +979,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P bd3ce723f1b5be52be46ede8614ca316f56e7e6f -R 137abcb878bf12767e2fb107dd20a728 +P a4730586cc1f686ead956ccd1cc218b5931942c9 +R 2e2d8adc5259d2440bcb724fb4357d2b U drh -Z 363de760bad75051e8a4f47a97fcd11d +Z 0c07da994a8e7e81f42215da8ed506cb diff --git a/manifest.uuid b/manifest.uuid index c735789a39..64d966b624 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a4730586cc1f686ead956ccd1cc218b5931942c9 \ No newline at end of file +253dd7072ef7f4e8742e5b6430658f8e5102e0bb \ No newline at end of file diff --git a/src/test_quota.c b/src/test_quota.c index d435f88558..479cf0f0d8 100644 --- a/src/test_quota.c +++ b/src/test_quota.c @@ -241,7 +241,7 @@ static void quotaGroupDeref(quotaGroup *pGroup){ ** */ static int quotaStrglob(const char *zGlob, const char *z){ - int c, c2; + int c, c2, cx; int invert; int seen; @@ -258,8 +258,9 @@ static int quotaStrglob(const char *zGlob, const char *z){ } return (*z)!=0; } + cx = (c=='/') ? '\\' : c; while( (c2 = (*(z++)))!=0 ){ - while( c2!=c ){ + while( c2!=c && c2!=cx ){ c2 = *(z++); if( c2==0 ) return 0; } @@ -423,7 +424,7 @@ static char *quota_utf8_to_mbcs(const char *zUtf8){ */ static void quota_mbcs_free(char *zOld){ #if SQLITE_OS_WIN - free(zOld); + sqlite3_free(zOld); #else /* No-op on unix */ #endif @@ -1004,7 +1005,7 @@ size_t sqlite3_quota_fwrite( iOfst = ftell(p->f); iEnd = iOfst + size*nmemb; pFile = p->pFile; - if( pFile->iSizeiSizepGroup; quotaEnter(); szNew = pGroup->iSize - pFile->iSize + iEnd; @@ -1035,14 +1036,16 @@ int sqlite3_quota_fclose(quota_FILE *p){ quotaFile *pFile; rc = fclose(p->f); pFile = p->pFile; - quotaEnter(); - pFile->nRef--; - if( pFile->nRef==0 ){ - quotaGroup *pGroup = pFile->pGroup; - if( pFile->deleteOnClose ) quotaRemoveFile(pFile); - quotaGroupDeref(pGroup); + if( pFile ){ + quotaEnter(); + pFile->nRef--; + if( pFile->nRef==0 ){ + quotaGroup *pGroup = pFile->pGroup; + if( pFile->deleteOnClose ) quotaRemoveFile(pFile); + quotaGroupDeref(pGroup); + } + quotaLeave(); } - quotaLeave(); sqlite3_free(p); return rc; } @@ -1305,9 +1308,13 @@ static int test_quota_dump( Tcl_ListObjAppendElement(interp, pGroupTerm, Tcl_NewWideIntObj(pGroup->iSize)); for(pFile=pGroup->pFiles; pFile; pFile=pFile->pNext){ + int i; + char zTemp[1000]; pFileTerm = Tcl_NewObj(); + sqlite3_snprintf(sizeof(zTemp), zTemp, "%s", pFile->zFilename); + for(i=0; zTemp[i]; i++){ if( zTemp[i]=='\\' ) zTemp[i] = '/'; } Tcl_ListObjAppendElement(interp, pFileTerm, - Tcl_NewStringObj(pFile->zFilename, -1)); + Tcl_NewStringObj(zTemp, -1)); Tcl_ListObjAppendElement(interp, pFileTerm, Tcl_NewWideIntObj(pFile->iSize)); Tcl_ListObjAppendElement(interp, pFileTerm, @@ -1537,6 +1544,32 @@ static int test_quota_remove( return TCL_OK; } +/* +** tclcmd: sqlite3_quota_glob PATTERN TEXT +** +** Test the glob pattern matching. Return 1 if TEXT matches PATTERN +** and return 0 if it does not. +*/ +static int test_quota_glob( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + const char *zPattern; /* The glob pattern */ + const char *zText; /* Text to compare agains the pattern */ + int rc; + if( objc!=3 ){ + Tcl_WrongNumArgs(interp, 1, objv, "PATTERN TEXT"); + return TCL_ERROR; + } + zPattern = Tcl_GetString(objv[1]); + zText = Tcl_GetString(objv[2]); + rc = quotaStrglob(zPattern, zText); + Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); + return TCL_OK; +} + /* ** This routine registers the custom TCL commands defined in this ** module. This should be the only procedure visible from outside @@ -1560,6 +1593,7 @@ int Sqlitequota_Init(Tcl_Interp *interp){ { "sqlite3_quota_rewind", test_quota_rewind }, { "sqlite3_quota_ftell", test_quota_ftell }, { "sqlite3_quota_remove", test_quota_remove }, + { "sqlite3_quota_glob", test_quota_glob }, }; int i; diff --git a/test/quota-glob.test b/test/quota-glob.test new file mode 100644 index 0000000000..bacaa27c29 --- /dev/null +++ b/test/quota-glob.test @@ -0,0 +1,50 @@ +# 2011 December 1 +# +# 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. +# +#*********************************************************************** +# +# Tests for the glob-style string compare operator embedded in the +# quota shim. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +catch { unset testnum } +catch { unset pattern } +catch { unset text } +catch { unset ans } + +foreach {testnum pattern text ans} { + 1 abcdefg abcdefg 1 + 2 abcdefG abcdefg 0 + 3 abcdef abcdefg 0 + 4 abcdefgh abcdefg 0 + 5 abcdef? abcdefg 1 + 6 abcdef? abcdef 0 + 7 abcdef? abcdefgh 0 + 8 abcdefg abcdef? 0 + 9 abcdef? abcdef? 1 + 10 abc/def abc/def 1 + 11 abc/def abc\\def 1 + 12 */abc/* x/abc/y 1 + 13 */abc/* /abc/ 1 + 16 */abc/* x///a/ab/abc 0 + 17 */abc/* x//a/ab/abc/ 1 + 16 */abc/* x///a/ab/abc 0 + 17 */abc/* x//a/ab/abc/ 1 +} { + do_test quota-glob-$testnum.1 { + sqlite3_quota_glob $::pattern $::text + } $::ans + do_test quota-glob-$testnum.2 { + sqlite3_quota_glob $::pattern [string map {/ \\} $::text] + } $::ans +} +finish_test diff --git a/test/quota2.test b/test/quota2.test index 33968082dd..458c3069d7 100644 --- a/test/quota2.test +++ b/test/quota2.test @@ -22,6 +22,17 @@ file delete -force quota2b file mkdir quota2a file mkdir quota2b +# The standard_path procedure converts a pathname into a standard format +# that is the same across platforms. +# +unset -nocomplain ::quota_pwd ::quota_mapping +set ::quota_pwd [string map {\\ /} [pwd]] +set ::quota_mapping [list $::quota_pwd PWD] +proc standard_path {x} { + set x [string map {\\ /} $x] + return [string map $::quota_mapping $x] +} + # The quota_check procedure is a callback from the quota handler. # It has three arguments which are (1) the full pathname of the file # that has gone over quota, (2) the quota limit, (3) the requested @@ -35,10 +46,10 @@ file mkdir quota2b # set ::quota {} set ::quota_request_ok 0 + proc quota_check {filename limitvar size} { upvar $limitvar limit - set filename [string map [list [pwd] PWD \\ /] $filename] - lappend ::quota $filename [set limit] $size + lappend ::quota [standard_path $filename] [set limit] $size if {$::quota_request_ok} {set limit $size} } @@ -96,15 +107,15 @@ do_test quota2-1.10 { sqlite3_quota_ftell $::h1 } {0} do_test quota2-1.11 { - string map [list [pwd] PWD \\ /] [sqlite3_quota_dump] + standard_path [sqlite3_quota_dump] } {{*/quota2b/* 5000 0} {*/quota2a/* 4000 4000 {PWD/quota2a/xyz.txt 4000 1 0}}} do_test quota1-1.12 { sqlite3_quota_fclose $::h1 - string map [list [pwd] PWD \\ /] [sqlite3_quota_dump] + standard_path [sqlite3_quota_dump] } {{*/quota2b/* 5000 0} {*/quota2a/* 4000 4000 {PWD/quota2a/xyz.txt 4000 0 0}}} do_test quota1-1.13 { sqlite3_quota_remove quota2a/xyz.txt - string map [list [pwd] PWD \\ /] [sqlite3_quota_dump] + standard_path [sqlite3_quota_dump] } {{*/quota2b/* 5000 0} {*/quota2a/* 4000 0}} From 0661ca6ce216ccabe0ede90a9556cc4da79f97f3 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 1 Dec 2011 22:12:58 +0000 Subject: [PATCH 04/11] Run quota-stdio tests in binary mode so that they work on windows. FossilOrigin-Name: 71e4e97d9c883aa9f1d43d61543685924fc9339a --- manifest | 12 ++++++------ manifest.uuid | 2 +- test/quota2.test | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 66b7337e56..8f0434f9ff 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Progress\stoward\sgetting\sthings\sto\swork\sbetter\son\swindows. -D 2011-12-01T22:07:22.034 +C Run\squota-stdio\stests\sin\sbinary\smode\sso\sthat\sthey\swork\son\swindows. +D 2011-12-01T22:12:58.579 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5b4a3e12a850b021547e43daf886b25133b44c07 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -636,7 +636,7 @@ F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc F test/quick.test 1681febc928d686362d50057c642f77a02c62e57 F test/quota-glob.test bb88e8da2f24f7f8413492967beb35d3222f52a4 F test/quota.test 46e6571b45c3c58ac131cc38f7d600aa9f75974d -F test/quota2.test 87b9c7a63e458706e528c661efa3955abc540fc5 +F test/quota2.test eabde52ca2606f494be10aad87562b4dd2f4558a F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6 F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459 F test/randexpr1.test 1084050991e9ba22c1c10edd8d84673b501cc25a @@ -979,7 +979,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P a4730586cc1f686ead956ccd1cc218b5931942c9 -R 2e2d8adc5259d2440bcb724fb4357d2b +P 253dd7072ef7f4e8742e5b6430658f8e5102e0bb +R 81841ea938699b5dac6d44310547d5e9 U drh -Z 0c07da994a8e7e81f42215da8ed506cb +Z 485f7e550a4a58d4cb24ca1e40fc9f7f diff --git a/manifest.uuid b/manifest.uuid index 64d966b624..f798ec3b64 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -253dd7072ef7f4e8742e5b6430658f8e5102e0bb \ No newline at end of file +71e4e97d9c883aa9f1d43d61543685924fc9339a \ No newline at end of file diff --git a/test/quota2.test b/test/quota2.test index 458c3069d7..57d54d056a 100644 --- a/test/quota2.test +++ b/test/quota2.test @@ -68,7 +68,7 @@ for {set i 1} {$i<=1000} {incr i} { catch { unset h1 } catch { unset x } do_test quota2-1.1 { - set ::h1 [sqlite3_quota_fopen quota2a/xyz.txt w+] + set ::h1 [sqlite3_quota_fopen quota2a/xyz.txt w+b] sqlite3_quota_fwrite $::h1 1 7000 $bigtext } {4000} do_test quota2-1.2 { From eff1433b6b7d1221034ba3c77687178537b413e9 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 2 Dec 2011 15:27:41 +0000 Subject: [PATCH 05/11] Documentation improvements and additional test cases. FossilOrigin-Name: fa71896089538589fb7015d6507e22961e72233b --- manifest | 16 ++++++------- manifest.uuid | 2 +- src/test_quota.h | 12 +++++++--- test/quota-glob.test | 39 ++++++++++++++++++++++++++++++- test/quota2.test | 55 ++++++++++++++++++++++++++++++++++++++++---- 5 files changed, 107 insertions(+), 17 deletions(-) diff --git a/manifest b/manifest index 8f0434f9ff..46f615874f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Run\squota-stdio\stests\sin\sbinary\smode\sso\sthat\sthey\swork\son\swindows. -D 2011-12-01T22:12:58.579 +C Documentation\simprovements\sand\sadditional\stest\scases. +D 2011-12-02T15:27:41.260 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5b4a3e12a850b021547e43daf886b25133b44c07 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -221,7 +221,7 @@ F src/test_onefile.c 40cf9e212a377a6511469384a64b01e6e34b2eec F src/test_osinst.c 62b0b8ef21ce754cc94e17bb42377ed8795dba32 F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00 F src/test_quota.c 38c23c0fcbc92e0f8fe6fc0a76e66680cdb1b5cb -F src/test_quota.h 118dba604ae5b6903acdd40d2b94a1f319047612 +F src/test_quota.h 64240c0f7505dc1d920ff908d63d12ff2bf9c7c0 F src/test_rtree.c 6d06306e29946dc36f528a3a2cdc3add794656f1 F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0 F src/test_server.c 2f99eb2837dfa06a4aacf24af24c6affdf66a84f @@ -634,9 +634,9 @@ F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552 F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301 F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc F test/quick.test 1681febc928d686362d50057c642f77a02c62e57 -F test/quota-glob.test bb88e8da2f24f7f8413492967beb35d3222f52a4 +F test/quota-glob.test 32901e9eed6705d68ca3faee2a06b73b57cb3c26 F test/quota.test 46e6571b45c3c58ac131cc38f7d600aa9f75974d -F test/quota2.test eabde52ca2606f494be10aad87562b4dd2f4558a +F test/quota2.test b7169f613adf64c22a5336ca607d3b54d7b2ed5a F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6 F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459 F test/randexpr1.test 1084050991e9ba22c1c10edd8d84673b501cc25a @@ -979,7 +979,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P 253dd7072ef7f4e8742e5b6430658f8e5102e0bb -R 81841ea938699b5dac6d44310547d5e9 +P 71e4e97d9c883aa9f1d43d61543685924fc9339a +R 54a98987b22e40be43c533aef3d8d654 U drh -Z 485f7e550a4a58d4cb24ca1e40fc9f7f +Z 0fb6e66eea4239badfef5d9b0c5e6533 diff --git a/manifest.uuid b/manifest.uuid index f798ec3b64..f9f7f17f15 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -71e4e97d9c883aa9f1d43d61543685924fc9339a \ No newline at end of file +fa71896089538589fb7015d6507e22961e72233b \ No newline at end of file diff --git a/src/test_quota.h b/src/test_quota.h index df78e7eb71..d47f89bd78 100644 --- a/src/test_quota.h +++ b/src/test_quota.h @@ -65,21 +65,27 @@ int sqlite3_quota_shutdown(void); ** The zPattern is always compared against the full pathname of the file. ** Even if APIs are called with relative pathnames, SQLite converts the ** name to a full pathname before comparing it against zPattern. zPattern -** is a standard glob pattern with the following matching rules: +** is a glob pattern with the following matching rules: ** ** '*' Matches any sequence of zero or more characters. ** ** '?' Matches exactly one character. ** ** [...] Matches one character from the enclosed list of -** characters. +** characters. "]" can be part of the list if it is +** the first character. Within the list "X-Y" matches +** characters X or Y or any character in between the +** two. Ex: "[0-9]" matches any digit. ** ** [^...] Matches one character not in the enclosed list. ** +** / Matches either / or \. This allows glob patterns +** containing / to work on both unix and windows. +** ** Note that, unlike unix shell globbing, the directory separator "/" ** can match a wildcard. So, for example, the pattern "/abc/xyz/" "*" ** matches any files anywhere in the directory hierarchy beneath -** /abc/xyz +** /abc/xyz. ** ** If the iLimit for a quota group is set to zero, then the quota group ** is disabled and will be deleted when the last database connection using diff --git a/test/quota-glob.test b/test/quota-glob.test index bacaa27c29..28c813c30f 100644 --- a/test/quota-glob.test +++ b/test/quota-glob.test @@ -32,13 +32,50 @@ foreach {testnum pattern text ans} { 8 abcdefg abcdef? 0 9 abcdef? abcdef? 1 10 abc/def abc/def 1 - 11 abc/def abc\\def 1 + 11 abc//def abc/def 0 12 */abc/* x/abc/y 1 13 */abc/* /abc/ 1 16 */abc/* x///a/ab/abc 0 17 */abc/* x//a/ab/abc/ 1 16 */abc/* x///a/ab/abc 0 17 */abc/* x//a/ab/abc/ 1 + 18 **/abc/** x//a/ab/abc/ 1 + 19 *?/abc/*? x//a/ab/abc/y 1 + 20 ?*/abc/?* x//a/ab/abc/y 1 + 21 {abc[cde]efg} abcbefg 0 + 22 {abc[cde]efg} abccefg 1 + 23 {abc[cde]efg} abcdefg 1 + 24 {abc[cde]efg} abceefg 1 + 25 {abc[cde]efg} abcfefg 0 + 26 {abc[^cde]efg} abcbefg 1 + 27 {abc[^cde]efg} abccefg 0 + 28 {abc[^cde]efg} abcdefg 0 + 29 {abc[^cde]efg} abceefg 0 + 30 {abc[^cde]efg} abcfefg 1 + 31 {abc[c-e]efg} abcbefg 0 + 32 {abc[c-e]efg} abccefg 1 + 33 {abc[c-e]efg} abcdefg 1 + 34 {abc[c-e]efg} abceefg 1 + 35 {abc[c-e]efg} abcfefg 0 + 36 {abc[^c-e]efg} abcbefg 1 + 37 {abc[^c-e]efg} abccefg 0 + 38 {abc[^c-e]efg} abcdefg 0 + 39 {abc[^c-e]efg} abceefg 0 + 40 {abc[^c-e]efg} abcfefg 1 + 41 {abc[c-e]efg} abc-efg 0 + 42 {abc[-ce]efg} abc-efg 1 + 43 {abc[ce-]efg} abc-efg 1 + 44 {abc[][*?]efg} {abc]efg} 1 + 45 {abc[][*?]efg} {abc*efg} 1 + 46 {abc[][*?]efg} {abc?efg} 1 + 47 {abc[][*?]efg} {abc[efg} 1 + 48 {abc[^][*?]efg} {abc]efg} 0 + 49 {abc[^][*?]efg} {abc*efg} 0 + 50 {abc[^][*?]efg} {abc?efg} 0 + 51 {abc[^][*?]efg} {abc[efg} 0 + 52 {abc[^][*?]efg} {abcdefg} 1 + 53 {*[xyz]efg} {abcxefg} 1 + 54 {*[xyz]efg} {abcwefg} 0 } { do_test quota-glob-$testnum.1 { sqlite3_quota_glob $::pattern $::text diff --git a/test/quota2.test b/test/quota2.test index 57d54d056a..d408cda9ca 100644 --- a/test/quota2.test +++ b/test/quota2.test @@ -17,10 +17,10 @@ source $testdir/malloc_common.tcl db close sqlite3_quota_initialize "" 1 -file delete -force quota2a -file delete -force quota2b -file mkdir quota2a -file mkdir quota2b +foreach dir {quota2a quota2b quota2c} { + file delete -force $dir + file mkdir $dir +} # The standard_path procedure converts a pathname into a standard format # that is the same across platforms. @@ -119,6 +119,53 @@ do_test quota1-1.13 { } {{*/quota2b/* 5000 0} {*/quota2a/* 4000 0}} +set quota {} +do_test quota2-2.1 { + set ::h1 [sqlite3_quota_fopen quota2c/xyz.txt w+b] + sqlite3_quota_fwrite $::h1 1 7000 $bigtext +} {7000} +do_test quota2-2.2 { + set ::quota +} {} +do_test quota2-2.3 { + sqlite3_quota_rewind $::h1 + set ::x [sqlite3_quota_fread $::h1 1001 7] + string length $::x +} {6006} +do_test quota2-2.4 { + string match $::x [string range $::bigtext 0 6005] +} {1} +do_test quota2-2.5 { + sqlite3_quota_fseek $::h1 0 SEEK_END + sqlite3_quota_ftell $::h1 +} {7000} +do_test quota2-2.6 { + sqlite3_quota_fseek $::h1 -100 SEEK_END + sqlite3_quota_ftell $::h1 +} {6900} +do_test quota2-2.7 { + sqlite3_quota_fseek $::h1 -100 SEEK_CUR + sqlite3_quota_ftell $::h1 +} {6800} +do_test quota2-2.8 { + sqlite3_quota_fseek $::h1 50 SEEK_CUR + sqlite3_quota_ftell $::h1 +} {6850} +do_test quota2-2.9 { + sqlite3_quota_fseek $::h1 50 SEEK_SET + sqlite3_quota_ftell $::h1 +} {50} +do_test quota2-2.10 { + sqlite3_quota_rewind $::h1 + sqlite3_quota_ftell $::h1 +} {0} +do_test quota2-2.11 { + standard_path [sqlite3_quota_dump] +} {{*/quota2b/* 5000 0} {*/quota2a/* 4000 0}} +do_test quota1-2.12 { + sqlite3_quota_fclose $::h1 + standard_path [sqlite3_quota_dump] +} {{*/quota2b/* 5000 0} {*/quota2a/* 4000 0}} catch { sqlite3_quota_shutdown } catch { unset quota_request_ok } From a0036917350bff6ca89bef8d135a6c8ad1770f48 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 2 Dec 2011 15:31:07 +0000 Subject: [PATCH 06/11] One minor documentation enhancement. FossilOrigin-Name: 8cfd3575c8d9f5361c5276d6b83aba47606975a3 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/test_quota.h | 3 +++ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index 46f615874f..5de01fa78e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Documentation\simprovements\sand\sadditional\stest\scases. -D 2011-12-02T15:27:41.260 +C One\sminor\sdocumentation\senhancement. +D 2011-12-02T15:31:07.596 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5b4a3e12a850b021547e43daf886b25133b44c07 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -221,7 +221,7 @@ F src/test_onefile.c 40cf9e212a377a6511469384a64b01e6e34b2eec F src/test_osinst.c 62b0b8ef21ce754cc94e17bb42377ed8795dba32 F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00 F src/test_quota.c 38c23c0fcbc92e0f8fe6fc0a76e66680cdb1b5cb -F src/test_quota.h 64240c0f7505dc1d920ff908d63d12ff2bf9c7c0 +F src/test_quota.h c9e778a1ace38cd5be936e99a3d757477e2d1d4f F src/test_rtree.c 6d06306e29946dc36f528a3a2cdc3add794656f1 F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0 F src/test_server.c 2f99eb2837dfa06a4aacf24af24c6affdf66a84f @@ -979,7 +979,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P 71e4e97d9c883aa9f1d43d61543685924fc9339a -R 54a98987b22e40be43c533aef3d8d654 +P fa71896089538589fb7015d6507e22961e72233b +R a322cd5996330a42d9cdf5afaa24ab27 U drh -Z 0fb6e66eea4239badfef5d9b0c5e6533 +Z 9258d38c087b789fa674695734308523 diff --git a/manifest.uuid b/manifest.uuid index f9f7f17f15..b9b86d16df 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -fa71896089538589fb7015d6507e22961e72233b \ No newline at end of file +8cfd3575c8d9f5361c5276d6b83aba47606975a3 \ No newline at end of file diff --git a/src/test_quota.h b/src/test_quota.h index d47f89bd78..6df423f5d1 100644 --- a/src/test_quota.h +++ b/src/test_quota.h @@ -87,6 +87,9 @@ int sqlite3_quota_shutdown(void); ** matches any files anywhere in the directory hierarchy beneath ** /abc/xyz. ** +** The glob algorithm works on bytes. Multi-byte UTF8 characters are +** matched as if each byte were a separate character. +** ** If the iLimit for a quota group is set to zero, then the quota group ** is disabled and will be deleted when the last database connection using ** the quota group is closed. From 69b2232d6e2cfe4a5d1cd25d48af015ee1faac7b Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 3 Dec 2011 00:13:06 +0000 Subject: [PATCH 07/11] Add the sqlite3_quota_fflush() interface. Enhance sqlite3_quota_remove() so that it can remove entire directories. FossilOrigin-Name: abcb65af4cdd192beaccdbc2109ad45b9e7f9d00 --- manifest | 16 ++++----- manifest.uuid | 2 +- src/test_quota.c | 91 ++++++++++++++++++++++++++++++++++++++++++++---- src/test_quota.h | 41 ++++++++++++++++++---- test/quota2.test | 64 +++++++++++++++++++++++++++++++--- 5 files changed, 189 insertions(+), 25 deletions(-) diff --git a/manifest b/manifest index 5de01fa78e..e49d82bcc0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C One\sminor\sdocumentation\senhancement. -D 2011-12-02T15:31:07.596 +C Add\sthe\ssqlite3_quota_fflush()\sinterface.\s\sEnhance\ssqlite3_quota_remove()\nso\sthat\sit\scan\sremove\sentire\sdirectories. +D 2011-12-03T00:13:06.592 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5b4a3e12a850b021547e43daf886b25133b44c07 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -220,8 +220,8 @@ F src/test_mutex.c a6bd7b9cf6e19d989e31392b06ac8d189f0d573e F src/test_onefile.c 40cf9e212a377a6511469384a64b01e6e34b2eec F src/test_osinst.c 62b0b8ef21ce754cc94e17bb42377ed8795dba32 F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00 -F src/test_quota.c 38c23c0fcbc92e0f8fe6fc0a76e66680cdb1b5cb -F src/test_quota.h c9e778a1ace38cd5be936e99a3d757477e2d1d4f +F src/test_quota.c 2e6191cbfc6ae978330a0d0ffcc3fb81b7059e68 +F src/test_quota.h 9b3c75a79e8c3c6a9d3846b73435bebcd550ba12 F src/test_rtree.c 6d06306e29946dc36f528a3a2cdc3add794656f1 F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0 F src/test_server.c 2f99eb2837dfa06a4aacf24af24c6affdf66a84f @@ -636,7 +636,7 @@ F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc F test/quick.test 1681febc928d686362d50057c642f77a02c62e57 F test/quota-glob.test 32901e9eed6705d68ca3faee2a06b73b57cb3c26 F test/quota.test 46e6571b45c3c58ac131cc38f7d600aa9f75974d -F test/quota2.test b7169f613adf64c22a5336ca607d3b54d7b2ed5a +F test/quota2.test 562b27570d1e0d0606c3769b648e23c72fa3859b F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6 F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459 F test/randexpr1.test 1084050991e9ba22c1c10edd8d84673b501cc25a @@ -979,7 +979,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P fa71896089538589fb7015d6507e22961e72233b -R a322cd5996330a42d9cdf5afaa24ab27 +P 8cfd3575c8d9f5361c5276d6b83aba47606975a3 +R 28ca02cd727421756b639f8157eb6391 U drh -Z 9258d38c087b789fa674695734308523 +Z 84dc1ce8a56d57cb5251e17d63b686ff diff --git a/manifest.uuid b/manifest.uuid index b9b86d16df..83ef24af72 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8cfd3575c8d9f5361c5276d6b83aba47606975a3 \ No newline at end of file +abcb65af4cdd192beaccdbc2109ad45b9e7f9d00 \ No newline at end of file diff --git a/src/test_quota.c b/src/test_quota.c index 479cf0f0d8..c073b47d28 100644 --- a/src/test_quota.c +++ b/src/test_quota.c @@ -552,7 +552,10 @@ static int quotaClose(sqlite3_file *pConn){ pFile->nRef--; if( pFile->nRef==0 ){ quotaGroup *pGroup = pFile->pGroup; - if( pFile->deleteOnClose ) quotaRemoveFile(pFile); + if( pFile->deleteOnClose ){ + gQuota.pOrigVfs->xDelete(gQuota.pOrigVfs, pFile->zFilename, 0); + quotaRemoveFile(pFile); + } quotaGroupDeref(pGroup); } quotaLeave(); @@ -1041,7 +1044,10 @@ int sqlite3_quota_fclose(quota_FILE *p){ pFile->nRef--; if( pFile->nRef==0 ){ quotaGroup *pGroup = pFile->pGroup; - if( pFile->deleteOnClose ) quotaRemoveFile(pFile); + if( pFile->deleteOnClose ){ + gQuota.pOrigVfs->xDelete(gQuota.pOrigVfs, pFile->zFilename, 0); + quotaRemoveFile(pFile); + } quotaGroupDeref(pGroup); } quotaLeave(); @@ -1050,6 +1056,13 @@ int sqlite3_quota_fclose(quota_FILE *p){ return rc; } +/* +** Flush memory buffers for a quota_FILE to disk. +*/ +int sqlite3_quota_fflush(quota_FILE *p){ + return fflush(p->f); +} + /* ** Seek on a quota_FILE stream. */ @@ -1072,14 +1085,57 @@ long sqlite3_quota_ftell(quota_FILE *p){ } /* -** Remove a file. Update quotas accordingly. +** Remove a managed file. Update quotas accordingly. */ int sqlite3_quota_remove(const char *zFilename){ - int rc = remove(zFilename); - sqlite3_quota_file(zFilename); + char *zFull; /* Full pathname for zFilename */ + int nFull; /* Number of bytes in zFilename */ + int rc; /* Result code */ + quotaGroup *pGroup; /* Group containing zFilename */ + quotaFile *pFile; /* A file in the group */ + quotaFile *pNextFile; /* next file in the group */ + int diff; /* Difference between filenames */ + char c; /* First character past end of pattern */ + + zFull = sqlite3_malloc(gQuota.sThisVfs.mxPathname + 1); + if( zFull==0 ) return SQLITE_NOMEM; + rc = gQuota.pOrigVfs->xFullPathname(gQuota.pOrigVfs, zFilename, + gQuota.sThisVfs.mxPathname+1, zFull); + if( rc ){ + sqlite3_free(zFull); + return rc; + } + + /* Figure out the length of the full pathname. If the name ends with + ** / (or \ on windows) then remove the trailing /. + */ + nFull = strlen(zFull); + if( nFull>0 && (zFull[nFull-1]=='/' || zFull[nFull-1]=='\\') ){ + nFull--; + zFull[nFull] = 0; + } + + quotaEnter(); + pGroup = quotaGroupFind(zFull); + if( pGroup ){ + for(pFile=pGroup->pFiles; pFile && rc==SQLITE_OK; pFile=pNextFile){ + pNextFile = pFile->pNext; + diff = memcmp(zFull, pFile->zFilename, nFull); + if( diff==0 && ((c = pFile->zFilename[nFull])==0 || c=='/' || c=='\\') ){ + if( pFile->nRef ){ + pFile->deleteOnClose = 1; + }else{ + rc = gQuota.pOrigVfs->xDelete(gQuota.pOrigVfs, pFile->zFilename, 0); + quotaRemoveFile(pFile); + quotaGroupDeref(pGroup); + } + } + } + } + quotaLeave(); + sqlite3_free(zFull); return rc; } - /***************************** Test Code ***********************************/ #ifdef SQLITE_TEST @@ -1445,6 +1501,28 @@ static int test_quota_fclose( return TCL_OK; } +/* +** tclcmd: sqlite3_quota_fflush HANDLE +*/ +static int test_quota_fflush( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + quota_FILE *p; + int rc; + + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "HANDLE"); + return TCL_ERROR; + } + p = sqlite3TestTextToPtr(Tcl_GetString(objv[1])); + rc = sqlite3_quota_fflush(p); + Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); + return TCL_OK; +} + /* ** tclcmd: sqlite3_quota_fseek HANDLE OFFSET WHENCE */ @@ -1589,6 +1667,7 @@ int Sqlitequota_Init(Tcl_Interp *interp){ { "sqlite3_quota_fread", test_quota_fread }, { "sqlite3_quota_fwrite", test_quota_fwrite }, { "sqlite3_quota_fclose", test_quota_fclose }, + { "sqlite3_quota_fflush", test_quota_fflush }, { "sqlite3_quota_fseek", test_quota_fseek }, { "sqlite3_quota_rewind", test_quota_rewind }, { "sqlite3_quota_ftell", test_quota_ftell }, diff --git a/src/test_quota.h b/src/test_quota.h index 6df423f5d1..dbcb2c185c 100644 --- a/src/test_quota.h +++ b/src/test_quota.h @@ -101,6 +101,10 @@ int sqlite3_quota_shutdown(void); ** database connections if those connections are to participate in the ** quota group. Creating a quota group does not affect database connections ** that are already open. +** +** The patterns that define the various quota groups should be distinct. +** If the same filename matches more than one quota group pattern, then +** the behavior of this package is undefined. */ int sqlite3_quota_set( const char *zPattern, /* The filename pattern */ @@ -116,14 +120,20 @@ int sqlite3_quota_set( ); /* -** Bring the named file under quota management. Or if it is already under -** management, update its size. +** Bring the named file under quota management, assuming its name matches +** the glob pattern of some quota group. Or if it is already under +** management, update its size. If zFilename does not match the glob +** pattern of any quota group, this routine is a no-op. */ int sqlite3_quota_file(const char *zFilename); /* ** The following object serves the same role as FILE in the standard C ** library. It represents an open connection to a file on disk for I/O. +** +** A single quota_FILE should not be used by two or more threads at the +** same time. Multiple threads can be using different quota_FILE objects +** simultaneously, but not the same quota_FILE object. */ typedef struct quota_FILE quota_FILE; @@ -141,6 +151,13 @@ quota_FILE *sqlite3_quota_fopen(const char *zFilename, const char *zMode); size_t sqlite3_quota_fread(void*, size_t, size_t, quota_FILE*); size_t sqlite3_quota_fwrite(void*, size_t, size_t, quota_FILE*); +/* +** Flush all written content held in memory buffers out to disk. +** This is the equivalent of fflush() in the standard library - not +** an fsync(). +*/ +int sqlite3_quota_fflush(quota_FILE*); + /* ** Close a quota_FILE object and free all associated resources. The ** file remains under quota management. @@ -156,11 +173,23 @@ void sqlite3_quota_rewind(quota_FILE*); long sqlite3_quota_ftell(quota_FILE*); /* -** Delete a file from the disk. If that file is under quota management, -** then adjust quotas accordingly. +** Delete a file from the disk, if that file is under quota management. +** Adjust quotas accordingly. ** -** The file being deleted must not be open for reading or writing or as -** a database when it is deleted. +** If zFilename is the name of a directory that matches one of the +** quota glob patterns, then all files under quota management that +** are contained within that directory are deleted. +** +** A standard SQLite result code is returned (SQLITE_OK, SQLITE_NOMEM, etc.) +** When deleting a directory of files, if the deletion of any one +** file fails (for example due to an I/O error), then this routine +** returns immediately, with the error code, and does not try to +** delete any of the other files in the specified directory. +** +** All files are removed from quota management and deleted from disk. +** However, no attempt is made to remove empty directories. +** +** This routine is a no-op for files that are not under quota management. */ int sqlite3_quota_remove(const char *zFilename); diff --git a/test/quota2.test b/test/quota2.test index d408cda9ca..4b9daca2a2 100644 --- a/test/quota2.test +++ b/test/quota2.test @@ -17,8 +17,10 @@ source $testdir/malloc_common.tcl db close sqlite3_quota_initialize "" 1 -foreach dir {quota2a quota2b quota2c} { +foreach dir {quota2a/x1 quota2a/x2 quota2a quota2b quota2c} { file delete -force $dir +} +foreach dir {quota2a quota2a/x1 quota2a/x2 quota2b quota2c} { file mkdir $dir } @@ -109,11 +111,11 @@ do_test quota2-1.10 { do_test quota2-1.11 { standard_path [sqlite3_quota_dump] } {{*/quota2b/* 5000 0} {*/quota2a/* 4000 4000 {PWD/quota2a/xyz.txt 4000 1 0}}} -do_test quota1-1.12 { +do_test quota2-1.12 { sqlite3_quota_fclose $::h1 standard_path [sqlite3_quota_dump] } {{*/quota2b/* 5000 0} {*/quota2a/* 4000 4000 {PWD/quota2a/xyz.txt 4000 0 0}}} -do_test quota1-1.13 { +do_test quota2-1.13 { sqlite3_quota_remove quota2a/xyz.txt standard_path [sqlite3_quota_dump] } {{*/quota2b/* 5000 0} {*/quota2a/* 4000 0}} @@ -162,11 +164,65 @@ do_test quota2-2.10 { do_test quota2-2.11 { standard_path [sqlite3_quota_dump] } {{*/quota2b/* 5000 0} {*/quota2a/* 4000 0}} -do_test quota1-2.12 { +do_test quota2-2.12 { sqlite3_quota_fclose $::h1 standard_path [sqlite3_quota_dump] } {{*/quota2b/* 5000 0} {*/quota2a/* 4000 0}} +do_test quota2-3.1 { + sqlite3_quota_set */quota2b/* 0 quota_check + set ::h1 [sqlite3_quota_fopen quota2a/x1/a.txt a] + sqlite3_quota_fwrite $::h1 10 10 $bigtext +} {10} +do_test quota2-3.2 { + standard_path [sqlite3_quota_dump] +} {{*/quota2a/* 4000 100 {PWD/quota2a/x1/a.txt 100 1 0}}} +do_test quota2-3.3 { + sqlite3_quota_fflush $::h1 + standard_path [sqlite3_quota_dump] +} {{*/quota2a/* 4000 100 {PWD/quota2a/x1/a.txt 100 1 0}}} +do_test quota2-3.4 { + sqlite3_quota_fclose $::h1 + standard_path [sqlite3_quota_dump] +} {{*/quota2a/* 4000 100 {PWD/quota2a/x1/a.txt 100 0 0}}} +do_test quota2-3.5 { + set ::h2 [sqlite3_quota_fopen quota2a/x2/b.txt a] + sqlite3_quota_fwrite $::h2 10 20 $bigtext + standard_path [sqlite3_quota_dump] +} {{*/quota2a/* 4000 300 {PWD/quota2a/x2/b.txt 200 1 0} {PWD/quota2a/x1/a.txt 100 0 0}}} +do_test quota2-3.6 { + set ::h3 [sqlite3_quota_fopen quota2a/x1/c.txt a] + sqlite3_quota_fwrite $::h3 10 50 $bigtext + standard_path [sqlite3_quota_dump] +} {{*/quota2a/* 4000 800 {PWD/quota2a/x1/c.txt 500 1 0} {PWD/quota2a/x2/b.txt 200 1 0} {PWD/quota2a/x1/a.txt 100 0 0}}} +do_test quota2-3.7 { + file exists quota2a/x1/a.txt +} {1} +do_test quota2-3.8 { + file exists quota2a/x2/b.txt +} {1} +do_test quota2-3.9 { + file exists quota2a/x1/c.txt +} {1} +do_test quota2-3.10 { + sqlite3_quota_remove quota2a/x1 + standard_path [sqlite3_quota_dump] +} {{*/quota2a/* 4000 700 {PWD/quota2a/x1/c.txt 500 1 1} {PWD/quota2a/x2/b.txt 200 1 0}}} +do_test quota2-3.11 { + sqlite3_quota_fclose $::h2 + sqlite3_quota_fclose $::h3 + standard_path [sqlite3_quota_dump] +} {{*/quota2a/* 4000 200 {PWD/quota2a/x2/b.txt 200 0 0}}} +do_test quota2-3.12 { + file exists quota2a/x1/a.txt +} {0} +do_test quota2-3.13 { + file exists quota2a/x2/b.txt +} {1} +do_test quota2-3.14 { + file exists quota2a/x1/c.txt +} {0} + catch { sqlite3_quota_shutdown } catch { unset quota_request_ok } finish_test From 663cebfeaed8b365d69246ed5f4d843d53f9be24 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 12 Dec 2011 19:47:25 +0000 Subject: [PATCH 08/11] Make sure the quota logic is usable as C++. FossilOrigin-Name: f4534bd3023a599691018f35389a76045e49d831 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/test_quota.c | 11 ++++++----- src/test_quota.h | 8 ++++++++ 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/manifest b/manifest index e49d82bcc0..af26387f87 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\ssqlite3_quota_fflush()\sinterface.\s\sEnhance\ssqlite3_quota_remove()\nso\sthat\sit\scan\sremove\sentire\sdirectories. -D 2011-12-03T00:13:06.592 +C Make\ssure\sthe\squota\slogic\sis\susable\sas\sC++. +D 2011-12-12T19:47:25.223 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5b4a3e12a850b021547e43daf886b25133b44c07 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -220,8 +220,8 @@ F src/test_mutex.c a6bd7b9cf6e19d989e31392b06ac8d189f0d573e F src/test_onefile.c 40cf9e212a377a6511469384a64b01e6e34b2eec F src/test_osinst.c 62b0b8ef21ce754cc94e17bb42377ed8795dba32 F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00 -F src/test_quota.c 2e6191cbfc6ae978330a0d0ffcc3fb81b7059e68 -F src/test_quota.h 9b3c75a79e8c3c6a9d3846b73435bebcd550ba12 +F src/test_quota.c 5259eaa0c98b1f55cbce1f34ed7043ae9538911e +F src/test_quota.h 98cb0cdc4b4c0fa917f7f43734127f6d182e94fa F src/test_rtree.c 6d06306e29946dc36f528a3a2cdc3add794656f1 F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0 F src/test_server.c 2f99eb2837dfa06a4aacf24af24c6affdf66a84f @@ -979,7 +979,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P 8cfd3575c8d9f5361c5276d6b83aba47606975a3 -R 28ca02cd727421756b639f8157eb6391 +P abcb65af4cdd192beaccdbc2109ad45b9e7f9d00 +R 219a0e733f4a37c7491a23e5eb8ab5d1 U drh -Z 84dc1ce8a56d57cb5251e17d63b686ff +Z ccc24742bcaed950386a7bec659a920b diff --git a/manifest.uuid b/manifest.uuid index 83ef24af72..ecb5e3b1f6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -abcb65af4cdd192beaccdbc2109ad45b9e7f9d00 \ No newline at end of file +f4534bd3023a599691018f35389a76045e49d831 \ No newline at end of file diff --git a/src/test_quota.c b/src/test_quota.c index c073b47d28..3ea3af0643 100644 --- a/src/test_quota.c +++ b/src/test_quota.c @@ -905,7 +905,8 @@ int sqlite3_quota_file(const char *zFilename){ int rc; int outFlags = 0; sqlite3_int64 iSize; - fd = sqlite3_malloc(gQuota.sThisVfs.szOsFile + gQuota.sThisVfs.mxPathname+1); + fd = (sqlite3_file*)sqlite3_malloc(gQuota.sThisVfs.szOsFile + + gQuota.sThisVfs.mxPathname+1); if( fd==0 ) return SQLITE_NOMEM; zFull = gQuota.sThisVfs.szOsFile + (char*)fd; rc = gQuota.pOrigVfs->xFullPathname(gQuota.pOrigVfs, zFilename, @@ -943,12 +944,12 @@ quota_FILE *sqlite3_quota_fopen(const char *zFilename, const char *zMode){ quotaGroup *pGroup; quotaFile *pFile; - zFull = sqlite3_malloc(gQuota.sThisVfs.mxPathname + 1); + zFull = (char*)sqlite3_malloc(gQuota.sThisVfs.mxPathname + 1); if( zFull==0 ) return 0; rc = gQuota.pOrigVfs->xFullPathname(gQuota.pOrigVfs, zFilename, gQuota.sThisVfs.mxPathname+1, zFull); if( rc ) goto quota_fopen_error; - p = sqlite3_malloc(sizeof(*p)); + p = (quota_FILE*)sqlite3_malloc(sizeof(*p)); if( p==0 ) goto quota_fopen_error; memset(p, 0, sizeof(*p)); zFullTranslated = quota_utf8_to_mbcs(zFull); @@ -1097,7 +1098,7 @@ int sqlite3_quota_remove(const char *zFilename){ int diff; /* Difference between filenames */ char c; /* First character past end of pattern */ - zFull = sqlite3_malloc(gQuota.sThisVfs.mxPathname + 1); + zFull = (char*)sqlite3_malloc(gQuota.sThisVfs.mxPathname + 1); if( zFull==0 ) return SQLITE_NOMEM; rc = gQuota.pOrigVfs->xFullPathname(gQuota.pOrigVfs, zFilename, gQuota.sThisVfs.mxPathname+1, zFull); @@ -1438,7 +1439,7 @@ static int test_quota_fread( p = sqlite3TestTextToPtr(Tcl_GetString(objv[1])); if( Tcl_GetIntFromObj(interp, objv[2], &sz) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[3], &nElem) ) return TCL_ERROR; - zBuf = sqlite3_malloc( sz*nElem + 1 ); + zBuf = (char*)sqlite3_malloc( sz*nElem + 1 ); if( zBuf==0 ){ Tcl_SetResult(interp, "out of memory", TCL_STATIC); return TCL_ERROR; diff --git a/src/test_quota.h b/src/test_quota.h index dbcb2c185c..5dab714176 100644 --- a/src/test_quota.h +++ b/src/test_quota.h @@ -30,6 +30,11 @@ #include "sqlite3.h" #include +/* Make this callable from C++ */ +#ifdef __cplusplus +extern "C" { +#endif + /* ** Initialize the quota VFS shim. Use the VFS named zOrigVfsName ** as the VFS that does the actual work. Use the default if @@ -193,4 +198,7 @@ long sqlite3_quota_ftell(quota_FILE*); */ int sqlite3_quota_remove(const char *zFilename); +#ifdef __cplusplus +} /* end of the 'extern "C"' block */ +#endif #endif /* _QUOTA_H_ */ From 27cec37d8e8ad5493b2225ff707bcdb7c79a1bd6 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 13 Dec 2011 23:26:10 +0000 Subject: [PATCH 09/11] Enhancements to test_quota.c: Remove the external dependency on sqlite3_win32_utf8_to_msbc(). Add an extra parameter to quota_fflush() that will also do an fsync (or the equivalent). FossilOrigin-Name: 92f4188f90e3cdd71f1457a6e0eb22615e4a54f4 --- manifest | 16 +++++++------- manifest.uuid | 2 +- src/test_quota.c | 54 +++++++++++++++++++++++++++++++++++++++++------- src/test_quota.h | 11 +++++++--- test/quota2.test | 10 ++++++++- 5 files changed, 72 insertions(+), 21 deletions(-) diff --git a/manifest b/manifest index af26387f87..0a28bcdaa2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Make\ssure\sthe\squota\slogic\sis\susable\sas\sC++. -D 2011-12-12T19:47:25.223 +C Enhancements\sto\stest_quota.c:\s\sRemove\sthe\sexternal\sdependency\son\s\nsqlite3_win32_utf8_to_msbc().\s\sAdd\san\sextra\sparameter\sto\squota_fflush()\nthat\swill\salso\sdo\san\sfsync\s(or\sthe\sequivalent). +D 2011-12-13T23:26:10.637 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5b4a3e12a850b021547e43daf886b25133b44c07 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -220,8 +220,8 @@ F src/test_mutex.c a6bd7b9cf6e19d989e31392b06ac8d189f0d573e F src/test_onefile.c 40cf9e212a377a6511469384a64b01e6e34b2eec F src/test_osinst.c 62b0b8ef21ce754cc94e17bb42377ed8795dba32 F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00 -F src/test_quota.c 5259eaa0c98b1f55cbce1f34ed7043ae9538911e -F src/test_quota.h 98cb0cdc4b4c0fa917f7f43734127f6d182e94fa +F src/test_quota.c fc7d4c4f8538396c1b0116efef695f9f33f984e7 +F src/test_quota.h 9ffa1d3ad6d0a6a24e8670ea64b909c717ec3358 F src/test_rtree.c 6d06306e29946dc36f528a3a2cdc3add794656f1 F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0 F src/test_server.c 2f99eb2837dfa06a4aacf24af24c6affdf66a84f @@ -636,7 +636,7 @@ F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc F test/quick.test 1681febc928d686362d50057c642f77a02c62e57 F test/quota-glob.test 32901e9eed6705d68ca3faee2a06b73b57cb3c26 F test/quota.test 46e6571b45c3c58ac131cc38f7d600aa9f75974d -F test/quota2.test 562b27570d1e0d0606c3769b648e23c72fa3859b +F test/quota2.test 1b8df088e604f2df573f96e726b5e518cb0cddaa F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6 F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459 F test/randexpr1.test 1084050991e9ba22c1c10edd8d84673b501cc25a @@ -979,7 +979,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P abcb65af4cdd192beaccdbc2109ad45b9e7f9d00 -R 219a0e733f4a37c7491a23e5eb8ab5d1 +P f4534bd3023a599691018f35389a76045e49d831 +R 47ed3793a4d313cda8ae0615d4d258b5 U drh -Z ccc24742bcaed950386a7bec659a920b +Z a4d5e00fab55c6c4275b01f8f924030e diff --git a/manifest.uuid b/manifest.uuid index ecb5e3b1f6..76cee7109d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f4534bd3023a599691018f35389a76045e49d831 \ No newline at end of file +92f4188f90e3cdd71f1457a6e0eb22615e4a54f4 \ No newline at end of file diff --git a/src/test_quota.c b/src/test_quota.c index 3ea3af0643..e8eac19652 100644 --- a/src/test_quota.c +++ b/src/test_quota.c @@ -404,6 +404,12 @@ static quotaFile *quotaFindFile( # endif #endif +#if SQLITE_OS_UNIX +# include +#endif +#if SQLITE_OS_WIN +# include +#endif /* ** Translate UTF8 to MBCS for use in fopen() calls. Return a pointer to the @@ -412,8 +418,26 @@ static quotaFile *quotaFindFile( */ static char *quota_utf8_to_mbcs(const char *zUtf8){ #if SQLITE_OS_WIN - extern char *sqlite3_win32_utf8_to_mbcs(const char*); - return sqlite3_win32_utf8_to_mbcs(zUtf8); + int n; /* Bytes in zUtf8 */ + int nWide; /* number of UTF-16 characters */ + int nMbcs; /* Bytes of MBCS */ + LPWSTR zTmpWide; /* The UTF16 text */ + char *zMbcs; /* The MBCS text */ + int codepage; /* Code page used by fopen() */ + + n = strlen(zUtf8); + nWide = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, NULL, 0); + zTmpWide = sqlite3_malloc( nWide*sizeof(zTmpWide[0]) ); + if( zTmpWide==0 ) return 0; + MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zTmpWide, nWide); + codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; + nMbcs = WideCharToMultiByte(codepage, 0, zTmpWide, nWide, 0, 0, 0, 0); + zMbcs = sqlite3_malloc( nMbcs+1 ); + if( zMbcs ){ + WideCharToMultiByte(codepage, 0, zTmpWide, nWide, zMbcs, nMbcs, 0, 0); + } + sqlite3_free(zTmpWide); + return zMbcs; #else return (char*)zUtf8; /* No-op on unix */ #endif @@ -1060,8 +1084,18 @@ int sqlite3_quota_fclose(quota_FILE *p){ /* ** Flush memory buffers for a quota_FILE to disk. */ -int sqlite3_quota_fflush(quota_FILE *p){ - return fflush(p->f); +int sqlite3_quota_fflush(quota_FILE *p, int doFsync){ + int rc; + rc = fflush(p->f); + if( rc==0 && doFsync ){ +#if SQLITE_OS_UNIX + rc = fsync(fileno(p->f)); +#endif +#if SQLITE_OS_WIN + rc = 0==FlushFileBuffers((HANDLE)_fileno(p->f)); +#endif + } + return rc; } /* @@ -1503,7 +1537,7 @@ static int test_quota_fclose( } /* -** tclcmd: sqlite3_quota_fflush HANDLE +** tclcmd: sqlite3_quota_fflush HANDLE ?HARDSYNC? */ static int test_quota_fflush( void * clientData, @@ -1513,13 +1547,17 @@ static int test_quota_fflush( ){ quota_FILE *p; int rc; + int doSync = 0; - if( objc!=2 ){ - Tcl_WrongNumArgs(interp, 1, objv, "HANDLE"); + if( objc!=2 && objc!=3 ){ + Tcl_WrongNumArgs(interp, 1, objv, "HANDLE ?HARDSYNC?"); return TCL_ERROR; } p = sqlite3TestTextToPtr(Tcl_GetString(objv[1])); - rc = sqlite3_quota_fflush(p); + if( objc==3 ){ + if( Tcl_GetBooleanFromObj(interp, objv[2], &doSync) ) return TCL_ERROR; + } + rc = sqlite3_quota_fflush(p, doSync); Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); return TCL_OK; } diff --git a/src/test_quota.h b/src/test_quota.h index 5dab714176..a2fddbbc43 100644 --- a/src/test_quota.h +++ b/src/test_quota.h @@ -158,10 +158,15 @@ size_t sqlite3_quota_fwrite(void*, size_t, size_t, quota_FILE*); /* ** Flush all written content held in memory buffers out to disk. -** This is the equivalent of fflush() in the standard library - not -** an fsync(). +** This is the equivalent of fflush() in the standard library. +** +** If the hardSync parameter is true (non-zero) then this routine +** also forces OS buffers to disk - the equivalent of fsync(). +** +** This routine return zero on success and non-zero if something goes +** wrong. */ -int sqlite3_quota_fflush(quota_FILE*); +int sqlite3_quota_fflush(quota_FILE*, int hardSync); /* ** Close a quota_FILE object and free all associated resources. The diff --git a/test/quota2.test b/test/quota2.test index 4b9daca2a2..cf3449dafc 100644 --- a/test/quota2.test +++ b/test/quota2.test @@ -177,7 +177,15 @@ do_test quota2-3.1 { do_test quota2-3.2 { standard_path [sqlite3_quota_dump] } {{*/quota2a/* 4000 100 {PWD/quota2a/x1/a.txt 100 1 0}}} -do_test quota2-3.3 { +do_test quota2-3.3a { + sqlite3_quota_fflush $::h1 0 + standard_path [sqlite3_quota_dump] +} {{*/quota2a/* 4000 100 {PWD/quota2a/x1/a.txt 100 1 0}}} +do_test quota2-3.3b { + sqlite3_quota_fflush $::h1 1 + standard_path [sqlite3_quota_dump] +} {{*/quota2a/* 4000 100 {PWD/quota2a/x1/a.txt 100 1 0}}} +do_test quota2-3.3c { sqlite3_quota_fflush $::h1 standard_path [sqlite3_quota_dump] } {{*/quota2a/* 4000 100 {PWD/quota2a/x1/a.txt 100 1 0}}} From 49ed5c8562cbf9059d454c0ac68cd38ae2b38f66 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 14 Dec 2011 00:04:52 +0000 Subject: [PATCH 10/11] Harden the utf8-to-mbcs converter in the quota module against failures. FossilOrigin-Name: 1cda511deb625868395a23c95346e14d0c300670 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/test_quota.c | 5 +++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 0a28bcdaa2..eb499cd1b5 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhancements\sto\stest_quota.c:\s\sRemove\sthe\sexternal\sdependency\son\s\nsqlite3_win32_utf8_to_msbc().\s\sAdd\san\sextra\sparameter\sto\squota_fflush()\nthat\swill\salso\sdo\san\sfsync\s(or\sthe\sequivalent). -D 2011-12-13T23:26:10.637 +C Harden\sthe\sutf8-to-mbcs\sconverter\sin\sthe\squota\smodule\sagainst\sfailures. +D 2011-12-14T00:04:52.373 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5b4a3e12a850b021547e43daf886b25133b44c07 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -220,7 +220,7 @@ F src/test_mutex.c a6bd7b9cf6e19d989e31392b06ac8d189f0d573e F src/test_onefile.c 40cf9e212a377a6511469384a64b01e6e34b2eec F src/test_osinst.c 62b0b8ef21ce754cc94e17bb42377ed8795dba32 F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00 -F src/test_quota.c fc7d4c4f8538396c1b0116efef695f9f33f984e7 +F src/test_quota.c 2552dfd897d2d74ecc368487fa5859e9a2b254ab F src/test_quota.h 9ffa1d3ad6d0a6a24e8670ea64b909c717ec3358 F src/test_rtree.c 6d06306e29946dc36f528a3a2cdc3add794656f1 F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0 @@ -979,7 +979,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P f4534bd3023a599691018f35389a76045e49d831 -R 47ed3793a4d313cda8ae0615d4d258b5 +P 92f4188f90e3cdd71f1457a6e0eb22615e4a54f4 +R 628f1bcc3bb63f06518edb62745f94e5 U drh -Z a4d5e00fab55c6c4275b01f8f924030e +Z 2cf614ef38a2cb741ec717409dbd005d diff --git a/manifest.uuid b/manifest.uuid index 76cee7109d..1cd189003e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -92f4188f90e3cdd71f1457a6e0eb22615e4a54f4 \ No newline at end of file +1cda511deb625868395a23c95346e14d0c300670 \ No newline at end of file diff --git a/src/test_quota.c b/src/test_quota.c index e8eac19652..e2c0808969 100644 --- a/src/test_quota.c +++ b/src/test_quota.c @@ -427,12 +427,13 @@ static char *quota_utf8_to_mbcs(const char *zUtf8){ n = strlen(zUtf8); nWide = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, NULL, 0); - zTmpWide = sqlite3_malloc( nWide*sizeof(zTmpWide[0]) ); + if( nWide==0 ) return 0; + zTmpWide = sqlite3_malloc( (nWide+1)*sizeof(zTmpWide[0]) ); if( zTmpWide==0 ) return 0; MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zTmpWide, nWide); codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; nMbcs = WideCharToMultiByte(codepage, 0, zTmpWide, nWide, 0, 0, 0, 0); - zMbcs = sqlite3_malloc( nMbcs+1 ); + zMbcs = nMbcs ? sqlite3_malloc( nMbcs+1 ) : 0; if( zMbcs ){ WideCharToMultiByte(codepage, 0, zTmpWide, nWide, zMbcs, nMbcs, 0, 0); } From c39f3e0085710806a3a19ac2eff8d5f099245893 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 15 Dec 2011 17:42:35 +0000 Subject: [PATCH 11/11] Use _commit() rather than FlushFileBuffers() as a substitute for fsync() on windows. Also cast for C++ and add support for SQLITE_FCNTL_VFSNAME. FossilOrigin-Name: e85cfe9a17a2943ee0cf7915451ff6cc05908030 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/test_quota.c | 17 ++++++++++++----- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index eb499cd1b5..90096462db 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Harden\sthe\sutf8-to-mbcs\sconverter\sin\sthe\squota\smodule\sagainst\sfailures. -D 2011-12-14T00:04:52.373 +C Use\s_commit()\srather\sthan\sFlushFileBuffers()\sas\sa\ssubstitute\sfor\sfsync()\non\swindows.\s\sAlso\scast\sfor\sC++\sand\sadd\ssupport\sfor\sSQLITE_FCNTL_VFSNAME. +D 2011-12-15T17:42:35.299 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5b4a3e12a850b021547e43daf886b25133b44c07 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -220,7 +220,7 @@ F src/test_mutex.c a6bd7b9cf6e19d989e31392b06ac8d189f0d573e F src/test_onefile.c 40cf9e212a377a6511469384a64b01e6e34b2eec F src/test_osinst.c 62b0b8ef21ce754cc94e17bb42377ed8795dba32 F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00 -F src/test_quota.c 2552dfd897d2d74ecc368487fa5859e9a2b254ab +F src/test_quota.c 1a5874e3ee9074426f43b37e8d7404948065b585 F src/test_quota.h 9ffa1d3ad6d0a6a24e8670ea64b909c717ec3358 F src/test_rtree.c 6d06306e29946dc36f528a3a2cdc3add794656f1 F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0 @@ -979,7 +979,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P 92f4188f90e3cdd71f1457a6e0eb22615e4a54f4 -R 628f1bcc3bb63f06518edb62745f94e5 +P 1cda511deb625868395a23c95346e14d0c300670 +R b97a14183d24f2ef8a473c4b8d89de75 U drh -Z 2cf614ef38a2cb741ec717409dbd005d +Z 78d66bb3da81c929977c8b164844aeef diff --git a/manifest.uuid b/manifest.uuid index 1cd189003e..39ac2ffec5 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1cda511deb625868395a23c95346e14d0c300670 \ No newline at end of file +e85cfe9a17a2943ee0cf7915451ff6cc05908030 \ No newline at end of file diff --git a/src/test_quota.c b/src/test_quota.c index e2c0808969..4529bd3028 100644 --- a/src/test_quota.c +++ b/src/test_quota.c @@ -409,6 +409,7 @@ static quotaFile *quotaFindFile( #endif #if SQLITE_OS_WIN # include +# include #endif /* @@ -428,12 +429,12 @@ static char *quota_utf8_to_mbcs(const char *zUtf8){ n = strlen(zUtf8); nWide = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, NULL, 0); if( nWide==0 ) return 0; - zTmpWide = sqlite3_malloc( (nWide+1)*sizeof(zTmpWide[0]) ); + zTmpWide = (LPWSTR)sqlite3_malloc( (nWide+1)*sizeof(zTmpWide[0]) ); if( zTmpWide==0 ) return 0; MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zTmpWide, nWide); codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; nMbcs = WideCharToMultiByte(codepage, 0, zTmpWide, nWide, 0, 0, 0, 0); - zMbcs = nMbcs ? sqlite3_malloc( nMbcs+1 ) : 0; + zMbcs = nMbcs ? (char*)sqlite3_malloc( nMbcs+1 ) : 0; if( zMbcs ){ WideCharToMultiByte(codepage, 0, zTmpWide, nWide, zMbcs, nMbcs, 0, 0); } @@ -714,7 +715,13 @@ static int quotaCheckReservedLock(sqlite3_file *pConn, int *pResOut){ */ static int quotaFileControl(sqlite3_file *pConn, int op, void *pArg){ sqlite3_file *pSubOpen = quotaSubOpen(pConn); - return pSubOpen->pMethods->xFileControl(pSubOpen, op, pArg); + int rc = pSubOpen->pMethods->xFileControl(pSubOpen, op, pArg); +#if defined(SQLITE_FCNTL_VFSNAME) + if( op==SQLITE_FCNTL_VFSNAME && rc==SQLITE_OK ){ + *(char**)pArg = sqlite3_mprintf("quota/%z", *(char**)pArg); + } +#endif + return rc; } /* Pass xSectorSize requests through to the original VFS unchanged. @@ -1093,10 +1100,10 @@ int sqlite3_quota_fflush(quota_FILE *p, int doFsync){ rc = fsync(fileno(p->f)); #endif #if SQLITE_OS_WIN - rc = 0==FlushFileBuffers((HANDLE)_fileno(p->f)); + rc = _commit(_fileno(p->f)); #endif } - return rc; + return rc!=0; } /*