aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2011-12-03 00:13:06 +0000
committerdrh <drh@noemail.net>2011-12-03 00:13:06 +0000
commit69b2232d6e2cfe4a5d1cd25d48af015ee1faac7b (patch)
tree703697081a6183c607575b55e0b72bd3894ec734 /src
parenta0036917350bff6ca89bef8d135a6c8ad1770f48 (diff)
downloadsqlite-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.c91
-rw-r--r--src/test_quota.h41
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);