Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch testFsWin32 Excluding Merge-Ins
This is equivalent to a diff from ecad75d6 to f3ffb3ae
2015-12-01
| ||
17:48 | The test_fs.c test module now works on Windows. (check-in: e3d86284 user: drh tags: trunk) | |
16:21 | Simplification to the read and write primatives in the unix VFS. (check-in: 9eefa449 user: drh tags: trunk) | |
2015-11-30
| ||
23:29 | Add experimental support for the 'test_fs' test module on Win32. (Closed-Leaf check-in: f3ffb3ae user: mistachkin tags: testFsWin32) | |
22:52 | Add the SQLITE_PRINTF_PRECISION_LIMIT compile-time option. (check-in: ecad75d6 user: drh tags: trunk) | |
22:22 | Fix a problem in xFullPathname for the unix VFS. The problem was found by Kostya Serebryany using libFuzzer. (check-in: bb1e2c4d user: drh tags: trunk) | |
Changes to Makefile.in.
︙ | ︙ | |||
398 399 400 401 402 403 404 405 406 407 408 409 410 411 | $(TOP)/src/test_schema.c \ $(TOP)/src/test_server.c \ $(TOP)/src/test_superlock.c \ $(TOP)/src/test_syscall.c \ $(TOP)/src/test_tclvar.c \ $(TOP)/src/test_thread.c \ $(TOP)/src/test_vfs.c \ $(TOP)/src/test_wsd.c \ $(TOP)/ext/fts3/fts3_term.c \ $(TOP)/ext/fts3/fts3_test.c \ $(TOP)/ext/rbu/test_rbu.c # Statically linked extensions # | > | 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 | $(TOP)/src/test_schema.c \ $(TOP)/src/test_server.c \ $(TOP)/src/test_superlock.c \ $(TOP)/src/test_syscall.c \ $(TOP)/src/test_tclvar.c \ $(TOP)/src/test_thread.c \ $(TOP)/src/test_vfs.c \ $(TOP)/src/test_windirent.c \ $(TOP)/src/test_wsd.c \ $(TOP)/ext/fts3/fts3_term.c \ $(TOP)/ext/fts3/fts3_test.c \ $(TOP)/ext/rbu/test_rbu.c # Statically linked extensions # |
︙ | ︙ |
Changes to Makefile.msc.
︙ | ︙ | |||
1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 | $(TOP)\src\test_schema.c \ $(TOP)\src\test_server.c \ $(TOP)\src\test_superlock.c \ $(TOP)\src\test_syscall.c \ $(TOP)\src\test_tclvar.c \ $(TOP)\src\test_thread.c \ $(TOP)\src\test_vfs.c \ $(TOP)\src\test_wsd.c \ $(TOP)\ext\fts3\fts3_term.c \ $(TOP)\ext\fts3\fts3_test.c \ $(TOP)\ext\rbu\test_rbu.c # Statically linked extensions # | > | 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 | $(TOP)\src\test_schema.c \ $(TOP)\src\test_server.c \ $(TOP)\src\test_superlock.c \ $(TOP)\src\test_syscall.c \ $(TOP)\src\test_tclvar.c \ $(TOP)\src\test_thread.c \ $(TOP)\src\test_vfs.c \ $(TOP)\src\test_windirent.c \ $(TOP)\src\test_wsd.c \ $(TOP)\ext\fts3\fts3_term.c \ $(TOP)\ext\fts3\fts3_test.c \ $(TOP)\ext\rbu\test_rbu.c # Statically linked extensions # |
︙ | ︙ |
Changes to main.mk.
︙ | ︙ | |||
308 309 310 311 312 313 314 315 316 317 318 319 320 321 | $(TOP)/src/test_server.c \ $(TOP)/src/test_sqllog.c \ $(TOP)/src/test_superlock.c \ $(TOP)/src/test_syscall.c \ $(TOP)/src/test_tclvar.c \ $(TOP)/src/test_thread.c \ $(TOP)/src/test_vfs.c \ $(TOP)/src/test_wsd.c # Extensions to be statically loaded. # TESTSRC += \ $(TOP)/ext/misc/amatch.c \ $(TOP)/ext/misc/closure.c \ | > | 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 | $(TOP)/src/test_server.c \ $(TOP)/src/test_sqllog.c \ $(TOP)/src/test_superlock.c \ $(TOP)/src/test_syscall.c \ $(TOP)/src/test_tclvar.c \ $(TOP)/src/test_thread.c \ $(TOP)/src/test_vfs.c \ $(TOP)/src/test_windirent.c \ $(TOP)/src/test_wsd.c # Extensions to be statically loaded. # TESTSRC += \ $(TOP)/ext/misc/amatch.c \ $(TOP)/ext/misc/closure.c \ |
︙ | ︙ |
Changes to src/test_fs.c.
︙ | ︙ | |||
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #if SQLITE_OS_UNIX # include <unistd.h> # include <dirent.h> #endif #if SQLITE_OS_WIN # include <io.h> #endif #ifndef SQLITE_OMIT_VIRTUALTABLE typedef struct fs_vtab fs_vtab; typedef struct fs_cursor fs_cursor; | > > > > > > > | 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #if SQLITE_OS_UNIX # include <unistd.h> # include <dirent.h> # ifndef DIRENT # define DIRENT dirent # endif #endif #if SQLITE_OS_WIN # include <io.h> # include "test_windirent.h" # ifndef S_ISREG # define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) # endif #endif #ifndef SQLITE_OMIT_VIRTUALTABLE typedef struct fs_vtab fs_vtab; typedef struct fs_cursor fs_cursor; |
︙ | ︙ | |||
112 113 114 115 116 117 118 | }; struct FsdirCsr { sqlite3_vtab_cursor base; char *zDir; /* Buffer containing directory scanned */ DIR *pDir; /* Open directory */ sqlite3_int64 iRowid; | | | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | }; struct FsdirCsr { sqlite3_vtab_cursor base; char *zDir; /* Buffer containing directory scanned */ DIR *pDir; /* Open directory */ sqlite3_int64 iRowid; struct DIRENT entry; /* Current entry */ }; /* ** This function is the implementation of both the xConnect and xCreate ** methods of the fsdir virtual table. ** ** The argv[] array contains the following: |
︙ | ︙ | |||
216 217 218 219 220 221 222 | /* ** Skip the cursor to the next entry. */ static int fsdirNext(sqlite3_vtab_cursor *cur){ FsdirCsr *pCsr = (FsdirCsr*)cur; if( pCsr->pDir ){ | | | 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 | /* ** Skip the cursor to the next entry. */ static int fsdirNext(sqlite3_vtab_cursor *cur){ FsdirCsr *pCsr = (FsdirCsr*)cur; if( pCsr->pDir ){ struct DIRENT *pRes = 0; readdir_r(pCsr->pDir, &pCsr->entry, &pRes); if( pRes==0 ){ closedir(pCsr->pDir); pCsr->pDir = 0; } pCsr->iRowid++; } |
︙ | ︙ | |||
457 458 459 460 461 462 463 | int argc, sqlite3_value **argv ){ FstreeCsr *pCsr = (FstreeCsr*)pVtabCursor; FstreeVtab *pTab = (FstreeVtab*)(pCsr->base.pVtab); int rc; const char *zSql = "WITH r(d) AS (" | | | > > > > | | | > > > > > > > > > > > > > > > | | > > > > > > > | 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 | int argc, sqlite3_value **argv ){ FstreeCsr *pCsr = (FstreeCsr*)pVtabCursor; FstreeVtab *pTab = (FstreeVtab*)(pCsr->base.pVtab); int rc; const char *zSql = "WITH r(d) AS (" " SELECT CASE WHEN dir=?2 THEN ?3 ELSE dir END || '/' || name " " FROM fsdir WHERE dir=?1 AND name NOT LIKE '.%'" " UNION ALL" " SELECT dir || '/' || name FROM r, fsdir WHERE dir=d AND name NOT LIKE '.%'" ") SELECT d FROM r;"; char *zRoot; int nRoot; char *zPrefix; int nPrefix; const char *zDir; int nDir; char aWild[2] = { '\0', '\0' }; #if SQLITE_OS_WIN zRoot = sqlite3_mprintf("%s%c", getenv("SystemDrive"), '/'); nRoot = strlen(zRoot); zPrefix = sqlite3_mprintf("%s", getenv("SystemDrive")); nPrefix = strlen(zPrefix); #else zRoot = "/"; nRoot = 1; zPrefix = ""; nPrefix = 0; #endif zDir = zRoot; nDir = nRoot; fstreeCloseFd(pCsr); sqlite3_finalize(pCsr->pStmt); pCsr->pStmt = 0; rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0); if( rc!=SQLITE_OK ) return rc; if( idxNum ){ const char *zQuery = (const char*)sqlite3_value_text(argv[0]); switch( idxNum ){ case SQLITE_INDEX_CONSTRAINT_GLOB: aWild[0] = '*'; aWild[1] = '?'; break; case SQLITE_INDEX_CONSTRAINT_LIKE: aWild[0] = '_'; aWild[1] = '%'; break; } if( sqlite3_strnicmp(zQuery, zPrefix, nPrefix)==0 ){ int i; for(i=nPrefix; zQuery[i]; i++){ if( zQuery[i]==aWild[0] || zQuery[i]==aWild[1] ) break; if( zQuery[i]=='/' ) nDir = i; } zDir = zQuery; } } sqlite3_bind_text(pCsr->pStmt, 1, zDir, nDir, SQLITE_TRANSIENT); sqlite3_bind_text(pCsr->pStmt, 2, zRoot, nRoot, SQLITE_TRANSIENT); sqlite3_bind_text(pCsr->pStmt, 3, zPrefix, nPrefix, SQLITE_TRANSIENT); #if SQLITE_OS_WIN sqlite3_free(zPrefix); sqlite3_free(zRoot); #endif return fstreeNext(pVtabCursor); } /* ** xEof method implementation. */ |
︙ | ︙ |
Added src/test_windirent.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | /* ** 2015 November 30 ** ** 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 file contains code to implement most of the opendir() family of ** POSIX functions on Win32 using the MSVCRT. */ #if defined(_WIN32) && defined(_MSC_VER) #include "test_windirent.h" /* ** Implementation of the POSIX opendir() function using the MSVCRT. */ LPDIR opendir( const char *dirname ){ struct _finddata_t data; LPDIR dirp = (LPDIR)sqlite3_malloc(sizeof(DIR)); SIZE_T namesize = sizeof(data.name) / sizeof(data.name[0]); if( dirp==NULL ) return NULL; memset(dirp, 0, sizeof(DIR)); /* TODO: Remove this if Unix-style root paths are not used. */ if( sqlite3_stricmp(dirname, "/")==0 ){ dirname = getenv("SystemDrive"); } _snprintf(data.name, namesize, "%s\\*", dirname); dirp->d_handle = _findfirst(data.name, &data); if( dirp->d_handle==BAD_INTPTR_T ){ closedir(dirp); return NULL; } /* TODO: Remove this block to allow hidden and system files. */ if( data.attrib&_A_HIDDEN || data.attrib&_A_SYSTEM ){ if( _findnext(dirp->d_handle, &data)==-1 ){ closedir(dirp); return NULL; } } dirp->d_first.d_attributes = data.attrib; strncpy(dirp->d_first.d_name, data.name, NAME_MAX); dirp->d_first.d_name[NAME_MAX] = '\0'; return dirp; } /* ** Implementation of the POSIX readdir() function using the MSVCRT. */ LPDIRENT readdir( LPDIR dirp ){ struct _finddata_t data; if( dirp==NULL ) return NULL; if( dirp->d_first.d_ino==0 ){ dirp->d_first.d_ino++; dirp->d_next.d_ino++; return &dirp->d_first; } next: if( _findnext(dirp->d_handle, &data)==-1 ) return NULL; /* TODO: Remove this block to allow hidden and system files. */ if( data.attrib&_A_HIDDEN ) goto next; if( data.attrib&_A_SYSTEM ) goto next; dirp->d_next.d_ino++; dirp->d_next.d_attributes = data.attrib; strncpy(dirp->d_next.d_name, data.name, NAME_MAX); dirp->d_next.d_name[NAME_MAX] = '\0'; return &dirp->d_next; } /* ** Implementation of the POSIX readdir_r() function using the MSVCRT. */ INT readdir_r( LPDIR dirp, LPDIRENT entry, LPDIRENT *result ){ struct _finddata_t data; if( dirp==NULL ) return EBADF; if( dirp->d_first.d_ino==0 ){ dirp->d_first.d_ino++; dirp->d_next.d_ino++; entry->d_ino = dirp->d_first.d_ino; entry->d_attributes = dirp->d_first.d_attributes; strncpy(entry->d_name, dirp->d_first.d_name, NAME_MAX); entry->d_name[NAME_MAX] = '\0'; *result = entry; return 0; } next: if( _findnext(dirp->d_handle, &data)==-1 ){ *result = NULL; return ENOENT; } /* TODO: Remove this block to allow hidden and system files. */ if( data.attrib&_A_HIDDEN ) goto next; if( data.attrib&_A_SYSTEM ) goto next; entry->d_ino = (ino_t)-1; /* not available */ entry->d_attributes = data.attrib; strncpy(entry->d_name, data.name, NAME_MAX); entry->d_name[NAME_MAX] = '\0'; *result = entry; return 0; } /* ** Implementation of the POSIX closedir() function using the MSVCRT. */ INT closedir( LPDIR dirp ){ INT result = 0; if( dirp==NULL ) return EINVAL; if( dirp->d_handle!=NULL_INTPTR_T && dirp->d_handle!=BAD_INTPTR_T ){ result = _findclose(dirp->d_handle); } sqlite3_free(dirp); return result; } #endif /* defined(WIN32) && defined(_MSC_VER) */ |
Added src/test_windirent.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | /* ** 2015 November 30 ** ** 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 file contains declarations for most of the opendir() family of ** POSIX functions on Win32 using the MSVCRT. */ #if defined(_WIN32) && defined(_MSC_VER) /* ** We need several data types from the Windows SDK header. */ #define WIN32_LEAN_AND_MEAN #include "windows.h" /* ** We need several support functions from the SQLite core. */ #include "sqlite3.h" /* ** We need several things from the ANSI and MSVCRT headers. */ #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <io.h> #include <limits.h> /* ** We may need to provide the "ino_t" type. */ #ifndef INO_T_DEFINED #define INO_T_DEFINED typedef unsigned short ino_t; #endif /* ** We need to define "NAME_MAX" if it was not present in "limits.h". */ #ifndef NAME_MAX # ifdef FILENAME_MAX # define NAME_MAX (FILENAME_MAX) # else # define NAME_MAX (260) # endif #endif /* ** We need to define "NULL_INTPTR_T" and "BAD_INTPTR_T". */ #ifndef NULL_INTPTR_T # define NULL_INTPTR_T ((intptr_t)(0)) #endif #ifndef BAD_INTPTR_T # define BAD_INTPTR_T ((intptr_t)(-1)) #endif /* ** We need to provide the necessary structures and related types. */ typedef struct DIRENT DIRENT; typedef struct DIR DIR; typedef DIRENT *LPDIRENT; typedef DIR *LPDIR; struct DIRENT { ino_t d_ino; /* Sequence number, do not use. */ unsigned d_attributes; /* Win32 file attributes. */ char d_name[NAME_MAX + 1]; /* Name within the directory. */ }; struct DIR { intptr_t d_handle; /* Value returned by "_findfirst". */ DIRENT d_first; /* DIRENT constructed based on "_findfirst". */ DIRENT d_next; /* DIRENT constructed based on "_findnext". */ }; /* ** Finally, we can provide the function prototypes for the opendir(), ** readdir(), readdir_r(), and closedir() POSIX functions. */ extern LPDIR opendir(const char *dirname); extern LPDIRENT readdir(LPDIR dirp); extern INT readdir_r(LPDIR dirp, LPDIRENT entry, LPDIRENT *result); extern INT closedir(LPDIR dirp); #endif /* defined(WIN32) && defined(_MSC_VER) */ |
Changes to test/vtabH.test.
︙ | ︙ | |||
104 105 106 107 108 109 110 | set ::gfunc } $cnt } } #------------------------------------------------------------------------- # | | > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > | > | | 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | set ::gfunc } $cnt } } #------------------------------------------------------------------------- # if {1} { reset_db register_fs_module db do_execsql_test 3.0 { SELECT name FROM fsdir WHERE dir = '.' AND name = 'test.db'; SELECT name FROM fsdir WHERE dir = '.' AND name = '.' } {test.db .} proc list_root_files {} { if {$::tcl_platform(platform) eq "windows"} { set res [list] foreach name [glob -directory $::env(SystemDrive)/ -- *] { if {[string index [file tail $name] 0] eq "."} continue lappend res $name } return $res } else { return [exec ls -U /] } } proc list_files { pattern } { if {$::tcl_platform(platform) eq "windows"} { set res [list] foreach name [glob -nocomplain $pattern] { if {[string index [file tail $name] 0] eq "."} continue lappend res $name } return $res } else { return [glob -nocomplain $pattern] } } # Read the first 5 entries from the root directory. # set res [list] foreach p [lrange [list_root_files] 0 4] { if {$::tcl_platform(platform) eq "windows"} { lappend res $p } else { lappend res "/$p" } } do_execsql_test 3.1 { SELECT path FROM fstree LIMIT 5; } $res # Read all entries in the current directory. # proc contents {pattern} { set res [list] foreach f [list_files $pattern] { lappend res $f if {[file isdir $f]} { set res [concat $res [contents "$f/*"]] } } set res } |
︙ | ︙ |