1 /*
2 ** 2014-06-13
3 **
4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
6 **
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.
10 **
11 ******************************************************************************
12 **
13 ** This SQLite extension implements SQL functions readfile() and
14 ** writefile(), and eponymous virtual type "fsdir".
15 **
16 ** WRITEFILE(FILE, DATA [, MODE [, MTIME]]):
17 **
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.
21 **
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:
27 **
28 ** regular files: (mode & 0170000)==0100000
29 ** symbolic links: (mode & 0170000)==0120000
30 ** directories: (mode & 0170000)==0040000
31 **
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.
37 **
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
41 ** returning.
42 **
43 ** If three or more arguments are passed to this function and an
44 ** error is encountered, an exception is raised.
45 **
46 ** READFILE(FILE):
47 **
48 ** Read and return the contents of file FILE (type blob) from disk.
49 **
50 ** FSDIR:
51 **
52 ** Used as follows:
53 **
54 ** SELECT * FROM fsdir($path [, $dir]);
55 **
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.
61 **
62 ** Each row has the following columns:
63 **
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
69 ** directory, NULL.
70 **
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.
75 **
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.
80 */
81 #include "sqlite3ext.h"
82 SQLITE_EXTENSION_INIT1
83 #include <stdio.h>
84 #include <string.h>
85 #include <assert.h>
86
87 #include <sys/types.h>
88 #include <sys/stat.h>
89 #include <fcntl.h>
90 #if !defined(_WIN32) && !defined(WIN32)
91 # include <unistd.h>
92 # include <dirent.h>
93 # include <utime.h>
94 # include <sys/time.h>
95 #else
96 # include "windows.h"
97 # include <io.h>
98 # include <direct.h>
99 # include "test_windirent.h"
100 # define dirent DIRENT
101 # ifndef chmod
102 # define chmod _chmod
103 # endif
104 # ifndef stat
105 # define stat _stat
106 # endif
107 # define mkdir(path,mode) _mkdir(path)
108 # define lstat(path,buf) stat(path,buf)
109 #endif
110 #include <time.h>
111 #include <errno.h>
112
113
114 /*
115 ** Structure of the fsdir() table-valued function
116 */
117 /* 0 1 2 3 4 5 */
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 */
125
126
127 /*
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.
131 **
132 ** If the file exceeds the SQLite blob size limit, through an
133 ** SQLITE_TOOBIG error.
134 **
135 ** Throw an SQLITE_IOERR if there are difficulties pulling the file
136 ** off of disk.
137 */
readFileContents(sqlite3_context * ctx,const char * zName)138 static void readFileContents(sqlite3_context *ctx, const char *zName){
139 FILE *in;
140 sqlite3_int64 nIn;
141 void *pBuf;
142 sqlite3 *db;
143 int mxBlob;
144
145 in = fopen(zName, "rb");
146 if( in==0 ){
147 /* File does not exist or is unreadable. Leave the result set to NULL. */
148 return;
149 }
150 fseek(in, 0, SEEK_END);
151 nIn = ftell(in);
152 rewind(in);
153 db = sqlite3_context_db_handle(ctx);
154 mxBlob = sqlite3_limit(db, SQLITE_LIMIT_LENGTH, -1);
155 if( nIn>mxBlob ){
156 sqlite3_result_error_code(ctx, SQLITE_TOOBIG);
157 fclose(in);
158 return;
159 }
160 pBuf = sqlite3_malloc64( nIn ? nIn : 1 );
161 if( pBuf==0 ){
162 sqlite3_result_error_nomem(ctx);
163 fclose(in);
164 return;
165 }
166 if( nIn==(sqlite3_int64)fread(pBuf, 1, (size_t)nIn, in) ){
167 sqlite3_result_blob64(ctx, pBuf, nIn, sqlite3_free);
168 }else{
169 sqlite3_result_error_code(ctx, SQLITE_IOERR);
170 sqlite3_free(pBuf);
171 }
172 fclose(in);
173 }
174
175 /*
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.
179 */
readfileFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)180 static void readfileFunc(
181 sqlite3_context *context,
182 int argc,
183 sqlite3_value **argv
184 ){
185 const char *zName;
186 (void)(argc); /* Unused parameter */
187 zName = (const char*)sqlite3_value_text(argv[0]);
188 if( zName==0 ) return;
189 readFileContents(context, zName);
190 }
191
192 /*
193 ** Set the error message contained in context ctx to the results of
194 ** vprintf(zFmt, ...).
195 */
ctxErrorMsg(sqlite3_context * ctx,const char * zFmt,...)196 static void ctxErrorMsg(sqlite3_context *ctx, const char *zFmt, ...){
197 char *zMsg = 0;
198 va_list ap;
199 va_start(ap, zFmt);
200 zMsg = sqlite3_vmprintf(zFmt, ap);
201 sqlite3_result_error(ctx, zMsg, -1);
202 sqlite3_free(zMsg);
203 va_end(ap);
204 }
205
206 #if defined(_WIN32)
207 /*
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).
210 */
fileTimeToUnixTime(LPFILETIME pFileTime)211 static sqlite3_uint64 fileTimeToUnixTime(
212 LPFILETIME pFileTime
213 ){
214 SYSTEMTIME epochSystemTime;
215 ULARGE_INTEGER epochIntervals;
216 FILETIME epochFileTime;
217 ULARGE_INTEGER fileIntervals;
218
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;
226
227 fileIntervals.LowPart = pFileTime->dwLowDateTime;
228 fileIntervals.HighPart = pFileTime->dwHighDateTime;
229
230 return (fileIntervals.QuadPart - epochIntervals.QuadPart) / 10000000;
231 }
232
233
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
238 #
utf8_to_utf16(const char * z)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) )
243 return rv;
244 sqlite3_free(rv);
245 return 0;
246 }
247 #endif
248
249 /*
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.
253 */
statTimesToUtc(const char * zPath,struct stat * pStatBuf)254 static void statTimesToUtc(
255 const char *zPath,
256 struct stat *pStatBuf
257 ){
258 HANDLE hFindFile;
259 WIN32_FIND_DATAW fd;
260 LPWSTR zUnicodeName;
261 extern LPWSTR sqlite3_win32_utf8_to_unicode(const char*);
262 zUnicodeName = sqlite3_win32_utf8_to_unicode(zPath);
263 if( zUnicodeName ){
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);
271 }
272 sqlite3_free(zUnicodeName);
273 }
274 }
275 #endif
276
277 /*
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().
281 */
fileStat(const char * zPath,struct stat * pStatBuf)282 static int fileStat(
283 const char *zPath,
284 struct stat *pStatBuf
285 ){
286 #if defined(_WIN32)
287 int rc = stat(zPath, pStatBuf);
288 if( rc==0 ) statTimesToUtc(zPath, pStatBuf);
289 return rc;
290 #else
291 return stat(zPath, pStatBuf);
292 #endif
293 }
294
295 /*
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().
299 */
fileLinkStat(const char * zPath,struct stat * pStatBuf)300 static int fileLinkStat(
301 const char *zPath,
302 struct stat *pStatBuf
303 ){
304 #if defined(_WIN32)
305 int rc = lstat(zPath, pStatBuf);
306 if( rc==0 ) statTimesToUtc(zPath, pStatBuf);
307 return rc;
308 #else
309 return lstat(zPath, pStatBuf);
310 #endif
311 }
312
313 /*
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.
319 **
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.
323 */
makeDirectory(const char * zFile)324 static int makeDirectory(
325 const char *zFile
326 ){
327 char *zCopy = sqlite3_mprintf("%s", zFile);
328 int rc = SQLITE_OK;
329
330 if( zCopy==0 ){
331 rc = SQLITE_NOMEM;
332 }else{
333 int nCopy = (int)strlen(zCopy);
334 int i = 1;
335
336 while( rc==SQLITE_OK ){
337 struct stat sStat;
338 int rc2;
339
340 for(; zCopy[i]!='/' && i<nCopy; i++);
341 if( i==nCopy ) break;
342 zCopy[i] = '\0';
343
344 rc2 = fileStat(zCopy, &sStat);
345 if( rc2!=0 ){
346 if( mkdir(zCopy, 0777) ) rc = SQLITE_ERROR;
347 }else{
348 if( !S_ISDIR(sStat.st_mode) ) rc = SQLITE_ERROR;
349 }
350 zCopy[i] = '/';
351 i++;
352 }
353
354 sqlite3_free(zCopy);
355 }
356
357 return rc;
358 }
359
360 /*
361 ** This function does the work for the writefile() UDF. Refer to
362 ** header comments at the top of this file for details.
363 */
writeFile(sqlite3_context * pCtx,const char * zFile,sqlite3_value * pData,mode_t mode,sqlite3_int64 mtime)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) */
370 ){
371 if( zFile==0 ) return 1;
372 #if !defined(_WIN32) && !defined(WIN32)
373 if( S_ISLNK(mode) ){
374 const char *zTo = (const char*)sqlite3_value_text(pData);
375 if( zTo==0 || symlink(zTo, zFile)<0 ) return 1;
376 }else
377 #endif
378 {
379 if( S_ISDIR(mode) ){
380 if( mkdir(zFile, mode) ){
381 /* The mkdir() call to create the directory failed. This might not
382 ** be an error though - if there is already a directory at the same
383 ** path and either the permissions already match or can be changed
384 ** to do so using chmod(), it is not an error. */
385 struct stat sStat;
386 if( errno!=EEXIST
387 || 0!=fileStat(zFile, &sStat)
388 || !S_ISDIR(sStat.st_mode)
389 || ((sStat.st_mode&0777)!=(mode&0777) && 0!=chmod(zFile, mode&0777))
390 ){
391 return 1;
392 }
393 }
394 }else{
395 sqlite3_int64 nWrite = 0;
396 const char *z;
397 int rc = 0;
398 FILE *out = fopen(zFile, "wb");
399 if( out==0 ) return 1;
400 z = (const char*)sqlite3_value_blob(pData);
401 if( z ){
402 sqlite3_int64 n = fwrite(z, 1, sqlite3_value_bytes(pData), out);
403 nWrite = sqlite3_value_bytes(pData);
404 if( nWrite!=n ){
405 rc = 1;
406 }
407 }
408 fclose(out);
409 if( rc==0 && mode && chmod(zFile, mode & 0777) ){
410 rc = 1;
411 }
412 if( rc ) return 2;
413 sqlite3_result_int64(pCtx, nWrite);
414 }
415 }
416
417 if( mtime>=0 ){
418 #if defined(_WIN32)
419 #if !SQLITE_OS_WINRT
420 /* Windows */
421 FILETIME lastAccess;
422 FILETIME lastWrite;
423 SYSTEMTIME currentTime;
424 LONGLONG intervals;
425 HANDLE hFile;
426 LPWSTR zUnicodeName;
427 extern LPWSTR sqlite3_win32_utf8_to_unicode(const char*);
428
429 GetSystemTime(¤tTime);
430 SystemTimeToFileTime(¤tTime, &lastAccess);
431 intervals = Int32x32To64(mtime, 10000000) + 116444736000000000;
432 lastWrite.dwLowDateTime = (DWORD)intervals;
433 lastWrite.dwHighDateTime = intervals >> 32;
434 zUnicodeName = sqlite3_win32_utf8_to_unicode(zFile);
435 if( zUnicodeName==0 ){
436 return 1;
437 }
438 hFile = CreateFileW(
439 zUnicodeName, FILE_WRITE_ATTRIBUTES, 0, NULL, OPEN_EXISTING,
440 FILE_FLAG_BACKUP_SEMANTICS, NULL
441 );
442 sqlite3_free(zUnicodeName);
443 if( hFile!=INVALID_HANDLE_VALUE ){
444 BOOL bResult = SetFileTime(hFile, NULL, &lastAccess, &lastWrite);
445 CloseHandle(hFile);
446 return !bResult;
447 }else{
448 return 1;
449 }
450 #endif
451 #elif defined(AT_FDCWD) && 0 /* utimensat() is not universally available */
452 /* Recent unix */
453 struct timespec times[2];
454 times[0].tv_nsec = times[1].tv_nsec = 0;
455 times[0].tv_sec = time(0);
456 times[1].tv_sec = mtime;
457 if( utimensat(AT_FDCWD, zFile, times, AT_SYMLINK_NOFOLLOW) ){
458 return 1;
459 }
460 #else
461 /* Legacy unix */
462 struct timeval times[2];
463 times[0].tv_usec = times[1].tv_usec = 0;
464 times[0].tv_sec = time(0);
465 times[1].tv_sec = mtime;
466 if( utimes(zFile, times) ){
467 return 1;
468 }
469 #endif
470 }
471
472 return 0;
473 }
474
475 /*
476 ** Implementation of the "writefile(W,X[,Y[,Z]]])" SQL function.
477 ** Refer to header comments at the top of this file for details.
478 */
writefileFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)479 static void writefileFunc(
480 sqlite3_context *context,
481 int argc,
482 sqlite3_value **argv
483 ){
484 const char *zFile;
485 mode_t mode = 0;
486 int res;
487 sqlite3_int64 mtime = -1;
488
489 if( argc<2 || argc>4 ){
490 sqlite3_result_error(context,
491 "wrong number of arguments to function writefile()", -1
492 );
493 return;
494 }
495
496 zFile = (const char*)sqlite3_value_text(argv[0]);
497 if( zFile==0 ) return;
498 if( argc>=3 ){
499 mode = (mode_t)sqlite3_value_int(argv[2]);
500 }
501 if( argc==4 ){
502 mtime = sqlite3_value_int64(argv[3]);
503 }
504
505 res = writeFile(context, zFile, argv[1], mode, mtime);
506 if( res==1 && errno==ENOENT ){
507 if( makeDirectory(zFile)==SQLITE_OK ){
508 res = writeFile(context, zFile, argv[1], mode, mtime);
509 }
510 }
511
512 if( argc>2 && res!=0 ){
513 if( S_ISLNK(mode) ){
514 ctxErrorMsg(context, "failed to create symlink: %s", zFile);
515 }else if( S_ISDIR(mode) ){
516 ctxErrorMsg(context, "failed to create directory: %s", zFile);
517 }else{
518 ctxErrorMsg(context, "failed to write file: %s", zFile);
519 }
520 }
521 }
522
523 /*
524 ** SQL function: lsmode(MODE)
525 **
526 ** Given a numberic st_mode from stat(), convert it into a human-readable
527 ** text string in the style of "ls -l".
528 */
lsModeFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)529 static void lsModeFunc(
530 sqlite3_context *context,
531 int argc,
532 sqlite3_value **argv
533 ){
534 int i;
535 int iMode = sqlite3_value_int(argv[0]);
536 char z[16];
537 (void)argc;
538 if( S_ISLNK(iMode) ){
539 z[0] = 'l';
540 }else if( S_ISREG(iMode) ){
541 z[0] = '-';
542 }else if( S_ISDIR(iMode) ){
543 z[0] = 'd';
544 }else{
545 z[0] = '?';
546 }
547 for(i=0; i<3; i++){
548 int m = (iMode >> ((2-i)*3));
549 char *a = &z[1 + i*3];
550 a[0] = (m & 0x4) ? 'r' : '-';
551 a[1] = (m & 0x2) ? 'w' : '-';
552 a[2] = (m & 0x1) ? 'x' : '-';
553 }
554 z[10] = '\0';
555 sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT);
556 }
557
558 #ifndef SQLITE_OMIT_VIRTUALTABLE
559
560 /*
561 ** Cursor type for recursively iterating through a directory structure.
562 */
563 typedef struct fsdir_cursor fsdir_cursor;
564 typedef struct FsdirLevel FsdirLevel;
565
566 struct FsdirLevel {
567 DIR *pDir; /* From opendir() */
568 char *zDir; /* Name of directory (nul-terminated) */
569 };
570
571 struct fsdir_cursor {
572 sqlite3_vtab_cursor base; /* Base class - must be first */
573
574 int nLvl; /* Number of entries in aLvl[] array */
575 int iLvl; /* Index of current entry */
576 FsdirLevel *aLvl; /* Hierarchy of directories being traversed */
577
578 const char *zBase;
579 int nBase;
580
581 struct stat sStat; /* Current lstat() results */
582 char *zPath; /* Path to current entry */
583 sqlite3_int64 iRowid; /* Current rowid */
584 };
585
586 typedef struct fsdir_tab fsdir_tab;
587 struct fsdir_tab {
588 sqlite3_vtab base; /* Base class - must be first */
589 };
590
591 /*
592 ** Construct a new fsdir virtual table object.
593 */
fsdirConnect(sqlite3 * db,void * pAux,int argc,const char * const * argv,sqlite3_vtab ** ppVtab,char ** pzErr)594 static int fsdirConnect(
595 sqlite3 *db,
596 void *pAux,
597 int argc, const char *const*argv,
598 sqlite3_vtab **ppVtab,
599 char **pzErr
600 ){
601 fsdir_tab *pNew = 0;
602 int rc;
603 (void)pAux;
604 (void)argc;
605 (void)argv;
606 (void)pzErr;
607 rc = sqlite3_declare_vtab(db, "CREATE TABLE x" FSDIR_SCHEMA);
608 if( rc==SQLITE_OK ){
609 pNew = (fsdir_tab*)sqlite3_malloc( sizeof(*pNew) );
610 if( pNew==0 ) return SQLITE_NOMEM;
611 memset(pNew, 0, sizeof(*pNew));
612 sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
613 }
614 *ppVtab = (sqlite3_vtab*)pNew;
615 return rc;
616 }
617
618 /*
619 ** This method is the destructor for fsdir vtab objects.
620 */
fsdirDisconnect(sqlite3_vtab * pVtab)621 static int fsdirDisconnect(sqlite3_vtab *pVtab){
622 sqlite3_free(pVtab);
623 return SQLITE_OK;
624 }
625
626 /*
627 ** Constructor for a new fsdir_cursor object.
628 */
fsdirOpen(sqlite3_vtab * p,sqlite3_vtab_cursor ** ppCursor)629 static int fsdirOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
630 fsdir_cursor *pCur;
631 (void)p;
632 pCur = sqlite3_malloc( sizeof(*pCur) );
633 if( pCur==0 ) return SQLITE_NOMEM;
634 memset(pCur, 0, sizeof(*pCur));
635 pCur->iLvl = -1;
636 *ppCursor = &pCur->base;
637 return SQLITE_OK;
638 }
639
640 /*
641 ** Reset a cursor back to the state it was in when first returned
642 ** by fsdirOpen().
643 */
fsdirResetCursor(fsdir_cursor * pCur)644 static void fsdirResetCursor(fsdir_cursor *pCur){
645 int i;
646 for(i=0; i<=pCur->iLvl; i++){
647 FsdirLevel *pLvl = &pCur->aLvl[i];
648 if( pLvl->pDir ) closedir(pLvl->pDir);
649 sqlite3_free(pLvl->zDir);
650 }
651 sqlite3_free(pCur->zPath);
652 sqlite3_free(pCur->aLvl);
653 pCur->aLvl = 0;
654 pCur->zPath = 0;
655 pCur->zBase = 0;
656 pCur->nBase = 0;
657 pCur->nLvl = 0;
658 pCur->iLvl = -1;
659 pCur->iRowid = 1;
660 }
661
662 /*
663 ** Destructor for an fsdir_cursor.
664 */
fsdirClose(sqlite3_vtab_cursor * cur)665 static int fsdirClose(sqlite3_vtab_cursor *cur){
666 fsdir_cursor *pCur = (fsdir_cursor*)cur;
667
668 fsdirResetCursor(pCur);
669 sqlite3_free(pCur);
670 return SQLITE_OK;
671 }
672
673 /*
674 ** Set the error message for the virtual table associated with cursor
675 ** pCur to the results of vprintf(zFmt, ...).
676 */
fsdirSetErrmsg(fsdir_cursor * pCur,const char * zFmt,...)677 static void fsdirSetErrmsg(fsdir_cursor *pCur, const char *zFmt, ...){
678 va_list ap;
679 va_start(ap, zFmt);
680 pCur->base.pVtab->zErrMsg = sqlite3_vmprintf(zFmt, ap);
681 va_end(ap);
682 }
683
684
685 /*
686 ** Advance an fsdir_cursor to its next row of output.
687 */
fsdirNext(sqlite3_vtab_cursor * cur)688 static int fsdirNext(sqlite3_vtab_cursor *cur){
689 fsdir_cursor *pCur = (fsdir_cursor*)cur;
690 mode_t m = pCur->sStat.st_mode;
691
692 pCur->iRowid++;
693 if( S_ISDIR(m) ){
694 /* Descend into this directory */
695 int iNew = pCur->iLvl + 1;
696 FsdirLevel *pLvl;
697 if( iNew>=pCur->nLvl ){
698 int nNew = iNew+1;
699 sqlite3_int64 nByte = nNew*sizeof(FsdirLevel);
700 FsdirLevel *aNew = (FsdirLevel*)sqlite3_realloc64(pCur->aLvl, nByte);
701 if( aNew==0 ) return SQLITE_NOMEM;
702 memset(&aNew[pCur->nLvl], 0, sizeof(FsdirLevel)*(nNew-pCur->nLvl));
703 pCur->aLvl = aNew;
704 pCur->nLvl = nNew;
705 }
706 pCur->iLvl = iNew;
707 pLvl = &pCur->aLvl[iNew];
708
709 pLvl->zDir = pCur->zPath;
710 pCur->zPath = 0;
711 pLvl->pDir = opendir(pLvl->zDir);
712 if( pLvl->pDir==0 ){
713 fsdirSetErrmsg(pCur, "cannot read directory: %s", pCur->zPath);
714 return SQLITE_ERROR;
715 }
716 }
717
718 while( pCur->iLvl>=0 ){
719 FsdirLevel *pLvl = &pCur->aLvl[pCur->iLvl];
720 struct dirent *pEntry = readdir(pLvl->pDir);
721 if( pEntry ){
722 if( pEntry->d_name[0]=='.' ){
723 if( pEntry->d_name[1]=='.' && pEntry->d_name[2]=='\0' ) continue;
724 if( pEntry->d_name[1]=='\0' ) continue;
725 }
726 sqlite3_free(pCur->zPath);
727 pCur->zPath = sqlite3_mprintf("%s/%s", pLvl->zDir, pEntry->d_name);
728 if( pCur->zPath==0 ) return SQLITE_NOMEM;
729 if( fileLinkStat(pCur->zPath, &pCur->sStat) ){
730 fsdirSetErrmsg(pCur, "cannot stat file: %s", pCur->zPath);
731 return SQLITE_ERROR;
732 }
733 return SQLITE_OK;
734 }
735 closedir(pLvl->pDir);
736 sqlite3_free(pLvl->zDir);
737 pLvl->pDir = 0;
738 pLvl->zDir = 0;
739 pCur->iLvl--;
740 }
741
742 /* EOF */
743 sqlite3_free(pCur->zPath);
744 pCur->zPath = 0;
745 return SQLITE_OK;
746 }
747
748 /*
749 ** Return values of columns for the row at which the series_cursor
750 ** is currently pointing.
751 */
fsdirColumn(sqlite3_vtab_cursor * cur,sqlite3_context * ctx,int i)752 static int fsdirColumn(
753 sqlite3_vtab_cursor *cur, /* The cursor */
754 sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
755 int i /* Which column to return */
756 ){
757 fsdir_cursor *pCur = (fsdir_cursor*)cur;
758 switch( i ){
759 case FSDIR_COLUMN_NAME: {
760 sqlite3_result_text(ctx, &pCur->zPath[pCur->nBase], -1, SQLITE_TRANSIENT);
761 break;
762 }
763
764 case FSDIR_COLUMN_MODE:
765 sqlite3_result_int64(ctx, pCur->sStat.st_mode);
766 break;
767
768 case FSDIR_COLUMN_MTIME:
769 sqlite3_result_int64(ctx, pCur->sStat.st_mtime);
770 break;
771
772 case FSDIR_COLUMN_DATA: {
773 mode_t m = pCur->sStat.st_mode;
774 if( S_ISDIR(m) ){
775 sqlite3_result_null(ctx);
776 #if !defined(_WIN32) && !defined(WIN32)
777 }else if( S_ISLNK(m) ){
778 char aStatic[64];
779 char *aBuf = aStatic;
780 sqlite3_int64 nBuf = 64;
781 int n;
782
783 while( 1 ){
784 n = readlink(pCur->zPath, aBuf, nBuf);
785 if( n<nBuf ) break;
786 if( aBuf!=aStatic ) sqlite3_free(aBuf);
787 nBuf = nBuf*2;
788 aBuf = sqlite3_malloc64(nBuf);
789 if( aBuf==0 ){
790 sqlite3_result_error_nomem(ctx);
791 return SQLITE_NOMEM;
792 }
793 }
794
795 sqlite3_result_text(ctx, aBuf, n, SQLITE_TRANSIENT);
796 if( aBuf!=aStatic ) sqlite3_free(aBuf);
797 #endif
798 }else{
799 readFileContents(ctx, pCur->zPath);
800 }
801 }
802 case FSDIR_COLUMN_PATH:
803 default: {
804 /* The FSDIR_COLUMN_PATH and FSDIR_COLUMN_DIR are input parameters.
805 ** always return their values as NULL */
806 break;
807 }
808 }
809 return SQLITE_OK;
810 }
811
812 /*
813 ** Return the rowid for the current row. In this implementation, the
814 ** first row returned is assigned rowid value 1, and each subsequent
815 ** row a value 1 more than that of the previous.
816 */
fsdirRowid(sqlite3_vtab_cursor * cur,sqlite_int64 * pRowid)817 static int fsdirRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
818 fsdir_cursor *pCur = (fsdir_cursor*)cur;
819 *pRowid = pCur->iRowid;
820 return SQLITE_OK;
821 }
822
823 /*
824 ** Return TRUE if the cursor has been moved off of the last
825 ** row of output.
826 */
fsdirEof(sqlite3_vtab_cursor * cur)827 static int fsdirEof(sqlite3_vtab_cursor *cur){
828 fsdir_cursor *pCur = (fsdir_cursor*)cur;
829 return (pCur->zPath==0);
830 }
831
832 /*
833 ** xFilter callback.
834 **
835 ** idxNum==1 PATH parameter only
836 ** idxNum==2 Both PATH and DIR supplied
837 */
fsdirFilter(sqlite3_vtab_cursor * cur,int idxNum,const char * idxStr,int argc,sqlite3_value ** argv)838 static int fsdirFilter(
839 sqlite3_vtab_cursor *cur,
840 int idxNum, const char *idxStr,
841 int argc, sqlite3_value **argv
842 ){
843 const char *zDir = 0;
844 fsdir_cursor *pCur = (fsdir_cursor*)cur;
845 (void)idxStr;
846 fsdirResetCursor(pCur);
847
848 if( idxNum==0 ){
849 fsdirSetErrmsg(pCur, "table function fsdir requires an argument");
850 return SQLITE_ERROR;
851 }
852
853 assert( argc==idxNum && (argc==1 || argc==2) );
854 zDir = (const char*)sqlite3_value_text(argv[0]);
855 if( zDir==0 ){
856 fsdirSetErrmsg(pCur, "table function fsdir requires a non-NULL argument");
857 return SQLITE_ERROR;
858 }
859 if( argc==2 ){
860 pCur->zBase = (const char*)sqlite3_value_text(argv[1]);
861 }
862 if( pCur->zBase ){
863 pCur->nBase = (int)strlen(pCur->zBase)+1;
864 pCur->zPath = sqlite3_mprintf("%s/%s", pCur->zBase, zDir);
865 }else{
866 pCur->zPath = sqlite3_mprintf("%s", zDir);
867 }
868
869 if( pCur->zPath==0 ){
870 return SQLITE_NOMEM;
871 }
872 if( fileLinkStat(pCur->zPath, &pCur->sStat) ){
873 fsdirSetErrmsg(pCur, "cannot stat file: %s", pCur->zPath);
874 return SQLITE_ERROR;
875 }
876
877 return SQLITE_OK;
878 }
879
880 /*
881 ** SQLite will invoke this method one or more times while planning a query
882 ** that uses the generate_series virtual table. This routine needs to create
883 ** a query plan for each invocation and compute an estimated cost for that
884 ** plan.
885 **
886 ** In this implementation idxNum is used to represent the
887 ** query plan. idxStr is unused.
888 **
889 ** The query plan is represented by values of idxNum:
890 **
891 ** (1) The path value is supplied by argv[0]
892 ** (2) Path is in argv[0] and dir is in argv[1]
893 */
fsdirBestIndex(sqlite3_vtab * tab,sqlite3_index_info * pIdxInfo)894 static int fsdirBestIndex(
895 sqlite3_vtab *tab,
896 sqlite3_index_info *pIdxInfo
897 ){
898 int i; /* Loop over constraints */
899 int idxPath = -1; /* Index in pIdxInfo->aConstraint of PATH= */
900 int idxDir = -1; /* Index in pIdxInfo->aConstraint of DIR= */
901 int seenPath = 0; /* True if an unusable PATH= constraint is seen */
902 int seenDir = 0; /* True if an unusable DIR= constraint is seen */
903 const struct sqlite3_index_constraint *pConstraint;
904
905 (void)tab;
906 pConstraint = pIdxInfo->aConstraint;
907 for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
908 if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
909 switch( pConstraint->iColumn ){
910 case FSDIR_COLUMN_PATH: {
911 if( pConstraint->usable ){
912 idxPath = i;
913 seenPath = 0;
914 }else if( idxPath<0 ){
915 seenPath = 1;
916 }
917 break;
918 }
919 case FSDIR_COLUMN_DIR: {
920 if( pConstraint->usable ){
921 idxDir = i;
922 seenDir = 0;
923 }else if( idxDir<0 ){
924 seenDir = 1;
925 }
926 break;
927 }
928 }
929 }
930 if( seenPath || seenDir ){
931 /* If input parameters are unusable, disallow this plan */
932 return SQLITE_CONSTRAINT;
933 }
934
935 if( idxPath<0 ){
936 pIdxInfo->idxNum = 0;
937 /* The pIdxInfo->estimatedCost should have been initialized to a huge
938 ** number. Leave it unchanged. */
939 pIdxInfo->estimatedRows = 0x7fffffff;
940 }else{
941 pIdxInfo->aConstraintUsage[idxPath].omit = 1;
942 pIdxInfo->aConstraintUsage[idxPath].argvIndex = 1;
943 if( idxDir>=0 ){
944 pIdxInfo->aConstraintUsage[idxDir].omit = 1;
945 pIdxInfo->aConstraintUsage[idxDir].argvIndex = 2;
946 pIdxInfo->idxNum = 2;
947 pIdxInfo->estimatedCost = 10.0;
948 }else{
949 pIdxInfo->idxNum = 1;
950 pIdxInfo->estimatedCost = 100.0;
951 }
952 }
953
954 return SQLITE_OK;
955 }
956
957 /*
958 ** Register the "fsdir" virtual table.
959 */
fsdirRegister(sqlite3 * db)960 static int fsdirRegister(sqlite3 *db){
961 static sqlite3_module fsdirModule = {
962 0, /* iVersion */
963 0, /* xCreate */
964 fsdirConnect, /* xConnect */
965 fsdirBestIndex, /* xBestIndex */
966 fsdirDisconnect, /* xDisconnect */
967 0, /* xDestroy */
968 fsdirOpen, /* xOpen - open a cursor */
969 fsdirClose, /* xClose - close a cursor */
970 fsdirFilter, /* xFilter - configure scan constraints */
971 fsdirNext, /* xNext - advance a cursor */
972 fsdirEof, /* xEof - check for end of scan */
973 fsdirColumn, /* xColumn - read data */
974 fsdirRowid, /* xRowid - read data */
975 0, /* xUpdate */
976 0, /* xBegin */
977 0, /* xSync */
978 0, /* xCommit */
979 0, /* xRollback */
980 0, /* xFindMethod */
981 0, /* xRename */
982 0, /* xSavepoint */
983 0, /* xRelease */
984 0, /* xRollbackTo */
985 0, /* xShadowName */
986 };
987
988 int rc = sqlite3_create_module(db, "fsdir", &fsdirModule, 0);
989 return rc;
990 }
991 #else /* SQLITE_OMIT_VIRTUALTABLE */
992 # define fsdirRegister(x) SQLITE_OK
993 #endif
994
995 #ifdef _WIN32
996 __declspec(dllexport)
997 #endif
sqlite3_fileio_init(sqlite3 * db,char ** pzErrMsg,const sqlite3_api_routines * pApi)998 int sqlite3_fileio_init(
999 sqlite3 *db,
1000 char **pzErrMsg,
1001 const sqlite3_api_routines *pApi
1002 ){
1003 int rc = SQLITE_OK;
1004 SQLITE_EXTENSION_INIT2(pApi);
1005 (void)pzErrMsg; /* Unused parameter */
1006 rc = sqlite3_create_function(db, "readfile", 1,
1007 SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
1008 readfileFunc, 0, 0);
1009 if( rc==SQLITE_OK ){
1010 rc = sqlite3_create_function(db, "writefile", -1,
1011 SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
1012 writefileFunc, 0, 0);
1013 }
1014 if( rc==SQLITE_OK ){
1015 rc = sqlite3_create_function(db, "lsmode", 1, SQLITE_UTF8, 0,
1016 lsModeFunc, 0, 0);
1017 }
1018 if( rc==SQLITE_OK ){
1019 rc = fsdirRegister(db);
1020 }
1021 return rc;
1022 }
1023
1024 #if defined(FILEIO_WIN32_DLL) && (defined(_WIN32) || defined(WIN32))
1025 /* To allow a standalone DLL, make test_windirent.c use the same
1026 * redefined SQLite API calls as the above extension code does.
1027 * Just pull in this .c to accomplish this. As a beneficial side
1028 * effect, this extension becomes a single translation unit. */
1029 # include "test_windirent.c"
1030 #endif
1031