4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
11 ******************************************************************************
13 ** This SQLite extension implements SQL functions readfile() and
14 ** writefile(), and eponymous virtual type "fsdir".
16 ** WRITEFILE(FILE, DATA [, MODE [, MTIME]]):
18 ** If neither of the optional arguments is present, then this UDF
19 ** function writes blob DATA to file FILE. If successful, the number
20 ** of bytes written is returned. If an error occurs, NULL is returned.
22 ** If the first option argument - MODE - is present, then it must
23 ** be passed an integer value that corresponds to a POSIX mode
24 ** value (file type + permissions, as returned in the stat.st_mode
25 ** field by the stat() system call). Three types of files may
26 ** be written/created:
28 ** regular files: (mode & 0170000)==0100000
29 ** symbolic links: (mode & 0170000)==0120000
30 ** directories: (mode & 0170000)==0040000
32 ** For a directory, the DATA is ignored. For a symbolic link, it is
33 ** interpreted as text and used as the target of the link. For a
34 ** regular file, it is interpreted as a blob and written into the
35 ** named file. Regardless of the type of file, its permissions are
36 ** set to (mode & 0777) before returning.
38 ** If the optional MTIME argument is present, then it is interpreted
39 ** as an integer - the number of seconds since the unix epoch. The
40 ** modification-time of the target file is set to this value before
43 ** If three or more arguments are passed to this function and an
44 ** error is encountered, an exception is raised.
48 ** Read and return the contents of file FILE (type blob) from disk.
54 ** SELECT * FROM fsdir($path [, $dir]);
56 ** Parameter $path is an absolute or relative pathname. If the file that it
57 ** refers to does not exist, it is an error. If the path refers to a regular
58 ** file or symbolic link, it returns a single row. Or, if the path refers
59 ** to a directory, it returns one row for the directory, and one row for each
60 ** file within the hierarchy rooted at $path.
62 ** Each row has the following columns:
64 ** name: Path to file or directory (text value).
65 ** mode: Value of stat.st_mode for directory entry (an integer).
66 ** mtime: Value of stat.st_mtime for directory entry (an integer).
67 ** data: For a regular file, a blob containing the file data. For a
68 ** symlink, a text value containing the text of the link. For a
71 ** If a non-NULL value is specified for the optional $dir parameter and
72 ** $path is a relative path, then $path is interpreted relative to $dir.
73 ** And the paths returned in the "name" column of the table are also
74 ** relative to directory $dir.
76 ** Notes on building this extension for Windows:
77 ** Unless linked statically with the SQLite library, a preprocessor
78 ** symbol, FILEIO_WIN32_DLL, must be #define'd to create a stand-alone
79 ** DLL form of this extension for WIN32. See its use below for details.
81 #include "sqlite3ext.h"
82 SQLITE_EXTENSION_INIT1
87 #include <sys/types.h>
90 #if !defined(_WIN32) && !defined(WIN32)
94 # include <sys/time.h>
99 # include "test_windirent.h"
100 # define dirent DIRENT
102 # define chmod _chmod
107 # define mkdir(path,mode) _mkdir(path)
108 # define lstat(path,buf) stat(path,buf)
115 ** Structure of the fsdir() table-valued function
118 #define FSDIR_SCHEMA "(name,mode,mtime,data,path HIDDEN,dir HIDDEN)"
119 #define FSDIR_COLUMN_NAME 0 /* Name of the file */
120 #define FSDIR_COLUMN_MODE 1 /* Access mode */
121 #define FSDIR_COLUMN_MTIME 2 /* Last modification time */
122 #define FSDIR_COLUMN_DATA 3 /* File content */
123 #define FSDIR_COLUMN_PATH 4 /* Path to top of search */
124 #define FSDIR_COLUMN_DIR 5 /* Path is relative to this directory */
128 ** Set the result stored by context ctx to a blob containing the
129 ** contents of file zName. Or, leave the result unchanged (NULL)
130 ** if the file does not exist or is unreadable.
132 ** If the file exceeds the SQLite blob size limit, through an
133 ** SQLITE_TOOBIG error.
135 ** Throw an SQLITE_IOERR if there are difficulties pulling the file
138 static void readFileContents(sqlite3_context
*ctx
, const char *zName
){
145 in
= fopen(zName
, "rb");
147 /* File does not exist or is unreadable. Leave the result set to NULL. */
150 fseek(in
, 0, SEEK_END
);
153 db
= sqlite3_context_db_handle(ctx
);
154 mxBlob
= sqlite3_limit(db
, SQLITE_LIMIT_LENGTH
, -1);
156 sqlite3_result_error_code(ctx
, SQLITE_TOOBIG
);
160 pBuf
= sqlite3_malloc64( nIn
? nIn
: 1 );
162 sqlite3_result_error_nomem(ctx
);
166 if( nIn
==(sqlite3_int64
)fread(pBuf
, 1, (size_t)nIn
, in
) ){
167 sqlite3_result_blob64(ctx
, pBuf
, nIn
, sqlite3_free
);
169 sqlite3_result_error_code(ctx
, SQLITE_IOERR
);
176 ** Implementation of the "readfile(X)" SQL function. The entire content
177 ** of the file named X is read and returned as a BLOB. NULL is returned
178 ** if the file does not exist or is unreadable.
180 static void readfileFunc(
181 sqlite3_context
*context
,
186 (void)(argc
); /* Unused parameter */
187 zName
= (const char*)sqlite3_value_text(argv
[0]);
188 if( zName
==0 ) return;
189 readFileContents(context
, zName
);
193 ** Set the error message contained in context ctx to the results of
194 ** vprintf(zFmt, ...).
196 static void ctxErrorMsg(sqlite3_context
*ctx
, const char *zFmt
, ...){
200 zMsg
= sqlite3_vmprintf(zFmt
, ap
);
201 sqlite3_result_error(ctx
, zMsg
, -1);
208 ** This function is designed to convert a Win32 FILETIME structure into the
209 ** number of seconds since the Unix Epoch (1970-01-01 00:00:00 UTC).
211 static sqlite3_uint64
fileTimeToUnixTime(
214 SYSTEMTIME epochSystemTime
;
215 ULARGE_INTEGER epochIntervals
;
216 FILETIME epochFileTime
;
217 ULARGE_INTEGER fileIntervals
;
219 memset(&epochSystemTime
, 0, sizeof(SYSTEMTIME
));
220 epochSystemTime
.wYear
= 1970;
221 epochSystemTime
.wMonth
= 1;
222 epochSystemTime
.wDay
= 1;
223 SystemTimeToFileTime(&epochSystemTime
, &epochFileTime
);
224 epochIntervals
.LowPart
= epochFileTime
.dwLowDateTime
;
225 epochIntervals
.HighPart
= epochFileTime
.dwHighDateTime
;
227 fileIntervals
.LowPart
= pFileTime
->dwLowDateTime
;
228 fileIntervals
.HighPart
= pFileTime
->dwHighDateTime
;
230 return (fileIntervals
.QuadPart
- epochIntervals
.QuadPart
) / 10000000;
234 #if defined(FILEIO_WIN32_DLL) && (defined(_WIN32) || defined(WIN32))
235 # /* To allow a standalone DLL, use this next replacement function: */
236 # undef sqlite3_win32_utf8_to_unicode
237 # define sqlite3_win32_utf8_to_unicode utf8_to_utf16
239 LPWSTR
utf8_to_utf16(const char *z
){
240 int nAllot
= MultiByteToWideChar(CP_UTF8
, 0, z
, -1, NULL
, 0);
241 LPWSTR rv
= sqlite3_malloc(nAllot
* sizeof(WCHAR
));
242 if( rv
!=0 && 0 < MultiByteToWideChar(CP_UTF8
, 0, z
, -1, rv
, nAllot
) )
250 ** This function attempts to normalize the time values found in the stat()
251 ** buffer to UTC. This is necessary on Win32, where the runtime library
252 ** appears to return these values as local times.
254 static void statTimesToUtc(
256 struct stat
*pStatBuf
261 extern LPWSTR
sqlite3_win32_utf8_to_unicode(const char*);
262 zUnicodeName
= sqlite3_win32_utf8_to_unicode(zPath
);
264 memset(&fd
, 0, sizeof(WIN32_FIND_DATAW
));
265 hFindFile
= FindFirstFileW(zUnicodeName
, &fd
);
266 if( hFindFile
!=NULL
){
267 pStatBuf
->st_ctime
= (time_t)fileTimeToUnixTime(&fd
.ftCreationTime
);
268 pStatBuf
->st_atime
= (time_t)fileTimeToUnixTime(&fd
.ftLastAccessTime
);
269 pStatBuf
->st_mtime
= (time_t)fileTimeToUnixTime(&fd
.ftLastWriteTime
);
270 FindClose(hFindFile
);
272 sqlite3_free(zUnicodeName
);
278 ** This function is used in place of stat(). On Windows, special handling
279 ** is required in order for the included time to be returned as UTC. On all
280 ** other systems, this function simply calls stat().
284 struct stat
*pStatBuf
287 int rc
= stat(zPath
, pStatBuf
);
288 if( rc
==0 ) statTimesToUtc(zPath
, pStatBuf
);
291 return stat(zPath
, pStatBuf
);
296 ** This function is used in place of lstat(). On Windows, special handling
297 ** is required in order for the included time to be returned as UTC. On all
298 ** other systems, this function simply calls lstat().
300 static int fileLinkStat(
302 struct stat
*pStatBuf
305 int rc
= lstat(zPath
, pStatBuf
);
306 if( rc
==0 ) statTimesToUtc(zPath
, pStatBuf
);
309 return lstat(zPath
, pStatBuf
);
314 ** Argument zFile is the name of a file that will be created and/or written
315 ** by SQL function writefile(). This function ensures that the directory
316 ** zFile will be written to exists, creating it if required. The permissions
317 ** for any path components created by this function are set in accordance
318 ** with the current umask.
320 ** If an OOM condition is encountered, SQLITE_NOMEM is returned. Otherwise,
321 ** SQLITE_OK is returned if the directory is successfully created, or
322 ** SQLITE_ERROR otherwise.
324 static int makeDirectory(
327 char *zCopy
= sqlite3_mprintf("%s", zFile
);
333 int nCopy
= (int)strlen(zCopy
);
336 while( rc
==SQLITE_OK
){
340 for(; zCopy
[i
]!='/' && i
<nCopy
; i
++);
341 if( i
==nCopy
) break;
344 rc2
= fileStat(zCopy
, &sStat
);
346 if( mkdir(zCopy
, 0777) ) rc
= SQLITE_ERROR
;
348 if( !S_ISDIR(sStat
.st_mode
) ) rc
= SQLITE_ERROR
;
361 ** This function does the work for the writefile() UDF. Refer to
362 ** header comments at the top of this file for details.
364 static int writeFile(
365 sqlite3_context
*pCtx
, /* Context to return bytes written in */
366 const char *zFile
, /* File to write */
367 sqlite3_value
*pData
, /* Data to write */
368 mode_t mode
, /* MODE parameter passed to writefile() */
369 sqlite3_int64 mtime
/* MTIME parameter (or -1 to not set time) */
371 if( zFile
==0 ) return 1;
372 #if !defined(_WIN32) && !defined(WIN32)
374 const char *zTo
= (const char*)sqlite3_value_text(pData
);
375 if( zTo
==0 ) return 1;
377 if( symlink(zTo
, zFile
)<0 ) return 1;
382 if( mkdir(zFile
, mode
) ){
383 /* The mkdir() call to create the directory failed. This might not
384 ** be an error though - if there is already a directory at the same
385 ** path and either the permissions already match or can be changed
386 ** to do so using chmod(), it is not an error. */
389 || 0!=fileStat(zFile
, &sStat
)
390 || !S_ISDIR(sStat
.st_mode
)
391 || ((sStat
.st_mode
&0777)!=(mode
&0777) && 0!=chmod(zFile
, mode
&0777))
397 sqlite3_int64 nWrite
= 0;
400 FILE *out
= fopen(zFile
, "wb");
401 if( out
==0 ) return 1;
402 z
= (const char*)sqlite3_value_blob(pData
);
404 sqlite3_int64 n
= fwrite(z
, 1, sqlite3_value_bytes(pData
), out
);
405 nWrite
= sqlite3_value_bytes(pData
);
411 if( rc
==0 && mode
&& chmod(zFile
, mode
& 0777) ){
415 sqlite3_result_int64(pCtx
, nWrite
);
425 SYSTEMTIME currentTime
;
429 extern LPWSTR
sqlite3_win32_utf8_to_unicode(const char*);
431 GetSystemTime(¤tTime
);
432 SystemTimeToFileTime(¤tTime
, &lastAccess
);
433 intervals
= Int32x32To64(mtime
, 10000000) + 116444736000000000;
434 lastWrite
.dwLowDateTime
= (DWORD
)intervals
;
435 lastWrite
.dwHighDateTime
= intervals
>> 32;
436 zUnicodeName
= sqlite3_win32_utf8_to_unicode(zFile
);
437 if( zUnicodeName
==0 ){
441 zUnicodeName
, FILE_WRITE_ATTRIBUTES
, 0, NULL
, OPEN_EXISTING
,
442 FILE_FLAG_BACKUP_SEMANTICS
, NULL
444 sqlite3_free(zUnicodeName
);
445 if( hFile
!=INVALID_HANDLE_VALUE
){
446 BOOL bResult
= SetFileTime(hFile
, NULL
, &lastAccess
, &lastWrite
);
453 #elif defined(AT_FDCWD) && 0 /* utimensat() is not universally available */
455 struct timespec times
[2];
456 times
[0].tv_nsec
= times
[1].tv_nsec
= 0;
457 times
[0].tv_sec
= time(0);
458 times
[1].tv_sec
= mtime
;
459 if( utimensat(AT_FDCWD
, zFile
, times
, AT_SYMLINK_NOFOLLOW
) ){
465 ** Do not use utimes() on a symbolic link - it sees through the link and
466 ** modifies the timestamps on the target. Or fails if the target does
468 if( 0==S_ISLNK(mode
) ){
469 struct timeval times
[2];
470 times
[0].tv_usec
= times
[1].tv_usec
= 0;
471 times
[0].tv_sec
= time(0);
472 times
[1].tv_sec
= mtime
;
473 if( utimes(zFile
, times
) ){
484 ** Implementation of the "writefile(W,X[,Y[,Z]]])" SQL function.
485 ** Refer to header comments at the top of this file for details.
487 static void writefileFunc(
488 sqlite3_context
*context
,
495 sqlite3_int64 mtime
= -1;
497 if( argc
<2 || argc
>4 ){
498 sqlite3_result_error(context
,
499 "wrong number of arguments to function writefile()", -1
504 zFile
= (const char*)sqlite3_value_text(argv
[0]);
505 if( zFile
==0 ) return;
507 mode
= (mode_t
)sqlite3_value_int(argv
[2]);
510 mtime
= sqlite3_value_int64(argv
[3]);
513 res
= writeFile(context
, zFile
, argv
[1], mode
, mtime
);
514 if( res
==1 && errno
==ENOENT
){
515 if( makeDirectory(zFile
)==SQLITE_OK
){
516 res
= writeFile(context
, zFile
, argv
[1], mode
, mtime
);
520 if( argc
>2 && res
!=0 ){
522 ctxErrorMsg(context
, "failed to create symlink: %s", zFile
);
523 }else if( S_ISDIR(mode
) ){
524 ctxErrorMsg(context
, "failed to create directory: %s", zFile
);
526 ctxErrorMsg(context
, "failed to write file: %s", zFile
);
532 ** SQL function: lsmode(MODE)
534 ** Given a numberic st_mode from stat(), convert it into a human-readable
535 ** text string in the style of "ls -l".
537 static void lsModeFunc(
538 sqlite3_context
*context
,
543 int iMode
= sqlite3_value_int(argv
[0]);
546 if( S_ISLNK(iMode
) ){
548 }else if( S_ISREG(iMode
) ){
550 }else if( S_ISDIR(iMode
) ){
556 int m
= (iMode
>> ((2-i
)*3));
557 char *a
= &z
[1 + i
*3];
558 a
[0] = (m
& 0x4) ? 'r' : '-';
559 a
[1] = (m
& 0x2) ? 'w' : '-';
560 a
[2] = (m
& 0x1) ? 'x' : '-';
563 sqlite3_result_text(context
, z
, -1, SQLITE_TRANSIENT
);
566 #ifndef SQLITE_OMIT_VIRTUALTABLE
569 ** Cursor type for recursively iterating through a directory structure.
571 typedef struct fsdir_cursor fsdir_cursor
;
572 typedef struct FsdirLevel FsdirLevel
;
575 DIR *pDir
; /* From opendir() */
576 char *zDir
; /* Name of directory (nul-terminated) */
579 struct fsdir_cursor
{
580 sqlite3_vtab_cursor base
; /* Base class - must be first */
582 int nLvl
; /* Number of entries in aLvl[] array */
583 int iLvl
; /* Index of current entry */
584 FsdirLevel
*aLvl
; /* Hierarchy of directories being traversed */
589 struct stat sStat
; /* Current lstat() results */
590 char *zPath
; /* Path to current entry */
591 sqlite3_int64 iRowid
; /* Current rowid */
594 typedef struct fsdir_tab fsdir_tab
;
596 sqlite3_vtab base
; /* Base class - must be first */
600 ** Construct a new fsdir virtual table object.
602 static int fsdirConnect(
605 int argc
, const char *const*argv
,
606 sqlite3_vtab
**ppVtab
,
615 rc
= sqlite3_declare_vtab(db
, "CREATE TABLE x" FSDIR_SCHEMA
);
617 pNew
= (fsdir_tab
*)sqlite3_malloc( sizeof(*pNew
) );
618 if( pNew
==0 ) return SQLITE_NOMEM
;
619 memset(pNew
, 0, sizeof(*pNew
));
620 sqlite3_vtab_config(db
, SQLITE_VTAB_DIRECTONLY
);
622 *ppVtab
= (sqlite3_vtab
*)pNew
;
627 ** This method is the destructor for fsdir vtab objects.
629 static int fsdirDisconnect(sqlite3_vtab
*pVtab
){
635 ** Constructor for a new fsdir_cursor object.
637 static int fsdirOpen(sqlite3_vtab
*p
, sqlite3_vtab_cursor
**ppCursor
){
640 pCur
= sqlite3_malloc( sizeof(*pCur
) );
641 if( pCur
==0 ) return SQLITE_NOMEM
;
642 memset(pCur
, 0, sizeof(*pCur
));
644 *ppCursor
= &pCur
->base
;
649 ** Reset a cursor back to the state it was in when first returned
652 static void fsdirResetCursor(fsdir_cursor
*pCur
){
654 for(i
=0; i
<=pCur
->iLvl
; i
++){
655 FsdirLevel
*pLvl
= &pCur
->aLvl
[i
];
656 if( pLvl
->pDir
) closedir(pLvl
->pDir
);
657 sqlite3_free(pLvl
->zDir
);
659 sqlite3_free(pCur
->zPath
);
660 sqlite3_free(pCur
->aLvl
);
671 ** Destructor for an fsdir_cursor.
673 static int fsdirClose(sqlite3_vtab_cursor
*cur
){
674 fsdir_cursor
*pCur
= (fsdir_cursor
*)cur
;
676 fsdirResetCursor(pCur
);
682 ** Set the error message for the virtual table associated with cursor
683 ** pCur to the results of vprintf(zFmt, ...).
685 static void fsdirSetErrmsg(fsdir_cursor
*pCur
, const char *zFmt
, ...){
688 pCur
->base
.pVtab
->zErrMsg
= sqlite3_vmprintf(zFmt
, ap
);
694 ** Advance an fsdir_cursor to its next row of output.
696 static int fsdirNext(sqlite3_vtab_cursor
*cur
){
697 fsdir_cursor
*pCur
= (fsdir_cursor
*)cur
;
698 mode_t m
= pCur
->sStat
.st_mode
;
702 /* Descend into this directory */
703 int iNew
= pCur
->iLvl
+ 1;
705 if( iNew
>=pCur
->nLvl
){
707 sqlite3_int64 nByte
= nNew
*sizeof(FsdirLevel
);
708 FsdirLevel
*aNew
= (FsdirLevel
*)sqlite3_realloc64(pCur
->aLvl
, nByte
);
709 if( aNew
==0 ) return SQLITE_NOMEM
;
710 memset(&aNew
[pCur
->nLvl
], 0, sizeof(FsdirLevel
)*(nNew
-pCur
->nLvl
));
715 pLvl
= &pCur
->aLvl
[iNew
];
717 pLvl
->zDir
= pCur
->zPath
;
719 pLvl
->pDir
= opendir(pLvl
->zDir
);
721 fsdirSetErrmsg(pCur
, "cannot read directory: %s", pCur
->zPath
);
726 while( pCur
->iLvl
>=0 ){
727 FsdirLevel
*pLvl
= &pCur
->aLvl
[pCur
->iLvl
];
728 struct dirent
*pEntry
= readdir(pLvl
->pDir
);
730 if( pEntry
->d_name
[0]=='.' ){
731 if( pEntry
->d_name
[1]=='.' && pEntry
->d_name
[2]=='\0' ) continue;
732 if( pEntry
->d_name
[1]=='\0' ) continue;
734 sqlite3_free(pCur
->zPath
);
735 pCur
->zPath
= sqlite3_mprintf("%s/%s", pLvl
->zDir
, pEntry
->d_name
);
736 if( pCur
->zPath
==0 ) return SQLITE_NOMEM
;
737 if( fileLinkStat(pCur
->zPath
, &pCur
->sStat
) ){
738 fsdirSetErrmsg(pCur
, "cannot stat file: %s", pCur
->zPath
);
743 closedir(pLvl
->pDir
);
744 sqlite3_free(pLvl
->zDir
);
751 sqlite3_free(pCur
->zPath
);
757 ** Return values of columns for the row at which the series_cursor
758 ** is currently pointing.
760 static int fsdirColumn(
761 sqlite3_vtab_cursor
*cur
, /* The cursor */
762 sqlite3_context
*ctx
, /* First argument to sqlite3_result_...() */
763 int i
/* Which column to return */
765 fsdir_cursor
*pCur
= (fsdir_cursor
*)cur
;
767 case FSDIR_COLUMN_NAME
: {
768 sqlite3_result_text(ctx
, &pCur
->zPath
[pCur
->nBase
], -1, SQLITE_TRANSIENT
);
772 case FSDIR_COLUMN_MODE
:
773 sqlite3_result_int64(ctx
, pCur
->sStat
.st_mode
);
776 case FSDIR_COLUMN_MTIME
:
777 sqlite3_result_int64(ctx
, pCur
->sStat
.st_mtime
);
780 case FSDIR_COLUMN_DATA
: {
781 mode_t m
= pCur
->sStat
.st_mode
;
783 sqlite3_result_null(ctx
);
784 #if !defined(_WIN32) && !defined(WIN32)
785 }else if( S_ISLNK(m
) ){
787 char *aBuf
= aStatic
;
788 sqlite3_int64 nBuf
= 64;
792 n
= readlink(pCur
->zPath
, aBuf
, nBuf
);
794 if( aBuf
!=aStatic
) sqlite3_free(aBuf
);
796 aBuf
= sqlite3_malloc64(nBuf
);
798 sqlite3_result_error_nomem(ctx
);
803 sqlite3_result_text(ctx
, aBuf
, n
, SQLITE_TRANSIENT
);
804 if( aBuf
!=aStatic
) sqlite3_free(aBuf
);
807 readFileContents(ctx
, pCur
->zPath
);
810 case FSDIR_COLUMN_PATH
:
812 /* The FSDIR_COLUMN_PATH and FSDIR_COLUMN_DIR are input parameters.
813 ** always return their values as NULL */
821 ** Return the rowid for the current row. In this implementation, the
822 ** first row returned is assigned rowid value 1, and each subsequent
823 ** row a value 1 more than that of the previous.
825 static int fsdirRowid(sqlite3_vtab_cursor
*cur
, sqlite_int64
*pRowid
){
826 fsdir_cursor
*pCur
= (fsdir_cursor
*)cur
;
827 *pRowid
= pCur
->iRowid
;
832 ** Return TRUE if the cursor has been moved off of the last
835 static int fsdirEof(sqlite3_vtab_cursor
*cur
){
836 fsdir_cursor
*pCur
= (fsdir_cursor
*)cur
;
837 return (pCur
->zPath
==0);
843 ** idxNum==1 PATH parameter only
844 ** idxNum==2 Both PATH and DIR supplied
846 static int fsdirFilter(
847 sqlite3_vtab_cursor
*cur
,
848 int idxNum
, const char *idxStr
,
849 int argc
, sqlite3_value
**argv
851 const char *zDir
= 0;
852 fsdir_cursor
*pCur
= (fsdir_cursor
*)cur
;
854 fsdirResetCursor(pCur
);
857 fsdirSetErrmsg(pCur
, "table function fsdir requires an argument");
861 assert( argc
==idxNum
&& (argc
==1 || argc
==2) );
862 zDir
= (const char*)sqlite3_value_text(argv
[0]);
864 fsdirSetErrmsg(pCur
, "table function fsdir requires a non-NULL argument");
868 pCur
->zBase
= (const char*)sqlite3_value_text(argv
[1]);
871 pCur
->nBase
= (int)strlen(pCur
->zBase
)+1;
872 pCur
->zPath
= sqlite3_mprintf("%s/%s", pCur
->zBase
, zDir
);
874 pCur
->zPath
= sqlite3_mprintf("%s", zDir
);
877 if( pCur
->zPath
==0 ){
880 if( fileLinkStat(pCur
->zPath
, &pCur
->sStat
) ){
881 fsdirSetErrmsg(pCur
, "cannot stat file: %s", pCur
->zPath
);
889 ** SQLite will invoke this method one or more times while planning a query
890 ** that uses the generate_series virtual table. This routine needs to create
891 ** a query plan for each invocation and compute an estimated cost for that
894 ** In this implementation idxNum is used to represent the
895 ** query plan. idxStr is unused.
897 ** The query plan is represented by values of idxNum:
899 ** (1) The path value is supplied by argv[0]
900 ** (2) Path is in argv[0] and dir is in argv[1]
902 static int fsdirBestIndex(
904 sqlite3_index_info
*pIdxInfo
906 int i
; /* Loop over constraints */
907 int idxPath
= -1; /* Index in pIdxInfo->aConstraint of PATH= */
908 int idxDir
= -1; /* Index in pIdxInfo->aConstraint of DIR= */
909 int seenPath
= 0; /* True if an unusable PATH= constraint is seen */
910 int seenDir
= 0; /* True if an unusable DIR= constraint is seen */
911 const struct sqlite3_index_constraint
*pConstraint
;
914 pConstraint
= pIdxInfo
->aConstraint
;
915 for(i
=0; i
<pIdxInfo
->nConstraint
; i
++, pConstraint
++){
916 if( pConstraint
->op
!=SQLITE_INDEX_CONSTRAINT_EQ
) continue;
917 switch( pConstraint
->iColumn
){
918 case FSDIR_COLUMN_PATH
: {
919 if( pConstraint
->usable
){
922 }else if( idxPath
<0 ){
927 case FSDIR_COLUMN_DIR
: {
928 if( pConstraint
->usable
){
931 }else if( idxDir
<0 ){
938 if( seenPath
|| seenDir
){
939 /* If input parameters are unusable, disallow this plan */
940 return SQLITE_CONSTRAINT
;
944 pIdxInfo
->idxNum
= 0;
945 /* The pIdxInfo->estimatedCost should have been initialized to a huge
946 ** number. Leave it unchanged. */
947 pIdxInfo
->estimatedRows
= 0x7fffffff;
949 pIdxInfo
->aConstraintUsage
[idxPath
].omit
= 1;
950 pIdxInfo
->aConstraintUsage
[idxPath
].argvIndex
= 1;
952 pIdxInfo
->aConstraintUsage
[idxDir
].omit
= 1;
953 pIdxInfo
->aConstraintUsage
[idxDir
].argvIndex
= 2;
954 pIdxInfo
->idxNum
= 2;
955 pIdxInfo
->estimatedCost
= 10.0;
957 pIdxInfo
->idxNum
= 1;
958 pIdxInfo
->estimatedCost
= 100.0;
966 ** Register the "fsdir" virtual table.
968 static int fsdirRegister(sqlite3
*db
){
969 static sqlite3_module fsdirModule
= {
972 fsdirConnect
, /* xConnect */
973 fsdirBestIndex
, /* xBestIndex */
974 fsdirDisconnect
, /* xDisconnect */
976 fsdirOpen
, /* xOpen - open a cursor */
977 fsdirClose
, /* xClose - close a cursor */
978 fsdirFilter
, /* xFilter - configure scan constraints */
979 fsdirNext
, /* xNext - advance a cursor */
980 fsdirEof
, /* xEof - check for end of scan */
981 fsdirColumn
, /* xColumn - read data */
982 fsdirRowid
, /* xRowid - read data */
997 int rc
= sqlite3_create_module(db
, "fsdir", &fsdirModule
, 0);
1000 #else /* SQLITE_OMIT_VIRTUALTABLE */
1001 # define fsdirRegister(x) SQLITE_OK
1005 __declspec(dllexport
)
1007 int sqlite3_fileio_init(
1010 const sqlite3_api_routines
*pApi
1013 SQLITE_EXTENSION_INIT2(pApi
);
1014 (void)pzErrMsg
; /* Unused parameter */
1015 rc
= sqlite3_create_function(db
, "readfile", 1,
1016 SQLITE_UTF8
|SQLITE_DIRECTONLY
, 0,
1017 readfileFunc
, 0, 0);
1018 if( rc
==SQLITE_OK
){
1019 rc
= sqlite3_create_function(db
, "writefile", -1,
1020 SQLITE_UTF8
|SQLITE_DIRECTONLY
, 0,
1021 writefileFunc
, 0, 0);
1023 if( rc
==SQLITE_OK
){
1024 rc
= sqlite3_create_function(db
, "lsmode", 1, SQLITE_UTF8
, 0,
1027 if( rc
==SQLITE_OK
){
1028 rc
= fsdirRegister(db
);
1033 #if defined(FILEIO_WIN32_DLL) && (defined(_WIN32) || defined(WIN32))
1034 /* To allow a standalone DLL, make test_windirent.c use the same
1035 * redefined SQLite API calls as the above extension code does.
1036 * Just pull in this .c to accomplish this. As a beneficial side
1037 * effect, this extension becomes a single translation unit. */
1038 # include "test_windirent.c"