diff options
Diffstat (limited to 'Plugins/DbSqliteWx/fileio.c')
| -rw-r--r-- | Plugins/DbSqliteWx/fileio.c | 927 |
1 files changed, 0 insertions, 927 deletions
diff --git a/Plugins/DbSqliteWx/fileio.c b/Plugins/DbSqliteWx/fileio.c deleted file mode 100644 index 68f1ea5..0000000 --- a/Plugins/DbSqliteWx/fileio.c +++ /dev/null @@ -1,927 +0,0 @@ -/* -** 2014-06-13 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This SQLite extension implements SQL functions readfile() and -** writefile(), and eponymous virtual type "fsdir". -** -** WRITEFILE(FILE, DATA [, MODE [, MTIME]]): -** -** If neither of the optional arguments is present, then this UDF -** function writes blob DATA to file FILE. If successful, the number -** of bytes written is returned. If an error occurs, NULL is returned. -** -** If the first option argument - MODE - is present, then it must -** be passed an integer value that corresponds to a POSIX mode -** value (file type + permissions, as returned in the stat.st_mode -** field by the stat() system call). Three types of files may -** be written/created: -** -** regular files: (mode & 0170000)==0100000 -** symbolic links: (mode & 0170000)==0120000 -** directories: (mode & 0170000)==0040000 -** -** For a directory, the DATA is ignored. For a symbolic link, it is -** interpreted as text and used as the target of the link. For a -** regular file, it is interpreted as a blob and written into the -** named file. Regardless of the type of file, its permissions are -** set to (mode & 0777) before returning. -** -** If the optional MTIME argument is present, then it is interpreted -** as an integer - the number of seconds since the unix epoch. The -** modification-time of the target file is set to this value before -** returning. -** -** If three or more arguments are passed to this function and an -** error is encountered, an exception is raised. -** -** READFILE(FILE): -** -** Read and return the contents of file FILE (type blob) from disk. -** -** FSDIR: -** -** Used as follows: -** -** SELECT * FROM fsdir($path [, $dir]); -** -** Parameter $path is an absolute or relative pathname. If the file that it -** refers to does not exist, it is an error. If the path refers to a regular -** file or symbolic link, it returns a single row. Or, if the path refers -** to a directory, it returns one row for the directory, and one row for each -** file within the hierarchy rooted at $path. -** -** Each row has the following columns: -** -** name: Path to file or directory (text value). -** mode: Value of stat.st_mode for directory entry (an integer). -** mtime: Value of stat.st_mtime for directory entry (an integer). -** data: For a regular file, a blob containing the file data. For a -** symlink, a text value containing the text of the link. For a -** directory, NULL. -** -** If a non-NULL value is specified for the optional $dir parameter and -** $path is a relative path, then $path is interpreted relative to $dir. -** And the paths returned in the "name" column of the table are also -** relative to directory $dir. -*/ -#include "wx_sqlite3ext.h" -SQLITE_EXTENSION_INIT1 -#include <stdio.h> -#include <string.h> -#include <assert.h> - -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#if !defined(_WIN32) && !defined(WIN32) -# include <unistd.h> -# include <dirent.h> -# include <utime.h> -# include <sys/time.h> -#else -# include "windows.h" -# include <io.h> -# include <direct.h> -# include "test_windirent.h" -# define dirent DIRENT -# ifndef chmod -# define chmod _chmod -# endif -# ifndef stat -# define stat _stat -# endif -# define mkdir(path,mode) _mkdir(path) -# define lstat(path,buf) stat(path,buf) -#endif -#include <time.h> -#include <errno.h> - - -#define FSDIR_SCHEMA "(name,mode,mtime,data,path HIDDEN,dir HIDDEN)" - -/* -** Set the result stored by context ctx to a blob containing the -** contents of file zName. -*/ -static void readFileContents(wx_sqlite3_context *ctx, const char *zName){ - FILE *in; - long nIn; - void *pBuf; - - in = fopen(zName, "rb"); - if( in==0 ) return; - fseek(in, 0, SEEK_END); - nIn = ftell(in); - rewind(in); - pBuf = wx_sqlite3_malloc( nIn ); - if( pBuf && 1==fread(pBuf, nIn, 1, in) ){ - wx_sqlite3_result_blob(ctx, pBuf, nIn, wx_sqlite3_free); - }else{ - wx_sqlite3_free(pBuf); - } - fclose(in); -} - -/* -** Implementation of the "readfile(X)" SQL function. The entire content -** of the file named X is read and returned as a BLOB. NULL is returned -** if the file does not exist or is unreadable. -*/ -static void readfileFunc( - wx_sqlite3_context *context, - int argc, - wx_sqlite3_value **argv -){ - const char *zName; - (void)(argc); /* Unused parameter */ - zName = (const char*)wx_sqlite3_value_text(argv[0]); - if( zName==0 ) return; - readFileContents(context, zName); -} - -/* -** Set the error message contained in context ctx to the results of -** vprintf(zFmt, ...). -*/ -static void ctxErrorMsg(wx_sqlite3_context *ctx, const char *zFmt, ...){ - char *zMsg = 0; - va_list ap; - va_start(ap, zFmt); - zMsg = wx_sqlite3_vmprintf(zFmt, ap); - wx_sqlite3_result_error(ctx, zMsg, -1); - wx_sqlite3_free(zMsg); - va_end(ap); -} - -#if defined(_WIN32) -/* -** This function is designed to convert a Win32 FILETIME structure into the -** number of seconds since the Unix Epoch (1970-01-01 00:00:00 UTC). -*/ -static wx_sqlite3_uint64 fileTimeToUnixTime( - LPFILETIME pFileTime -){ - SYSTEMTIME epochSystemTime; - ULARGE_INTEGER epochIntervals; - FILETIME epochFileTime; - ULARGE_INTEGER fileIntervals; - - memset(&epochSystemTime, 0, sizeof(SYSTEMTIME)); - epochSystemTime.wYear = 1970; - epochSystemTime.wMonth = 1; - epochSystemTime.wDay = 1; - SystemTimeToFileTime(&epochSystemTime, &epochFileTime); - epochIntervals.LowPart = epochFileTime.dwLowDateTime; - epochIntervals.HighPart = epochFileTime.dwHighDateTime; - - fileIntervals.LowPart = pFileTime->dwLowDateTime; - fileIntervals.HighPart = pFileTime->dwHighDateTime; - - return (fileIntervals.QuadPart - epochIntervals.QuadPart) / 10000000; -} - -/* -** This function attempts to normalize the time values found in the stat() -** buffer to UTC. This is necessary on Win32, where the runtime library -** appears to return these values as local times. -*/ -static void statTimesToUtc( - const char *zPath, - struct stat *pStatBuf -){ - HANDLE hFindFile; - WIN32_FIND_DATAW fd; - LPWSTR zUnicodeName; - extern LPWSTR wx_sqlite3_win32_utf8_to_unicode(const char*); - zUnicodeName = wx_sqlite3_win32_utf8_to_unicode(zPath); - if( zUnicodeName ){ - memset(&fd, 0, sizeof(WIN32_FIND_DATA)); - hFindFile = FindFirstFileW(zUnicodeName, &fd); - if( hFindFile!=NULL ){ - pStatBuf->st_ctime = (time_t)fileTimeToUnixTime(&fd.ftCreationTime); - pStatBuf->st_atime = (time_t)fileTimeToUnixTime(&fd.ftLastAccessTime); - pStatBuf->st_mtime = (time_t)fileTimeToUnixTime(&fd.ftLastWriteTime); - FindClose(hFindFile); - } - wx_sqlite3_free(zUnicodeName); - } -} -#endif - -/* -** This function is used in place of stat(). On Windows, special handling -** is required in order for the included time to be returned as UTC. On all -** other systems, this function simply calls stat(). -*/ -static int fileStat( - const char *zPath, - struct stat *pStatBuf -){ -#if defined(_WIN32) - int rc = stat(zPath, pStatBuf); - if( rc==0 ) statTimesToUtc(zPath, pStatBuf); - return rc; -#else - return stat(zPath, pStatBuf); -#endif -} - -/* -** This function is used in place of lstat(). On Windows, special handling -** is required in order for the included time to be returned as UTC. On all -** other systems, this function simply calls lstat(). -*/ -static int fileLinkStat( - const char *zPath, - struct stat *pStatBuf -){ -#if defined(_WIN32) - int rc = lstat(zPath, pStatBuf); - if( rc==0 ) statTimesToUtc(zPath, pStatBuf); - return rc; -#else - return lstat(zPath, pStatBuf); -#endif -} - -/* -** Argument zFile is the name of a file that will be created and/or written -** by SQL function writefile(). This function ensures that the directory -** zFile will be written to exists, creating it if required. The permissions -** for any path components created by this function are set to (mode&0777). -** -** If an OOM condition is encountered, SQLITE_NOMEM is returned. Otherwise, -** SQLITE_OK is returned if the directory is successfully created, or -** SQLITE_ERROR otherwise. -*/ -static int makeDirectory( - const char *zFile, - mode_t mode -){ - char *zCopy = wx_sqlite3_mprintf("%s", zFile); - int rc = SQLITE_OK; - - if( zCopy==0 ){ - rc = SQLITE_NOMEM; - }else{ - int nCopy = (int)strlen(zCopy); - int i = 1; - - while( rc==SQLITE_OK ){ - struct stat sStat; - int rc2; - - for(; zCopy[i]!='/' && i<nCopy; i++); - if( i==nCopy ) break; - zCopy[i] = '\0'; - - rc2 = fileStat(zCopy, &sStat); - if( rc2!=0 ){ - if( mkdir(zCopy, mode & 0777) ) rc = SQLITE_ERROR; - }else{ - if( !S_ISDIR(sStat.st_mode) ) rc = SQLITE_ERROR; - } - zCopy[i] = '/'; - i++; - } - - wx_sqlite3_free(zCopy); - } - - return rc; -} - -/* -** This function does the work for the writefile() UDF. Refer to -** header comments at the top of this file for details. -*/ -static int writeFile( - wx_sqlite3_context *pCtx, /* Context to return bytes written in */ - const char *zFile, /* File to write */ - wx_sqlite3_value *pData, /* Data to write */ - mode_t mode, /* MODE parameter passed to writefile() */ - wx_sqlite3_int64 mtime /* MTIME parameter (or -1 to not set time) */ -){ -#if !defined(_WIN32) && !defined(WIN32) - if( S_ISLNK(mode) ){ - const char *zTo = (const char*)wx_sqlite3_value_text(pData); - if( symlink(zTo, zFile)<0 ) return 1; - }else -#endif - { - if( S_ISDIR(mode) ){ - if( mkdir(zFile, mode) ){ - /* The mkdir() call to create the directory failed. This might not - ** be an error though - if there is already a directory at the same - ** path and either the permissions already match or can be changed - ** to do so using chmod(), it is not an error. */ - struct stat sStat; - if( errno!=EEXIST - || 0!=fileStat(zFile, &sStat) - || !S_ISDIR(sStat.st_mode) - || ((sStat.st_mode&0777)!=(mode&0777) && 0!=chmod(zFile, mode&0777)) - ){ - return 1; - } - } - }else{ - wx_sqlite3_int64 nWrite = 0; - const char *z; - int rc = 0; - FILE *out = fopen(zFile, "wb"); - if( out==0 ) return 1; - z = (const char*)wx_sqlite3_value_blob(pData); - if( z ){ - wx_sqlite3_int64 n = fwrite(z, 1, wx_sqlite3_value_bytes(pData), out); - nWrite = wx_sqlite3_value_bytes(pData); - if( nWrite!=n ){ - rc = 1; - } - } - fclose(out); - if( rc==0 && mode && chmod(zFile, mode & 0777) ){ - rc = 1; - } - if( rc ) return 2; - wx_sqlite3_result_int64(pCtx, nWrite); - } - } - - if( mtime>=0 ){ -#if defined(_WIN32) - /* Windows */ - FILETIME lastAccess; - FILETIME lastWrite; - SYSTEMTIME currentTime; - LONGLONG intervals; - HANDLE hFile; - LPWSTR zUnicodeName; - extern LPWSTR wx_sqlite3_win32_utf8_to_unicode(const char*); - - GetSystemTime(¤tTime); - SystemTimeToFileTime(¤tTime, &lastAccess); - intervals = Int32x32To64(mtime, 10000000) + 116444736000000000; - lastWrite.dwLowDateTime = (DWORD)intervals; - lastWrite.dwHighDateTime = intervals >> 32; - zUnicodeName = wx_sqlite3_win32_utf8_to_unicode(zFile); - if( zUnicodeName==0 ){ - return 1; - } - hFile = CreateFileW( - zUnicodeName, FILE_WRITE_ATTRIBUTES, 0, NULL, OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, NULL - ); - wx_sqlite3_free(zUnicodeName); - if( hFile!=INVALID_HANDLE_VALUE ){ - BOOL bResult = SetFileTime(hFile, NULL, &lastAccess, &lastWrite); - CloseHandle(hFile); - return !bResult; - }else{ - return 1; - } -#elif defined(AT_FDCWD) && 0 /* utimensat() is not universally available */ - /* Recent unix */ - struct timespec times[2]; - times[0].tv_nsec = times[1].tv_nsec = 0; - times[0].tv_sec = time(0); - times[1].tv_sec = mtime; - if( utimensat(AT_FDCWD, zFile, times, AT_SYMLINK_NOFOLLOW) ){ - return 1; - } -#else - /* Legacy unix */ - struct timeval times[2]; - times[0].tv_usec = times[1].tv_usec = 0; - times[0].tv_sec = time(0); - times[1].tv_sec = mtime; - if( utimes(zFile, times) ){ - return 1; - } -#endif - } - - return 0; -} - -/* -** Implementation of the "writefile(W,X[,Y[,Z]]])" SQL function. -** Refer to header comments at the top of this file for details. -*/ -static void writefileFunc( - wx_sqlite3_context *context, - int argc, - wx_sqlite3_value **argv -){ - const char *zFile; - mode_t mode = 0; - int res; - wx_sqlite3_int64 mtime = -1; - - if( argc<2 || argc>4 ){ - wx_sqlite3_result_error(context, - "wrong number of arguments to function writefile()", -1 - ); - return; - } - - zFile = (const char*)wx_sqlite3_value_text(argv[0]); - if( zFile==0 ) return; - if( argc>=3 ){ - mode = (mode_t)wx_sqlite3_value_int(argv[2]); - } - if( argc==4 ){ - mtime = wx_sqlite3_value_int64(argv[3]); - } - - res = writeFile(context, zFile, argv[1], mode, mtime); - if( res==1 && errno==ENOENT ){ - if( makeDirectory(zFile, mode)==SQLITE_OK ){ - res = writeFile(context, zFile, argv[1], mode, mtime); - } - } - - if( argc>2 && res!=0 ){ - if( S_ISLNK(mode) ){ - ctxErrorMsg(context, "failed to create symlink: %s", zFile); - }else if( S_ISDIR(mode) ){ - ctxErrorMsg(context, "failed to create directory: %s", zFile); - }else{ - ctxErrorMsg(context, "failed to write file: %s", zFile); - } - } -} - -/* -** SQL function: lsmode(MODE) -** -** Given a numberic st_mode from stat(), convert it into a human-readable -** text string in the style of "ls -l". -*/ -static void lsModeFunc( - wx_sqlite3_context *context, - int argc, - wx_sqlite3_value **argv -){ - int i; - int iMode = wx_sqlite3_value_int(argv[0]); - char z[16]; - (void)argc; - if( S_ISLNK(iMode) ){ - z[0] = 'l'; - }else if( S_ISREG(iMode) ){ - z[0] = '-'; - }else if( S_ISDIR(iMode) ){ - z[0] = 'd'; - }else{ - z[0] = '?'; - } - for(i=0; i<3; i++){ - int m = (iMode >> ((2-i)*3)); - char *a = &z[1 + i*3]; - a[0] = (m & 0x4) ? 'r' : '-'; - a[1] = (m & 0x2) ? 'w' : '-'; - a[2] = (m & 0x1) ? 'x' : '-'; - } - z[10] = '\0'; - wx_sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT); -} - -#ifndef SQLITE_OMIT_VIRTUALTABLE - -/* -** Cursor type for recursively iterating through a directory structure. -*/ -typedef struct fsdir_cursor fsdir_cursor; -typedef struct FsdirLevel FsdirLevel; - -struct FsdirLevel { - DIR *pDir; /* From opendir() */ - char *zDir; /* Name of directory (nul-terminated) */ -}; - -struct fsdir_cursor { - wx_sqlite3_vtab_cursor base; /* Base class - must be first */ - - int nLvl; /* Number of entries in aLvl[] array */ - int iLvl; /* Index of current entry */ - FsdirLevel *aLvl; /* Hierarchy of directories being traversed */ - - const char *zBase; - int nBase; - - struct stat sStat; /* Current lstat() results */ - char *zPath; /* Path to current entry */ - wx_sqlite3_int64 iRowid; /* Current rowid */ -}; - -typedef struct fsdir_tab fsdir_tab; -struct fsdir_tab { - wx_sqlite3_vtab base; /* Base class - must be first */ -}; - -/* -** Construct a new fsdir virtual table object. -*/ -static int fsdirConnect( - wx_sqlite3 *db, - void *pAux, - int argc, const char *const*argv, - wx_sqlite3_vtab **ppVtab, - char **pzErr -){ - fsdir_tab *pNew = 0; - int rc; - (void)pAux; - (void)argc; - (void)argv; - (void)pzErr; - rc = wx_sqlite3_declare_vtab(db, "CREATE TABLE x" FSDIR_SCHEMA); - if( rc==SQLITE_OK ){ - pNew = (fsdir_tab*)wx_sqlite3_malloc( sizeof(*pNew) ); - if( pNew==0 ) return SQLITE_NOMEM; - memset(pNew, 0, sizeof(*pNew)); - } - *ppVtab = (wx_sqlite3_vtab*)pNew; - return rc; -} - -/* -** This method is the destructor for fsdir vtab objects. -*/ -static int fsdirDisconnect(wx_sqlite3_vtab *pVtab){ - wx_sqlite3_free(pVtab); - return SQLITE_OK; -} - -/* -** Constructor for a new fsdir_cursor object. -*/ -static int fsdirOpen(wx_sqlite3_vtab *p, wx_sqlite3_vtab_cursor **ppCursor){ - fsdir_cursor *pCur; - (void)p; - pCur = wx_sqlite3_malloc( sizeof(*pCur) ); - if( pCur==0 ) return SQLITE_NOMEM; - memset(pCur, 0, sizeof(*pCur)); - pCur->iLvl = -1; - *ppCursor = &pCur->base; - return SQLITE_OK; -} - -/* -** Reset a cursor back to the state it was in when first returned -** by fsdirOpen(). -*/ -static void fsdirResetCursor(fsdir_cursor *pCur){ - int i; - for(i=0; i<=pCur->iLvl; i++){ - FsdirLevel *pLvl = &pCur->aLvl[i]; - if( pLvl->pDir ) closedir(pLvl->pDir); - wx_sqlite3_free(pLvl->zDir); - } - wx_sqlite3_free(pCur->zPath); - wx_sqlite3_free(pCur->aLvl); - pCur->aLvl = 0; - pCur->zPath = 0; - pCur->zBase = 0; - pCur->nBase = 0; - pCur->nLvl = 0; - pCur->iLvl = -1; - pCur->iRowid = 1; -} - -/* -** Destructor for an fsdir_cursor. -*/ -static int fsdirClose(wx_sqlite3_vtab_cursor *cur){ - fsdir_cursor *pCur = (fsdir_cursor*)cur; - - fsdirResetCursor(pCur); - wx_sqlite3_free(pCur); - return SQLITE_OK; -} - -/* -** Set the error message for the virtual table associated with cursor -** pCur to the results of vprintf(zFmt, ...). -*/ -static void fsdirSetErrmsg(fsdir_cursor *pCur, const char *zFmt, ...){ - va_list ap; - va_start(ap, zFmt); - pCur->base.pVtab->zErrMsg = wx_sqlite3_vmprintf(zFmt, ap); - va_end(ap); -} - - -/* -** Advance an fsdir_cursor to its next row of output. -*/ -static int fsdirNext(wx_sqlite3_vtab_cursor *cur){ - fsdir_cursor *pCur = (fsdir_cursor*)cur; - mode_t m = pCur->sStat.st_mode; - - pCur->iRowid++; - if( S_ISDIR(m) ){ - /* Descend into this directory */ - int iNew = pCur->iLvl + 1; - FsdirLevel *pLvl; - if( iNew>=pCur->nLvl ){ - int nNew = iNew+1; - int nByte = nNew*sizeof(FsdirLevel); - FsdirLevel *aNew = (FsdirLevel*)wx_sqlite3_realloc(pCur->aLvl, nByte); - if( aNew==0 ) return SQLITE_NOMEM; - memset(&aNew[pCur->nLvl], 0, sizeof(FsdirLevel)*(nNew-pCur->nLvl)); - pCur->aLvl = aNew; - pCur->nLvl = nNew; - } - pCur->iLvl = iNew; - pLvl = &pCur->aLvl[iNew]; - - pLvl->zDir = pCur->zPath; - pCur->zPath = 0; - pLvl->pDir = opendir(pLvl->zDir); - if( pLvl->pDir==0 ){ - fsdirSetErrmsg(pCur, "cannot read directory: %s", pCur->zPath); - return SQLITE_ERROR; - } - } - - while( pCur->iLvl>=0 ){ - FsdirLevel *pLvl = &pCur->aLvl[pCur->iLvl]; - struct dirent *pEntry = readdir(pLvl->pDir); - if( pEntry ){ - if( pEntry->d_name[0]=='.' ){ - if( pEntry->d_name[1]=='.' && pEntry->d_name[2]=='\0' ) continue; - if( pEntry->d_name[1]=='\0' ) continue; - } - wx_sqlite3_free(pCur->zPath); - pCur->zPath = wx_sqlite3_mprintf("%s/%s", pLvl->zDir, pEntry->d_name); - if( pCur->zPath==0 ) return SQLITE_NOMEM; - if( fileLinkStat(pCur->zPath, &pCur->sStat) ){ - fsdirSetErrmsg(pCur, "cannot stat file: %s", pCur->zPath); - return SQLITE_ERROR; - } - return SQLITE_OK; - } - closedir(pLvl->pDir); - wx_sqlite3_free(pLvl->zDir); - pLvl->pDir = 0; - pLvl->zDir = 0; - pCur->iLvl--; - } - - /* EOF */ - wx_sqlite3_free(pCur->zPath); - pCur->zPath = 0; - return SQLITE_OK; -} - -/* -** Return values of columns for the row at which the series_cursor -** is currently pointing. -*/ -static int fsdirColumn( - wx_sqlite3_vtab_cursor *cur, /* The cursor */ - wx_sqlite3_context *ctx, /* First argument to wx_sqlite3_result_...() */ - int i /* Which column to return */ -){ - fsdir_cursor *pCur = (fsdir_cursor*)cur; - switch( i ){ - case 0: { /* name */ - wx_sqlite3_result_text(ctx, &pCur->zPath[pCur->nBase], -1, SQLITE_TRANSIENT); - break; - } - - case 1: /* mode */ - wx_sqlite3_result_int64(ctx, pCur->sStat.st_mode); - break; - - case 2: /* mtime */ - wx_sqlite3_result_int64(ctx, pCur->sStat.st_mtime); - break; - - case 3: { /* data */ - mode_t m = pCur->sStat.st_mode; - if( S_ISDIR(m) ){ - wx_sqlite3_result_null(ctx); -#if !defined(_WIN32) && !defined(WIN32) - }else if( S_ISLNK(m) ){ - char aStatic[64]; - char *aBuf = aStatic; - int nBuf = 64; - int n; - - while( 1 ){ - n = readlink(pCur->zPath, aBuf, nBuf); - if( n<nBuf ) break; - if( aBuf!=aStatic ) wx_sqlite3_free(aBuf); - nBuf = nBuf*2; - aBuf = wx_sqlite3_malloc(nBuf); - if( aBuf==0 ){ - wx_sqlite3_result_error_nomem(ctx); - return SQLITE_NOMEM; - } - } - - wx_sqlite3_result_text(ctx, aBuf, n, SQLITE_TRANSIENT); - if( aBuf!=aStatic ) wx_sqlite3_free(aBuf); -#endif - }else{ - readFileContents(ctx, pCur->zPath); - } - } - } - return SQLITE_OK; -} - -/* -** Return the rowid for the current row. In this implementation, the -** first row returned is assigned rowid value 1, and each subsequent -** row a value 1 more than that of the previous. -*/ -static int fsdirRowid(wx_sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ - fsdir_cursor *pCur = (fsdir_cursor*)cur; - *pRowid = pCur->iRowid; - return SQLITE_OK; -} - -/* -** Return TRUE if the cursor has been moved off of the last -** row of output. -*/ -static int fsdirEof(wx_sqlite3_vtab_cursor *cur){ - fsdir_cursor *pCur = (fsdir_cursor*)cur; - return (pCur->zPath==0); -} - -/* -** xFilter callback. -*/ -static int fsdirFilter( - wx_sqlite3_vtab_cursor *cur, - int idxNum, const char *idxStr, - int argc, wx_sqlite3_value **argv -){ - const char *zDir = 0; - fsdir_cursor *pCur = (fsdir_cursor*)cur; - (void)idxStr; - fsdirResetCursor(pCur); - - if( idxNum==0 ){ - fsdirSetErrmsg(pCur, "table function fsdir requires an argument"); - return SQLITE_ERROR; - } - - assert( argc==idxNum && (argc==1 || argc==2) ); - zDir = (const char*)wx_sqlite3_value_text(argv[0]); - if( zDir==0 ){ - fsdirSetErrmsg(pCur, "table function fsdir requires a non-NULL argument"); - return SQLITE_ERROR; - } - if( argc==2 ){ - pCur->zBase = (const char*)wx_sqlite3_value_text(argv[1]); - } - if( pCur->zBase ){ - pCur->nBase = (int)strlen(pCur->zBase)+1; - pCur->zPath = wx_sqlite3_mprintf("%s/%s", pCur->zBase, zDir); - }else{ - pCur->zPath = wx_sqlite3_mprintf("%s", zDir); - } - - if( pCur->zPath==0 ){ - return SQLITE_NOMEM; - } - if( fileLinkStat(pCur->zPath, &pCur->sStat) ){ - fsdirSetErrmsg(pCur, "cannot stat file: %s", pCur->zPath); - return SQLITE_ERROR; - } - - return SQLITE_OK; -} - -/* -** SQLite will invoke this method one or more times while planning a query -** that uses the generate_series virtual table. This routine needs to create -** a query plan for each invocation and compute an estimated cost for that -** plan. -** -** In this implementation idxNum is used to represent the -** query plan. idxStr is unused. -** -** The query plan is represented by bits in idxNum: -** -** (1) start = $value -- constraint exists -** (2) stop = $value -- constraint exists -** (4) step = $value -- constraint exists -** (8) output in descending order -*/ -static int fsdirBestIndex( - wx_sqlite3_vtab *tab, - wx_sqlite3_index_info *pIdxInfo -){ - int i; /* Loop over constraints */ - int idx4 = -1; - int idx5 = -1; - const struct wx_sqlite3_index_constraint *pConstraint; - - (void)tab; - pConstraint = pIdxInfo->aConstraint; - for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){ - if( pConstraint->usable==0 ) continue; - if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; - if( pConstraint->iColumn==4 ) idx4 = i; - if( pConstraint->iColumn==5 ) idx5 = i; - } - - if( idx4<0 ){ - pIdxInfo->idxNum = 0; - pIdxInfo->estimatedCost = (double)(((wx_sqlite3_int64)1) << 50); - }else{ - pIdxInfo->aConstraintUsage[idx4].omit = 1; - pIdxInfo->aConstraintUsage[idx4].argvIndex = 1; - if( idx5>=0 ){ - pIdxInfo->aConstraintUsage[idx5].omit = 1; - pIdxInfo->aConstraintUsage[idx5].argvIndex = 2; - pIdxInfo->idxNum = 2; - pIdxInfo->estimatedCost = 10.0; - }else{ - pIdxInfo->idxNum = 1; - pIdxInfo->estimatedCost = 100.0; - } - } - - return SQLITE_OK; -} - -/* -** Register the "fsdir" virtual table. -*/ -static int fsdirRegister(wx_sqlite3 *db){ - static wx_sqlite3_module fsdirModule = { - 0, /* iVersion */ - 0, /* xCreate */ - fsdirConnect, /* xConnect */ - fsdirBestIndex, /* xBestIndex */ - fsdirDisconnect, /* xDisconnect */ - 0, /* xDestroy */ - fsdirOpen, /* xOpen - open a cursor */ - fsdirClose, /* xClose - close a cursor */ - fsdirFilter, /* xFilter - configure scan constraints */ - fsdirNext, /* xNext - advance a cursor */ - fsdirEof, /* xEof - check for end of scan */ - fsdirColumn, /* xColumn - read data */ - fsdirRowid, /* xRowid - read data */ - 0, /* xUpdate */ - 0, /* xBegin */ - 0, /* xSync */ - 0, /* xCommit */ - 0, /* xRollback */ - 0, /* xFindMethod */ - 0, /* xRename */ - 0, /* xSavepoint */ - 0, /* xRelease */ - 0 /* xRollbackTo */ - }; - - int rc = wx_sqlite3_create_module(db, "fsdir", &fsdirModule, 0); - return rc; -} -#else /* SQLITE_OMIT_VIRTUALTABLE */ -# define fsdirRegister(x) SQLITE_OK -#endif - -#ifdef _WIN32 -__declspec(dllexport) -#endif -int wx_sqlite3_fileio_init( - wx_sqlite3 *db, - char **pzErrMsg, - const wx_sqlite3_api_routines *pApi -){ - int rc = SQLITE_OK; - SQLITE_EXTENSION_INIT2(pApi); - (void)pzErrMsg; /* Unused parameter */ - rc = wx_sqlite3_create_function(db, "readfile", 1, SQLITE_UTF8, 0, - readfileFunc, 0, 0); - if( rc==SQLITE_OK ){ - rc = wx_sqlite3_create_function(db, "writefile", -1, SQLITE_UTF8, 0, - writefileFunc, 0, 0); - } - if( rc==SQLITE_OK ){ - rc = wx_sqlite3_create_function(db, "lsmode", 1, SQLITE_UTF8, 0, - lsModeFunc, 0, 0); - } - if( rc==SQLITE_OK ){ - rc = fsdirRegister(db); - } - return rc; -} - |
