15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 2010 September 31 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The author disclaims copyright to this source code. In place of 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** a legal notice, here is a blessing: 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** May you do good and not evil. 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** May you find forgiveness for yourself and forgive others. 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** May you share freely, never taking more than you give. 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)************************************************************************* 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This file contains a VFS "shim" - a layer that sits in between the 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** pager and the real VFS. 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This particular shim enforces a quota system on files. One or more 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** database files are in a "quota group" that is defined by a GLOB 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** pattern. A quota is set for the combined size of all files in the 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** the group. A quota of zero means "no limit". If the total size 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** of all files in the quota group is greater than the limit, then 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** write requests that attempt to enlarge a file fail with SQLITE_FULL. 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** However, before returning SQLITE_FULL, the write requests invoke 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** a callback function that is configurable for each quota group. 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This callback has the opportunity to enlarge the quota. If the 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** callback does enlarge the quota such that the total size of all 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** files within the group is less than the new quota, then the write 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** continues as if nothing had happened. 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sqlite3.h" 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h> 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <assert.h> 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** For an build without mutexes, no-op the mutex calls. 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE==0 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define sqlite3_mutex_alloc(X) ((sqlite3_mutex*)8) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define sqlite3_mutex_free(X) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define sqlite3_mutex_enter(X) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define sqlite3_mutex_try(X) SQLITE_OK 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define sqlite3_mutex_leave(X) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define sqlite3_mutex_held(X) ((void)(X),1) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define sqlite3_mutex_notheld(X) ((void)(X),1) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif /* SQLITE_THREADSAFE==0 */ 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/************************ Object Definitions ******************************/ 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Forward declaration of all object types */ 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct quotaGroup quotaGroup; 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct quotaConn quotaConn; 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct quotaFile quotaFile; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** A "quota group" is a collection of files whose collective size we want 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** to limit. Each quota group is defined by a GLOB pattern. 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** There is an instance of the following object for each defined quota 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** group. This object records the GLOB pattern that defines which files 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** belong to the quota group. The object also remembers the size limit 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** for the group (the quota) and the callback to be invoked when the 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** sum of the sizes of the files within the group goes over the limit. 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** A quota group must be established (using sqlite3_quota_set(...)) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** prior to opening any of the database connections that access files 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** within the quota group. 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct quotaGroup { 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *zPattern; /* Filename pattern to be quotaed */ 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_int64 iLimit; /* Upper bound on total file size */ 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_int64 iSize; /* Current size of all files */ 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void (*xCallback)( /* Callback invoked when going over quota */ 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *zFilename, /* Name of file whose size increases */ 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_int64 *piLimit, /* IN/OUT: The current limit */ 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_int64 iSize, /* Total size of all files in the group */ 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void *pArg /* Client data */ 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ); 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void *pArg; /* Third argument to the xCallback() */ 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void (*xDestroy)(void*); /* Optional destructor for pArg */ 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaGroup *pNext, **ppPrev; /* Doubly linked list of all quota objects */ 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaFile *pFiles; /* Files within this group */ 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** An instance of this structure represents a single file that is part 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** of a quota group. A single file can be opened multiple times. In 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** order keep multiple openings of the same file from causing the size 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** of the file to count against the quota multiple times, each file 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** has a unique instance of this object and multiple open connections 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** to the same file each point to a single instance of this object. 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct quotaFile { 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *zFilename; /* Name of this file */ 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaGroup *pGroup; /* Quota group to which this file belongs */ 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_int64 iSize; /* Current size of this file */ 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int nRef; /* Number of times this file is open */ 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaFile *pNext, **ppPrev; /* Linked list of files in the same group */ 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** An instance of the following object represents each open connection 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** to a file that participates in quota tracking. This object is a 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** subclass of sqlite3_file. The sqlite3_file object for the underlying 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** VFS is appended to this structure. 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct quotaConn { 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_file base; /* Base class - must be first */ 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaFile *pFile; /* The underlying file */ 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* The underlying VFS sqlite3_file is appended to this object */ 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/************************* Global Variables **********************************/ 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** All global variables used by this file are containing within the following 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** gQuota structure. 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct { 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* The pOrigVfs is the real, original underlying VFS implementation. 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ** Most operations pass-through to the real VFS. This value is read-only 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ** during operation. It is only modified at start-time and thus does not 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ** require a mutex. 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_vfs *pOrigVfs; 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* The sThisVfs is the VFS structure used by this shim. It is initialized 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ** at start-time and thus does not require a mutex 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_vfs sThisVfs; 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* The sIoMethods defines the methods used by sqlite3_file objects 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ** associated with this shim. It is initialized at start-time and does 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ** not require a mutex. 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ** 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ** When the underlying VFS is called to open a file, it might return 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ** either a version 1 or a version 2 sqlite3_file object. This shim 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ** has to create a wrapper sqlite3_file of the same version. Hence 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ** there are two I/O method structures, one for version 1 and the other 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ** for version 2. 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_io_methods sIoMethodsV1; 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_io_methods sIoMethodsV2; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* True when this shim as been initialized. 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int isInitialized; 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* For run-time access any of the other global data structures in this 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ** shim, the following mutex must be held. 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_mutex *pMutex; 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* List of quotaGroup objects. 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaGroup *pGroup; 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} gQuota; 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/************************* Utility Routines *********************************/ 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Acquire and release the mutex used to serialize access to the 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** list of quotaGroups. 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void quotaEnter(void){ sqlite3_mutex_enter(gQuota.pMutex); } 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void quotaLeave(void){ sqlite3_mutex_leave(gQuota.pMutex); } 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* If the reference count and threshold for a quotaGroup are both 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** zero, then destroy the quotaGroup. 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void quotaGroupDeref(quotaGroup *pGroup){ 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( pGroup->pFiles==0 && pGroup->iLimit==0 ){ 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *pGroup->ppPrev = pGroup->pNext; 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( pGroup->pNext ) pGroup->pNext->ppPrev = pGroup->ppPrev; 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( pGroup->xDestroy ) pGroup->xDestroy(pGroup->pArg); 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_free(pGroup); 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Return TRUE if string z matches glob pattern zGlob. 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Globbing rules: 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** '*' Matches any sequence of zero or more characters. 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** '?' Matches exactly one character. 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** [...] Matches one character from the enclosed list of 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** characters. 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** [^...] Matches one character not in the enclosed list. 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int quotaStrglob(const char *zGlob, const char *z){ 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int c, c2; 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int invert; 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int seen; 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while( (c = (*(zGlob++)))!=0 ){ 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( c=='*' ){ 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while( (c=(*(zGlob++))) == '*' || c=='?' ){ 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( c=='?' && (*(z++))==0 ) return 0; 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( c==0 ){ 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1; 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }else if( c=='[' ){ 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while( *z && quotaStrglob(zGlob-1,z)==0 ){ 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) z++; 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (*z)!=0; 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while( (c2 = (*(z++)))!=0 ){ 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while( c2!=c ){ 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2 = *(z++); 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( c2==0 ) return 0; 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( quotaStrglob(zGlob,z) ) return 1; 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }else if( c=='?' ){ 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( (*(z++))==0 ) return 0; 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }else if( c=='[' ){ 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int prior_c = 0; 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) seen = 0; 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) invert = 0; 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c = *(z++); 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( c==0 ) return 0; 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2 = *(zGlob++); 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( c2=='^' ){ 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) invert = 1; 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2 = *(zGlob++); 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( c2==']' ){ 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( c==']' ) seen = 1; 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2 = *(zGlob++); 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while( c2 && c2!=']' ){ 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( c2=='-' && zGlob[0]!=']' && zGlob[0]!=0 && prior_c>0 ){ 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2 = *(zGlob++); 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( c>=prior_c && c<=c2 ) seen = 1; 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prior_c = 0; 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }else{ 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( c==c2 ){ 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) seen = 1; 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prior_c = c2; 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2 = *(zGlob++); 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( c2==0 || (seen ^ invert)==0 ) return 0; 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }else{ 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( c!=(*(z++)) ) return 0; 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return *z==0; 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Find a quotaGroup given the filename. 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Return a pointer to the quotaGroup object. Return NULL if not found. 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static quotaGroup *quotaGroupFind(const char *zFilename){ 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaGroup *p; 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for(p=gQuota.pGroup; p && quotaStrglob(p->zPattern, zFilename)==0; 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p=p->pNext){} 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return p; 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Translate an sqlite3_file* that is really a quotaConn* into 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** the sqlite3_file* for the underlying original VFS. 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static sqlite3_file *quotaSubOpen(sqlite3_file *pConn){ 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaConn *p = (quotaConn*)pConn; 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (sqlite3_file*)&p[1]; 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/************************* VFS Method Wrappers *****************************/ 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This is the xOpen method used for the "quota" VFS. 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Most of the work is done by the underlying original VFS. This method 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** simply links the new file into the appropriate quota group if it is a 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** file that needs to be tracked. 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int quotaOpen( 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_vfs *pVfs, /* The quota VFS */ 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *zName, /* Name of file to be opened */ 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_file *pConn, /* Fill in this file descriptor */ 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int flags, /* Flags to control the opening */ 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int *pOutFlags /* Flags showing results of opening */ 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){ 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rc; /* Result code */ 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaConn *pQuotaOpen; /* The new quota file descriptor */ 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaFile *pFile; /* Corresponding quotaFile obj */ 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaGroup *pGroup; /* The group file belongs to */ 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_file *pSubOpen; /* Real file descriptor */ 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_vfs *pOrigVfs = gQuota.pOrigVfs; /* Real VFS */ 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* If the file is not a main database file or a WAL, then use the 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ** normal xOpen method. 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( (flags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_WAL))==0 ){ 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return pOrigVfs->xOpen(pOrigVfs, zName, pConn, flags, pOutFlags); 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* If the name of the file does not match any quota group, then 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ** use the normal xOpen method. 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaEnter(); 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pGroup = quotaGroupFind(zName); 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( pGroup==0 ){ 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rc = pOrigVfs->xOpen(pOrigVfs, zName, pConn, flags, pOutFlags); 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }else{ 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* If we get to this point, it means the file needs to be quota tracked. 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pQuotaOpen = (quotaConn*)pConn; 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pSubOpen = quotaSubOpen(pConn); 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rc = pOrigVfs->xOpen(pOrigVfs, zName, pSubOpen, flags, pOutFlags); 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( rc==SQLITE_OK ){ 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for(pFile=pGroup->pFiles; pFile && strcmp(pFile->zFilename, zName); 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pFile=pFile->pNext){} 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( pFile==0 ){ 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int nName = strlen(zName); 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pFile = sqlite3_malloc( sizeof(*pFile) + nName + 1 ); 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( pFile==0 ){ 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaLeave(); 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pSubOpen->pMethods->xClose(pSubOpen); 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SQLITE_NOMEM; 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(pFile, 0, sizeof(*pFile)); 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pFile->zFilename = (char*)&pFile[1]; 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(pFile->zFilename, zName, nName+1); 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pFile->pNext = pGroup->pFiles; 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( pGroup->pFiles ) pGroup->pFiles->ppPrev = &pFile->pNext; 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pFile->ppPrev = &pGroup->pFiles; 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pGroup->pFiles = pFile; 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pFile->pGroup = pGroup; 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pFile->nRef++; 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pQuotaOpen->pFile = pFile; 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( pSubOpen->pMethods->iVersion==1 ){ 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pQuotaOpen->base.pMethods = &gQuota.sIoMethodsV1; 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }else{ 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pQuotaOpen->base.pMethods = &gQuota.sIoMethodsV2; 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaLeave(); 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rc; 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/************************ I/O Method Wrappers *******************************/ 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* xClose requests get passed through to the original VFS. But we 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** also have to unlink the quotaConn from the quotaFile and quotaGroup. 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The quotaFile and/or quotaGroup are freed if they are no longer in use. 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int quotaClose(sqlite3_file *pConn){ 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaConn *p = (quotaConn*)pConn; 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaFile *pFile = p->pFile; 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_file *pSubOpen = quotaSubOpen(pConn); 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rc; 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rc = pSubOpen->pMethods->xClose(pSubOpen); 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaEnter(); 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pFile->nRef--; 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( pFile->nRef==0 ){ 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaGroup *pGroup = pFile->pGroup; 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pGroup->iSize -= pFile->iSize; 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( pFile->pNext ) pFile->pNext->ppPrev = pFile->ppPrev; 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *pFile->ppPrev = pFile->pNext; 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaGroupDeref(pGroup); 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_free(pFile); 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaLeave(); 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rc; 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Pass xRead requests directory thru to the original VFS without 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** further processing. 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int quotaRead( 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_file *pConn, 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void *pBuf, 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int iAmt, 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_int64 iOfst 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){ 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_file *pSubOpen = quotaSubOpen(pConn); 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return pSubOpen->pMethods->xRead(pSubOpen, pBuf, iAmt, iOfst); 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Check xWrite requests to see if they expand the file. If they do, 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** the perform a quota check before passing them through to the 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** original VFS. 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int quotaWrite( 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_file *pConn, 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const void *pBuf, 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int iAmt, 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_int64 iOfst 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){ 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaConn *p = (quotaConn*)pConn; 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_file *pSubOpen = quotaSubOpen(pConn); 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_int64 iEnd = iOfst+iAmt; 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaGroup *pGroup; 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaFile *pFile = p->pFile; 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_int64 szNew; 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( pFile->iSize<iEnd ){ 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pGroup = pFile->pGroup; 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaEnter(); 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) szNew = pGroup->iSize - pFile->iSize + iEnd; 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( szNew>pGroup->iLimit && pGroup->iLimit>0 ){ 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( pGroup->xCallback ){ 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pGroup->xCallback(pFile->zFilename, &pGroup->iLimit, szNew, 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pGroup->pArg); 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( szNew>pGroup->iLimit && pGroup->iLimit>0 ){ 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaLeave(); 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SQLITE_FULL; 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pGroup->iSize = szNew; 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pFile->iSize = iEnd; 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaLeave(); 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return pSubOpen->pMethods->xWrite(pSubOpen, pBuf, iAmt, iOfst); 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Pass xTruncate requests thru to the original VFS. If the 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** success, update the file size. 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int quotaTruncate(sqlite3_file *pConn, sqlite3_int64 size){ 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaConn *p = (quotaConn*)pConn; 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_file *pSubOpen = quotaSubOpen(pConn); 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rc = pSubOpen->pMethods->xTruncate(pSubOpen, size); 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaFile *pFile = p->pFile; 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaGroup *pGroup; 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( rc==SQLITE_OK ){ 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaEnter(); 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pGroup = pFile->pGroup; 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pGroup->iSize -= pFile->iSize; 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pFile->iSize = size; 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pGroup->iSize += size; 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaLeave(); 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rc; 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Pass xSync requests through to the original VFS without change 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int quotaSync(sqlite3_file *pConn, int flags){ 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_file *pSubOpen = quotaSubOpen(pConn); 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return pSubOpen->pMethods->xSync(pSubOpen, flags); 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Pass xFileSize requests through to the original VFS but then 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** update the quotaGroup with the new size before returning. 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int quotaFileSize(sqlite3_file *pConn, sqlite3_int64 *pSize){ 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaConn *p = (quotaConn*)pConn; 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_file *pSubOpen = quotaSubOpen(pConn); 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaFile *pFile = p->pFile; 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaGroup *pGroup; 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_int64 sz; 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rc; 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rc = pSubOpen->pMethods->xFileSize(pSubOpen, &sz); 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( rc==SQLITE_OK ){ 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaEnter(); 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pGroup = pFile->pGroup; 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pGroup->iSize -= pFile->iSize; 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pFile->iSize = sz; 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pGroup->iSize += sz; 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaLeave(); 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *pSize = sz; 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rc; 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Pass xLock requests through to the original VFS unchanged. 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int quotaLock(sqlite3_file *pConn, int lock){ 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_file *pSubOpen = quotaSubOpen(pConn); 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return pSubOpen->pMethods->xLock(pSubOpen, lock); 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Pass xUnlock requests through to the original VFS unchanged. 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int quotaUnlock(sqlite3_file *pConn, int lock){ 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_file *pSubOpen = quotaSubOpen(pConn); 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return pSubOpen->pMethods->xUnlock(pSubOpen, lock); 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Pass xCheckReservedLock requests through to the original VFS unchanged. 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int quotaCheckReservedLock(sqlite3_file *pConn, int *pResOut){ 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_file *pSubOpen = quotaSubOpen(pConn); 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return pSubOpen->pMethods->xCheckReservedLock(pSubOpen, pResOut); 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Pass xFileControl requests through to the original VFS unchanged. 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int quotaFileControl(sqlite3_file *pConn, int op, void *pArg){ 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_file *pSubOpen = quotaSubOpen(pConn); 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return pSubOpen->pMethods->xFileControl(pSubOpen, op, pArg); 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Pass xSectorSize requests through to the original VFS unchanged. 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int quotaSectorSize(sqlite3_file *pConn){ 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_file *pSubOpen = quotaSubOpen(pConn); 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return pSubOpen->pMethods->xSectorSize(pSubOpen); 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Pass xDeviceCharacteristics requests through to the original VFS unchanged. 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int quotaDeviceCharacteristics(sqlite3_file *pConn){ 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_file *pSubOpen = quotaSubOpen(pConn); 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return pSubOpen->pMethods->xDeviceCharacteristics(pSubOpen); 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Pass xShmMap requests through to the original VFS unchanged. 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int quotaShmMap( 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_file *pConn, /* Handle open on database file */ 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int iRegion, /* Region to retrieve */ 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int szRegion, /* Size of regions */ 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int bExtend, /* True to extend file if necessary */ 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void volatile **pp /* OUT: Mapped memory */ 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){ 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_file *pSubOpen = quotaSubOpen(pConn); 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return pSubOpen->pMethods->xShmMap(pSubOpen, iRegion, szRegion, bExtend, pp); 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Pass xShmLock requests through to the original VFS unchanged. 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int quotaShmLock( 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_file *pConn, /* Database file holding the shared memory */ 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int ofst, /* First lock to acquire or release */ 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int n, /* Number of locks to acquire or release */ 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int flags /* What to do with the lock */ 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){ 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_file *pSubOpen = quotaSubOpen(pConn); 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return pSubOpen->pMethods->xShmLock(pSubOpen, ofst, n, flags); 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Pass xShmBarrier requests through to the original VFS unchanged. 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void quotaShmBarrier(sqlite3_file *pConn){ 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_file *pSubOpen = quotaSubOpen(pConn); 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pSubOpen->pMethods->xShmBarrier(pSubOpen); 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Pass xShmUnmap requests through to the original VFS unchanged. 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int quotaShmUnmap(sqlite3_file *pConn, int deleteFlag){ 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_file *pSubOpen = quotaSubOpen(pConn); 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return pSubOpen->pMethods->xShmUnmap(pSubOpen, deleteFlag); 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/************************** Public Interfaces *****************************/ 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Initialize the quota VFS shim. Use the VFS named zOrigVfsName 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** as the VFS that does the actual work. Use the default if 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** zOrigVfsName==NULL. 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The quota VFS shim is named "quota". It will become the default 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** VFS if makeDefault is non-zero. 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** THIS ROUTINE IS NOT THREADSAFE. Call this routine exactly once 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** during start-up. 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int sqlite3_quota_initialize(const char *zOrigVfsName, int makeDefault){ 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_vfs *pOrigVfs; 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( gQuota.isInitialized ) return SQLITE_MISUSE; 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pOrigVfs = sqlite3_vfs_find(zOrigVfsName); 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( pOrigVfs==0 ) return SQLITE_ERROR; 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert( pOrigVfs!=&gQuota.sThisVfs ); 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gQuota.pMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( !gQuota.pMutex ){ 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SQLITE_NOMEM; 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gQuota.isInitialized = 1; 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gQuota.pOrigVfs = pOrigVfs; 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gQuota.sThisVfs = *pOrigVfs; 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gQuota.sThisVfs.xOpen = quotaOpen; 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gQuota.sThisVfs.szOsFile += sizeof(quotaConn); 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gQuota.sThisVfs.zName = "quota"; 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gQuota.sIoMethodsV1.iVersion = 1; 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gQuota.sIoMethodsV1.xClose = quotaClose; 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gQuota.sIoMethodsV1.xRead = quotaRead; 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gQuota.sIoMethodsV1.xWrite = quotaWrite; 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gQuota.sIoMethodsV1.xTruncate = quotaTruncate; 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gQuota.sIoMethodsV1.xSync = quotaSync; 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gQuota.sIoMethodsV1.xFileSize = quotaFileSize; 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gQuota.sIoMethodsV1.xLock = quotaLock; 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gQuota.sIoMethodsV1.xUnlock = quotaUnlock; 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gQuota.sIoMethodsV1.xCheckReservedLock = quotaCheckReservedLock; 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gQuota.sIoMethodsV1.xFileControl = quotaFileControl; 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gQuota.sIoMethodsV1.xSectorSize = quotaSectorSize; 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gQuota.sIoMethodsV1.xDeviceCharacteristics = quotaDeviceCharacteristics; 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gQuota.sIoMethodsV2 = gQuota.sIoMethodsV1; 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gQuota.sIoMethodsV2.iVersion = 2; 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gQuota.sIoMethodsV2.xShmMap = quotaShmMap; 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gQuota.sIoMethodsV2.xShmLock = quotaShmLock; 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gQuota.sIoMethodsV2.xShmBarrier = quotaShmBarrier; 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gQuota.sIoMethodsV2.xShmUnmap = quotaShmUnmap; 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_vfs_register(&gQuota.sThisVfs, makeDefault); 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SQLITE_OK; 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Shutdown the quota system. 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** All SQLite database connections must be closed before calling this 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** routine. 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** THIS ROUTINE IS NOT THREADSAFE. Call this routine exactly one while 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** shutting down in order to free all remaining quota groups. 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int sqlite3_quota_shutdown(void){ 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaGroup *pGroup; 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( gQuota.isInitialized==0 ) return SQLITE_MISUSE; 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for(pGroup=gQuota.pGroup; pGroup; pGroup=pGroup->pNext){ 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( pGroup->pFiles ) return SQLITE_MISUSE; 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while( gQuota.pGroup ){ 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pGroup = gQuota.pGroup; 6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gQuota.pGroup = pGroup->pNext; 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pGroup->iLimit = 0; 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaGroupDeref(pGroup); 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gQuota.isInitialized = 0; 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_mutex_free(gQuota.pMutex); 6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_vfs_unregister(&gQuota.sThisVfs); 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(&gQuota, 0, sizeof(gQuota)); 6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SQLITE_OK; 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Create or destroy a quota group. 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The quota group is defined by the zPattern. When calling this routine 6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** with a zPattern for a quota group that already exists, this routine 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** merely updates the iLimit, xCallback, and pArg values for that quota 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** group. If zPattern is new, then a new quota group is created. 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** If the iLimit for a quota group is set to zero, then the quota group 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** is disabled and will be deleted when the last database connection using 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** the quota group is closed. 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Calling this routine on a zPattern that does not exist and with a 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** zero iLimit is a no-op. 6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** A quota group must exist with a non-zero iLimit prior to opening 6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** database connections if those connections are to participate in the 6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** quota group. Creating a quota group does not affect database connections 6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** that are already open. 6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int sqlite3_quota_set( 6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *zPattern, /* The filename pattern */ 6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_int64 iLimit, /* New quota to set for this quota group */ 6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void (*xCallback)( /* Callback invoked when going over quota */ 6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *zFilename, /* Name of file whose size increases */ 6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_int64 *piLimit, /* IN/OUT: The current limit */ 6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_int64 iSize, /* Total size of all files in the group */ 6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void *pArg /* Client data */ 6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ), 6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void *pArg, /* client data passed thru to callback */ 6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void (*xDestroy)(void*) /* Optional destructor for pArg */ 6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){ 6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaGroup *pGroup; 6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaEnter(); 6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pGroup = gQuota.pGroup; 6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while( pGroup && strcmp(pGroup->zPattern, zPattern)!=0 ){ 6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pGroup = pGroup->pNext; 6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( pGroup==0 ){ 6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int nPattern = strlen(zPattern); 6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( iLimit<=0 ){ 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaLeave(); 6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SQLITE_OK; 6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pGroup = sqlite3_malloc( sizeof(*pGroup) + nPattern + 1 ); 6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( pGroup==0 ){ 6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaLeave(); 6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SQLITE_NOMEM; 6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(pGroup, 0, sizeof(*pGroup)); 6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pGroup->zPattern = (char*)&pGroup[1]; 6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy((char *)pGroup->zPattern, zPattern, nPattern+1); 6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( gQuota.pGroup ) gQuota.pGroup->ppPrev = &pGroup->pNext; 6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pGroup->pNext = gQuota.pGroup; 6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pGroup->ppPrev = &gQuota.pGroup; 6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gQuota.pGroup = pGroup; 6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pGroup->iLimit = iLimit; 7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pGroup->xCallback = xCallback; 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( pGroup->xDestroy && pGroup->pArg!=pArg ){ 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pGroup->xDestroy(pGroup->pArg); 7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pGroup->pArg = pArg; 7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pGroup->xDestroy = xDestroy; 7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaGroupDeref(pGroup); 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaLeave(); 7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SQLITE_OK; 7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/***************************** Test Code ***********************************/ 7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef SQLITE_TEST 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <tcl.h> 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Argument passed to a TCL quota-over-limit callback. 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct TclQuotaCallback TclQuotaCallback; 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct TclQuotaCallback { 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Interp *interp; /* Interpreter in which to run the script */ 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Obj *pScript; /* Script to be run */ 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern const char *sqlite3TestErrorName(int); 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This is the callback from a quota-over-limit. 7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void tclQuotaCallback( 7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *zFilename, /* Name of file whose size increases */ 7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_int64 *piLimit, /* IN/OUT: The current limit */ 7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_int64 iSize, /* Total size of all files in the group */ 7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void *pArg /* Client data */ 7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){ 7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TclQuotaCallback *p; /* Callback script object */ 7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Obj *pEval; /* Script to evaluate */ 7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Obj *pVarname; /* Name of variable to pass as 2nd arg */ 7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int rnd; /* Random part of pVarname */ 7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rc; /* Tcl error code */ 7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p = (TclQuotaCallback *)pArg; 7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( p==0 ) return; 7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pVarname = Tcl_NewStringObj("::piLimit_", -1); 7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_IncrRefCount(pVarname); 7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_randomness(sizeof(rnd), (void *)&rnd); 7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_AppendObjToObj(pVarname, Tcl_NewIntObj((int)(rnd&0x7FFFFFFF))); 7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_ObjSetVar2(p->interp, pVarname, 0, Tcl_NewWideIntObj(*piLimit), 0); 7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pEval = Tcl_DuplicateObj(p->pScript); 7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_IncrRefCount(pEval); 7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_ListObjAppendElement(0, pEval, Tcl_NewStringObj(zFilename, -1)); 7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_ListObjAppendElement(0, pEval, pVarname); 7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_ListObjAppendElement(0, pEval, Tcl_NewWideIntObj(iSize)); 7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rc = Tcl_EvalObjEx(p->interp, pEval, TCL_EVAL_GLOBAL); 7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( rc==TCL_OK ){ 7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Obj *pLimit = Tcl_ObjGetVar2(p->interp, pVarname, 0, 0); 7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rc = Tcl_GetWideIntFromObj(p->interp, pLimit, piLimit); 7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_UnsetVar(p->interp, Tcl_GetString(pVarname), 0); 7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_DecrRefCount(pEval); 7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_DecrRefCount(pVarname); 7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( rc!=TCL_OK ) Tcl_BackgroundError(p->interp); 7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Destructor for a TCL quota-over-limit callback. 7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void tclCallbackDestructor(void *pObj){ 7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TclQuotaCallback *p = (TclQuotaCallback*)pObj; 7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( p ){ 7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_DecrRefCount(p->pScript); 7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_free((char *)p); 7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** tclcmd: sqlite3_quota_initialize NAME MAKEDEFAULT 7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int test_quota_initialize( 7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void * clientData, 7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Interp *interp, 7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int objc, 7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Obj *CONST objv[] 7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){ 7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *zName; /* Name of new quota VFS */ 7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int makeDefault; /* True to make the new VFS the default */ 7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rc; /* Value returned by quota_initialize() */ 7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* Process arguments */ 7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( objc!=3 ){ 7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_WrongNumArgs(interp, 1, objv, "NAME MAKEDEFAULT"); 7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_ERROR; 7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zName = Tcl_GetString(objv[1]); 8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( Tcl_GetBooleanFromObj(interp, objv[2], &makeDefault) ) return TCL_ERROR; 8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( zName[0]=='\0' ) zName = 0; 8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* Call sqlite3_quota_initialize() */ 8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rc = sqlite3_quota_initialize(zName, makeDefault); 8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_STATIC); 8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_OK; 8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** tclcmd: sqlite3_quota_shutdown 8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int test_quota_shutdown( 8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void * clientData, 8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Interp *interp, 8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int objc, 8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Obj *CONST objv[] 8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){ 8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rc; /* Value returned by quota_shutdown() */ 8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( objc!=1 ){ 8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_WrongNumArgs(interp, 1, objv, ""); 8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_ERROR; 8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* Call sqlite3_quota_shutdown() */ 8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rc = sqlite3_quota_shutdown(); 8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_STATIC); 8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_OK; 8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** tclcmd: sqlite3_quota_set PATTERN LIMIT SCRIPT 8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int test_quota_set( 8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void * clientData, 8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Interp *interp, 8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int objc, 8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Obj *CONST objv[] 8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){ 8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *zPattern; /* File pattern to configure */ 8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_int64 iLimit; /* Initial quota in bytes */ 8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Obj *pScript; /* Tcl script to invoke to increase quota */ 8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rc; /* Value returned by quota_set() */ 8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TclQuotaCallback *p; /* Callback object */ 8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int nScript; /* Length of callback script */ 8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void (*xDestroy)(void*); /* Optional destructor for pArg */ 8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void (*xCallback)(const char *, sqlite3_int64 *, sqlite3_int64, void *); 8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* Process arguments */ 8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( objc!=4 ){ 8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_WrongNumArgs(interp, 1, objv, "PATTERN LIMIT SCRIPT"); 8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_ERROR; 8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zPattern = Tcl_GetString(objv[1]); 8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( Tcl_GetWideIntFromObj(interp, objv[2], &iLimit) ) return TCL_ERROR; 8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pScript = objv[3]; 8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_GetStringFromObj(pScript, &nScript); 8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( nScript>0 ){ 8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* Allocate a TclQuotaCallback object */ 8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p = (TclQuotaCallback *)sqlite3_malloc(sizeof(TclQuotaCallback)); 8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( !p ){ 8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_SetResult(interp, (char *)"SQLITE_NOMEM", TCL_STATIC); 8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_OK; 8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(p, 0, sizeof(TclQuotaCallback)); 8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->interp = interp; 8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_IncrRefCount(pScript); 8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->pScript = pScript; 8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) xDestroy = tclCallbackDestructor; 8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) xCallback = tclQuotaCallback; 8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }else{ 8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p = 0; 8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) xDestroy = 0; 8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) xCallback = 0; 8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* Invoke sqlite3_quota_set() */ 8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rc = sqlite3_quota_set(zPattern, iLimit, xCallback, (void*)p, xDestroy); 8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_STATIC); 8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_OK; 8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** tclcmd: sqlite3_quota_dump 8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int test_quota_dump( 8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void * clientData, 8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Interp *interp, 8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int objc, 8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Obj *CONST objv[] 8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){ 8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Obj *pResult; 8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Obj *pGroupTerm; 8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Obj *pFileTerm; 8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaGroup *pGroup; 9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaFile *pFile; 9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pResult = Tcl_NewObj(); 9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaEnter(); 9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for(pGroup=gQuota.pGroup; pGroup; pGroup=pGroup->pNext){ 9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pGroupTerm = Tcl_NewObj(); 9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_ListObjAppendElement(interp, pGroupTerm, 9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_NewStringObj(pGroup->zPattern, -1)); 9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_ListObjAppendElement(interp, pGroupTerm, 9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_NewWideIntObj(pGroup->iLimit)); 9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_ListObjAppendElement(interp, pGroupTerm, 9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_NewWideIntObj(pGroup->iSize)); 9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for(pFile=pGroup->pFiles; pFile; pFile=pFile->pNext){ 9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pFileTerm = Tcl_NewObj(); 9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_ListObjAppendElement(interp, pFileTerm, 9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_NewStringObj(pFile->zFilename, -1)); 9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_ListObjAppendElement(interp, pFileTerm, 9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_NewWideIntObj(pFile->iSize)); 9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_ListObjAppendElement(interp, pFileTerm, 9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_NewWideIntObj(pFile->nRef)); 9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_ListObjAppendElement(interp, pGroupTerm, pFileTerm); 9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_ListObjAppendElement(interp, pResult, pGroupTerm); 9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quotaLeave(); 9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_SetObjResult(interp, pResult); 9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_OK; 9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This routine registers the custom TCL commands defined in this 9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** module. This should be the only procedure visible from outside 9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** of this module. 9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int Sqlitequota_Init(Tcl_Interp *interp){ 9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static struct { 9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *zName; 9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_ObjCmdProc *xProc; 9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } aCmd[] = { 9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "sqlite3_quota_initialize", test_quota_initialize }, 9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "sqlite3_quota_shutdown", test_quota_shutdown }, 9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "sqlite3_quota_set", test_quota_set }, 9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "sqlite3_quota_dump", test_quota_dump }, 9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ 9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); 9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_OK; 9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 953