/ Check-in [e3d86284]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:The test_fs.c test module now works on Windows.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: e3d8628456848a70035bbdeca6dc6c21f688b9a5
User & Date: drh 2015-12-01 17:48:45
Context
2015-12-01
21:23
Add the SQLITE_LIKE_DOESNT_MATCH_BLOBS compile-time option. check-in: 9e1d6d4c user: drh tags: trunk
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
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to Makefile.in.

   398    398     $(TOP)/src/test_schema.c \
   399    399     $(TOP)/src/test_server.c \
   400    400     $(TOP)/src/test_superlock.c \
   401    401     $(TOP)/src/test_syscall.c \
   402    402     $(TOP)/src/test_tclvar.c \
   403    403     $(TOP)/src/test_thread.c \
   404    404     $(TOP)/src/test_vfs.c \
          405  +  $(TOP)/src/test_windirent.c \
   405    406     $(TOP)/src/test_wsd.c       \
   406    407     $(TOP)/ext/fts3/fts3_term.c \
   407    408     $(TOP)/ext/fts3/fts3_test.c \
   408    409     $(TOP)/ext/rbu/test_rbu.c 
   409    410   
   410    411   # Statically linked extensions
   411    412   #

Changes to Makefile.msc.

  1067   1067     $(TOP)\src\test_schema.c \
  1068   1068     $(TOP)\src\test_server.c \
  1069   1069     $(TOP)\src\test_superlock.c \
  1070   1070     $(TOP)\src\test_syscall.c \
  1071   1071     $(TOP)\src\test_tclvar.c \
  1072   1072     $(TOP)\src\test_thread.c \
  1073   1073     $(TOP)\src\test_vfs.c \
         1074  +  $(TOP)\src\test_windirent.c \
  1074   1075     $(TOP)\src\test_wsd.c \
  1075   1076     $(TOP)\ext\fts3\fts3_term.c \
  1076   1077     $(TOP)\ext\fts3\fts3_test.c \
  1077   1078     $(TOP)\ext\rbu\test_rbu.c
  1078   1079   
  1079   1080   # Statically linked extensions
  1080   1081   #

Changes to main.mk.

   308    308     $(TOP)/src/test_server.c \
   309    309     $(TOP)/src/test_sqllog.c \
   310    310     $(TOP)/src/test_superlock.c \
   311    311     $(TOP)/src/test_syscall.c \
   312    312     $(TOP)/src/test_tclvar.c \
   313    313     $(TOP)/src/test_thread.c \
   314    314     $(TOP)/src/test_vfs.c \
          315  +  $(TOP)/src/test_windirent.c \
   315    316     $(TOP)/src/test_wsd.c
   316    317   
   317    318   # Extensions to be statically loaded.
   318    319   #
   319    320   TESTSRC += \
   320    321     $(TOP)/ext/misc/amatch.c \
   321    322     $(TOP)/ext/misc/closure.c \

Changes to src/test_fs.c.

    69     69   #include <sys/types.h>
    70     70   #include <sys/stat.h>
    71     71   #include <fcntl.h>
    72     72   
    73     73   #if SQLITE_OS_UNIX
    74     74   # include <unistd.h>
    75     75   # include <dirent.h>
           76  +# ifndef DIRENT
           77  +#  define DIRENT dirent
           78  +# endif
    76     79   #endif
    77     80   #if SQLITE_OS_WIN
    78     81   # include <io.h>
           82  +# include "test_windirent.h"
           83  +# ifndef S_ISREG
           84  +#  define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
           85  +# endif
    79     86   #endif
    80     87   
    81     88   #ifndef SQLITE_OMIT_VIRTUALTABLE
    82     89   
    83     90   typedef struct fs_vtab fs_vtab;
    84     91   typedef struct fs_cursor fs_cursor;
    85     92   
................................................................................
   112    119   };
   113    120   
   114    121   struct FsdirCsr {
   115    122     sqlite3_vtab_cursor base;
   116    123     char *zDir;                     /* Buffer containing directory scanned */
   117    124     DIR *pDir;                      /* Open directory */
   118    125     sqlite3_int64 iRowid;
   119         -  struct dirent entry;            /* Current entry */
          126  +  struct DIRENT entry;            /* Current entry */
   120    127   };
   121    128   
   122    129   /*
   123    130   ** This function is the implementation of both the xConnect and xCreate
   124    131   ** methods of the fsdir virtual table.
   125    132   **
   126    133   ** The argv[] array contains the following:
................................................................................
   216    223   /*
   217    224   ** Skip the cursor to the next entry.
   218    225   */
   219    226   static int fsdirNext(sqlite3_vtab_cursor *cur){
   220    227     FsdirCsr *pCsr = (FsdirCsr*)cur;
   221    228   
   222    229     if( pCsr->pDir ){
   223         -    struct dirent *pRes = 0;
          230  +    struct DIRENT *pRes = 0;
   224    231       readdir_r(pCsr->pDir, &pCsr->entry, &pRes);
   225    232       if( pRes==0 ){
   226    233         closedir(pCsr->pDir);
   227    234         pCsr->pDir = 0;
   228    235       }
   229    236       pCsr->iRowid++;
   230    237     }
................................................................................
   457    464     int argc, sqlite3_value **argv
   458    465   ){
   459    466     FstreeCsr *pCsr = (FstreeCsr*)pVtabCursor;
   460    467     FstreeVtab *pTab = (FstreeVtab*)(pCsr->base.pVtab);
   461    468     int rc;
   462    469     const char *zSql = 
   463    470   "WITH r(d) AS ("
   464         -"  SELECT CASE WHEN dir='/' THEN '' ELSE dir END || '/' || name "
   465         -"    FROM fsdir WHERE dir=? AND name NOT LIKE '.%'"
          471  +"  SELECT CASE WHEN dir=?2 THEN ?3 ELSE dir END || '/' || name "
          472  +"    FROM fsdir WHERE dir=?1 AND name NOT LIKE '.%'"
   466    473   "  UNION ALL"
   467    474   "  SELECT dir || '/' || name FROM r, fsdir WHERE dir=d AND name NOT LIKE '.%'"
   468    475   ") SELECT d FROM r;";
   469    476   
   470         -  const char *zDir = "/";
   471         -  int nDir = 1;
   472         -  char aWild[2] = {'\0', '\0' };
          477  +  char *zRoot;
          478  +  int nRoot;
          479  +  char *zPrefix;
          480  +  int nPrefix;
          481  +  const char *zDir;
          482  +  int nDir;
          483  +  char aWild[2] = { '\0', '\0' };
          484  +
          485  +#if SQLITE_OS_WIN
          486  +  zRoot = sqlite3_mprintf("%s%c", getenv("SystemDrive"), '/');
          487  +  nRoot = strlen(zRoot);
          488  +  zPrefix = sqlite3_mprintf("%s", getenv("SystemDrive"));
          489  +  nPrefix = strlen(zPrefix);
          490  +#else
          491  +  zRoot = "/";
          492  +  nRoot = 1;
          493  +  zPrefix = "";
          494  +  nPrefix = 0;
          495  +#endif
          496  +
          497  +  zDir = zRoot;
          498  +  nDir = nRoot;
   473    499   
   474    500     fstreeCloseFd(pCsr);
   475    501     sqlite3_finalize(pCsr->pStmt);
   476    502     pCsr->pStmt = 0;
   477    503     rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
   478    504     if( rc!=SQLITE_OK ) return rc;
   479    505   
................................................................................
   486    512           break;
   487    513         case SQLITE_INDEX_CONSTRAINT_LIKE:
   488    514           aWild[0] = '_';
   489    515           aWild[1] = '%';
   490    516           break;
   491    517       }
   492    518   
   493         -    if( zQuery[0]=='/' ){
          519  +    if( sqlite3_strnicmp(zQuery, zPrefix, nPrefix)==0 ){
   494    520         int i;
   495         -      for(i=1; zQuery[i]; i++){
          521  +      for(i=nPrefix; zQuery[i]; i++){
   496    522           if( zQuery[i]==aWild[0] || zQuery[i]==aWild[1] ) break;
   497    523           if( zQuery[i]=='/' ) nDir = i;
   498    524         }
   499    525         zDir = zQuery;
   500    526       }
   501    527     }
   502    528   
   503    529     sqlite3_bind_text(pCsr->pStmt, 1, zDir, nDir, SQLITE_TRANSIENT);
          530  +  sqlite3_bind_text(pCsr->pStmt, 2, zRoot, nRoot, SQLITE_TRANSIENT);
          531  +  sqlite3_bind_text(pCsr->pStmt, 3, zPrefix, nPrefix, SQLITE_TRANSIENT);
          532  +
          533  +#if SQLITE_OS_WIN
          534  +  sqlite3_free(zPrefix);
          535  +  sqlite3_free(zRoot);
          536  +#endif
   504    537   
   505    538     return fstreeNext(pVtabCursor); 
   506    539   }
   507    540   
   508    541   /*
   509    542   ** xEof method implementation.
   510    543   */

Added src/test_windirent.c.

            1  +/*
            2  +** 2015 November 30
            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  +** This file contains code to implement most of the opendir() family of
           13  +** POSIX functions on Win32 using the MSVCRT.
           14  +*/
           15  +
           16  +#if defined(_WIN32) && defined(_MSC_VER)
           17  +
           18  +#include "test_windirent.h"
           19  +
           20  +/*
           21  +** Implementation of the POSIX opendir() function using the MSVCRT.
           22  +*/
           23  +LPDIR opendir(
           24  +  const char *dirname
           25  +){
           26  +  struct _finddata_t data;
           27  +  LPDIR dirp = (LPDIR)sqlite3_malloc(sizeof(DIR));
           28  +  SIZE_T namesize = sizeof(data.name) / sizeof(data.name[0]);
           29  +
           30  +  if( dirp==NULL ) return NULL;
           31  +  memset(dirp, 0, sizeof(DIR));
           32  +
           33  +  /* TODO: Remove this if Unix-style root paths are not used. */
           34  +  if( sqlite3_stricmp(dirname, "/")==0 ){
           35  +    dirname = getenv("SystemDrive");
           36  +  }
           37  +
           38  +  _snprintf(data.name, namesize, "%s\\*", dirname);
           39  +  dirp->d_handle = _findfirst(data.name, &data);
           40  +
           41  +  if( dirp->d_handle==BAD_INTPTR_T ){
           42  +    closedir(dirp);
           43  +    return NULL;
           44  +  }
           45  +
           46  +  /* TODO: Remove this block to allow hidden and system files. */
           47  +  if( data.attrib&_A_HIDDEN || data.attrib&_A_SYSTEM ){
           48  +    if( _findnext(dirp->d_handle, &data)==-1 ){
           49  +      closedir(dirp);
           50  +      return NULL;
           51  +    }
           52  +  }
           53  +
           54  +  dirp->d_first.d_attributes = data.attrib;
           55  +  strncpy(dirp->d_first.d_name, data.name, NAME_MAX);
           56  +  dirp->d_first.d_name[NAME_MAX] = '\0';
           57  +
           58  +  return dirp;
           59  +}
           60  +
           61  +/*
           62  +** Implementation of the POSIX readdir() function using the MSVCRT.
           63  +*/
           64  +LPDIRENT readdir(
           65  +  LPDIR dirp
           66  +){
           67  +  struct _finddata_t data;
           68  +
           69  +  if( dirp==NULL ) return NULL;
           70  +
           71  +  if( dirp->d_first.d_ino==0 ){
           72  +    dirp->d_first.d_ino++;
           73  +    dirp->d_next.d_ino++;
           74  +
           75  +    return &dirp->d_first;
           76  +  }
           77  +
           78  +next:
           79  +
           80  +  if( _findnext(dirp->d_handle, &data)==-1 ) return NULL;
           81  +
           82  +  /* TODO: Remove this block to allow hidden and system files. */
           83  +  if( data.attrib&_A_HIDDEN ) goto next;
           84  +  if( data.attrib&_A_SYSTEM ) goto next;
           85  +
           86  +  dirp->d_next.d_ino++;
           87  +  dirp->d_next.d_attributes = data.attrib;
           88  +  strncpy(dirp->d_next.d_name, data.name, NAME_MAX);
           89  +  dirp->d_next.d_name[NAME_MAX] = '\0';
           90  +
           91  +  return &dirp->d_next;
           92  +}
           93  +
           94  +/*
           95  +** Implementation of the POSIX readdir_r() function using the MSVCRT.
           96  +*/
           97  +INT readdir_r(
           98  +  LPDIR dirp,
           99  +  LPDIRENT entry,
          100  +  LPDIRENT *result
          101  +){
          102  +  struct _finddata_t data;
          103  +
          104  +  if( dirp==NULL ) return EBADF;
          105  +
          106  +  if( dirp->d_first.d_ino==0 ){
          107  +    dirp->d_first.d_ino++;
          108  +    dirp->d_next.d_ino++;
          109  +
          110  +    entry->d_ino = dirp->d_first.d_ino;
          111  +    entry->d_attributes = dirp->d_first.d_attributes;
          112  +    strncpy(entry->d_name, dirp->d_first.d_name, NAME_MAX);
          113  +    entry->d_name[NAME_MAX] = '\0';
          114  +
          115  +    *result = entry;
          116  +    return 0;
          117  +  }
          118  +
          119  +next:
          120  +
          121  +  if( _findnext(dirp->d_handle, &data)==-1 ){
          122  +    *result = NULL;
          123  +    return ENOENT;
          124  +  }
          125  +
          126  +  /* TODO: Remove this block to allow hidden and system files. */
          127  +  if( data.attrib&_A_HIDDEN ) goto next;
          128  +  if( data.attrib&_A_SYSTEM ) goto next;
          129  +
          130  +  entry->d_ino = (ino_t)-1; /* not available */
          131  +  entry->d_attributes = data.attrib;
          132  +  strncpy(entry->d_name, data.name, NAME_MAX);
          133  +  entry->d_name[NAME_MAX] = '\0';
          134  +
          135  +  *result = entry;
          136  +  return 0;
          137  +}
          138  +
          139  +/*
          140  +** Implementation of the POSIX closedir() function using the MSVCRT.
          141  +*/
          142  +INT closedir(
          143  +  LPDIR dirp
          144  +){
          145  +  INT result = 0;
          146  +
          147  +  if( dirp==NULL ) return EINVAL;
          148  +
          149  +  if( dirp->d_handle!=NULL_INTPTR_T && dirp->d_handle!=BAD_INTPTR_T ){
          150  +    result = _findclose(dirp->d_handle);
          151  +  }
          152  +
          153  +  sqlite3_free(dirp);
          154  +  return result;
          155  +}
          156  +
          157  +#endif /* defined(WIN32) && defined(_MSC_VER) */

Added src/test_windirent.h.

            1  +/*
            2  +** 2015 November 30
            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  +** This file contains declarations for most of the opendir() family of
           13  +** POSIX functions on Win32 using the MSVCRT.
           14  +*/
           15  +
           16  +#if defined(_WIN32) && defined(_MSC_VER)
           17  +
           18  +/*
           19  +** We need several data types from the Windows SDK header.
           20  +*/
           21  +
           22  +#define WIN32_LEAN_AND_MEAN
           23  +#include "windows.h"
           24  +
           25  +/*
           26  +** We need several support functions from the SQLite core.
           27  +*/
           28  +
           29  +#include "sqlite3.h"
           30  +
           31  +/*
           32  +** We need several things from the ANSI and MSVCRT headers.
           33  +*/
           34  +
           35  +#include <stdio.h>
           36  +#include <stdlib.h>
           37  +#include <errno.h>
           38  +#include <io.h>
           39  +#include <limits.h>
           40  +
           41  +/*
           42  +** We may need to provide the "ino_t" type.
           43  +*/
           44  +
           45  +#ifndef INO_T_DEFINED
           46  +  #define INO_T_DEFINED
           47  +  typedef unsigned short ino_t;
           48  +#endif
           49  +
           50  +/*
           51  +** We need to define "NAME_MAX" if it was not present in "limits.h".
           52  +*/
           53  +
           54  +#ifndef NAME_MAX
           55  +#  ifdef FILENAME_MAX
           56  +#    define NAME_MAX (FILENAME_MAX)
           57  +#  else
           58  +#    define NAME_MAX (260)
           59  +#  endif
           60  +#endif
           61  +
           62  +/*
           63  +** We need to define "NULL_INTPTR_T" and "BAD_INTPTR_T".
           64  +*/
           65  +
           66  +#ifndef NULL_INTPTR_T
           67  +#  define NULL_INTPTR_T ((intptr_t)(0))
           68  +#endif
           69  +
           70  +#ifndef BAD_INTPTR_T
           71  +#  define BAD_INTPTR_T ((intptr_t)(-1))
           72  +#endif
           73  +
           74  +/*
           75  +** We need to provide the necessary structures and related types.
           76  +*/
           77  +
           78  +typedef struct DIRENT DIRENT;
           79  +typedef struct DIR DIR;
           80  +typedef DIRENT *LPDIRENT;
           81  +typedef DIR *LPDIR;
           82  +
           83  +struct DIRENT {
           84  +  ino_t d_ino;               /* Sequence number, do not use. */
           85  +  unsigned d_attributes;     /* Win32 file attributes. */
           86  +  char d_name[NAME_MAX + 1]; /* Name within the directory. */
           87  +};
           88  +
           89  +struct DIR {
           90  +  intptr_t d_handle; /* Value returned by "_findfirst". */
           91  +  DIRENT d_first;    /* DIRENT constructed based on "_findfirst". */
           92  +  DIRENT d_next;     /* DIRENT constructed based on "_findnext". */
           93  +};
           94  +
           95  +/*
           96  +** Finally, we can provide the function prototypes for the opendir(),
           97  +** readdir(), readdir_r(), and closedir() POSIX functions.
           98  +*/
           99  +
          100  +extern LPDIR opendir(const char *dirname);
          101  +extern LPDIRENT readdir(LPDIR dirp);
          102  +extern INT readdir_r(LPDIR dirp, LPDIRENT entry, LPDIRENT *result);
          103  +extern INT closedir(LPDIR dirp);
          104  +
          105  +#endif /* defined(WIN32) && defined(_MSC_VER) */

Changes to test/vtabH.test.

   104    104         set ::gfunc
   105    105       } $cnt
   106    106     }
   107    107   }
   108    108   
   109    109   #-------------------------------------------------------------------------
   110    110   #
   111         -if {$::tcl_platform(platform)=="unix"} {
          111  +if {1} {
   112    112     reset_db
   113    113     register_fs_module db
   114    114     do_execsql_test 3.0 {
   115    115       SELECT name FROM fsdir WHERE dir = '.' AND name = 'test.db';
   116    116       SELECT name FROM fsdir WHERE dir = '.' AND name = '.'
   117    117     } {test.db .}
   118    118     
          119  +  proc list_root_files {} {
          120  +    if {$::tcl_platform(platform) eq "windows"} {
          121  +      set res [list]
          122  +      foreach name [glob -directory $::env(SystemDrive)/ -- *] {
          123  +        if {[string index [file tail $name] 0] eq "."} continue
          124  +        lappend res $name
          125  +      }
          126  +      return $res
          127  +    } else {
          128  +      return [exec ls -U /]
          129  +    }
          130  +  }
          131  +
          132  +  proc list_files { pattern } {
          133  +    if {$::tcl_platform(platform) eq "windows"} {
          134  +      set res [list]
          135  +      foreach name [glob -nocomplain $pattern] {
          136  +        if {[string index [file tail $name] 0] eq "."} continue
          137  +        lappend res $name
          138  +      }
          139  +      return $res
          140  +    } else {
          141  +      return [glob -nocomplain $pattern]
          142  +    }
          143  +  }
          144  +
   119    145     # Read the first 5 entries from the root directory.
   120    146     #
   121    147     set res [list]
   122         -  foreach p [lrange [exec ls -U /] 0 4] {
   123         -    lappend res "/$p"
          148  +  foreach p [lrange [list_root_files] 0 4] {
          149  +    if {$::tcl_platform(platform) eq "windows"} {
          150  +      lappend res $p
          151  +    } else {
          152  +      lappend res "/$p"
          153  +    }
   124    154     }
   125    155     do_execsql_test 3.1 {
   126    156       SELECT path FROM fstree LIMIT 5;
   127    157     } $res
   128    158     
   129    159     # Read all entries in the current directory.
   130    160     #
   131    161     proc contents {pattern} {
   132    162       set res [list]
   133         -    foreach f [glob -nocomplain $pattern] {
          163  +    foreach f [list_files $pattern] {
   134    164         lappend res $f
   135    165         if {[file isdir $f]} {
   136    166           set res [concat $res [contents "$f/*"]]
   137    167         }
   138    168       }
   139    169       set res
   140    170     }