diff options
author | drh <drh@noemail.net> | 2011-12-03 00:13:06 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2011-12-03 00:13:06 +0000 |
commit | 69b2232d6e2cfe4a5d1cd25d48af015ee1faac7b (patch) | |
tree | 703697081a6183c607575b55e0b72bd3894ec734 /src | |
parent | a0036917350bff6ca89bef8d135a6c8ad1770f48 (diff) | |
download | sqlite-69b2232d6e2cfe4a5d1cd25d48af015ee1faac7b.tar.gz sqlite-69b2232d6e2cfe4a5d1cd25d48af015ee1faac7b.zip |
Add the sqlite3_quota_fflush() interface. Enhance sqlite3_quota_remove()
so that it can remove entire directories.
FossilOrigin-Name: abcb65af4cdd192beaccdbc2109ad45b9e7f9d00
Diffstat (limited to 'src')
-rw-r--r-- | src/test_quota.c | 91 | ||||
-rw-r--r-- | src/test_quota.h | 41 |
2 files changed, 120 insertions, 12 deletions
diff --git a/src/test_quota.c b/src/test_quota.c index 479cf0f0d..c073b47d2 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(); @@ -1051,6 +1057,13 @@ 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); +} + +/* ** Seek on a quota_FILE stream. */ int sqlite3_quota_fseek(quota_FILE *p, long offset, int whence){ @@ -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 @@ -1446,6 +1502,28 @@ static int test_quota_fclose( } /* +** 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 */ static int test_quota_fseek( @@ -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 6df423f5d..dbcb2c185 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; @@ -142,6 +152,13 @@ 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. +** +** 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. ** -** The file being deleted must not be open for reading or writing or as -** a database when it is deleted. +** This routine is a no-op for files that are not under quota management. */ int sqlite3_quota_remove(const char *zFilename); |