/ Check-in [bc6cce81]
Login

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

Overview
Comment:Fix a problem in the unix VFS implementation of xNextSystemCall(). Also some typos that prevent compilation when HAVE_POSIX_FALLOCATE is defined.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: bc6cce81565b17f886478bd51500bba2ed11ec1d
User & Date: dan 2011-03-29 10:04:23
Context
2011-03-29
15:40
Fix a problem whereby following an IO error in CommitPhaseTwo() of a multi-file transaction the b-tree layer could be left in TRANS_WRITE state, causing problems later on. check-in: dbe569a0 user: dan tags: trunk
15:00
If the keyword "unordered" appears at the end of the SQLITE_STAT1.STAT column for an index, then use that index for equality lookups only, never for range queries or sorting. Closed-Leaf check-in: 3b964155 user: drh tags: unordered-index-hack
10:04
Fix a problem in the unix VFS implementation of xNextSystemCall(). Also some typos that prevent compilation when HAVE_POSIX_FALLOCATE is defined. check-in: bc6cce81 user: dan tags: trunk
01:47
Fix the documentation for the sqlite3_column_*_name() functions to describe that the information can be invalidated when a prepared statement is reprepared by the first invocation of an sqlite3_step() for a particular execution cycle. check-in: 7270f80a user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

install-sh became a regular file.

Changes to src/os_unix.c.

367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
...
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457

458
459
460
461
462
463
464
465
....
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
#define osFchmod    ((int(*)(int,mode_t))aSyscall[14].pCurrent)

#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
  { "fallocate",    (sqlite3_syscall_ptr)posix_fallocate,  0 },
#else
  { "fallocate",    (sqlite3_syscall_ptr)0,                0 },
#endif
#define osFallocate ((int(*)(int,off_t,off_t)aSyscall[15].pCurrent)

}; /* End of the overrideable system calls */

/*
** This is the xSetSystemCall() method of sqlite3_vfs for all of the
** "unix" VFSes.  Return SQLITE_OK opon successfully updating the
** system call pointer, or SQLITE_NOTFOUND if there is no configurable
................................................................................
/*
** Return the name of the first system call after zName.  If zName==NULL
** then return the name of the first system call.  Return NULL if zName
** is the last system call or if zName is not the name of a valid
** system call.
*/
static const char *unixNextSystemCall(sqlite3_vfs *p, const char *zName){
  unsigned int i;

  UNUSED_PARAMETER(p);
  if( zName==0 ){
    i = -1;
  }else{
    for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0])-1; i++){
      if( strcmp(zName, aSyscall[0].zName)==0 ) break;
    }
  }
  for(i++; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){

    if( aSyscall[0].pCurrent!=0 ) return aSyscall[0].zName;
  }
  return 0;
}

/*
** Retry open() calls that fail due to EINTR
*/
................................................................................
    if( osFstat(pFile->h, &buf) ) return SQLITE_IOERR_FSTAT;

    nSize = ((nByte+pFile->szChunk-1) / pFile->szChunk) * pFile->szChunk;
    if( nSize>(i64)buf.st_size ){
#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
      int rc;
      do{
        rc = osFallocate(pFile->.h, buf.st_size, nSize-buf.st_size;
      }while( rc<0 && errno=EINTR );
      if( rc ) return SQLITE_IOERR_WRITE;
#else
      /* If the OS does not have posix_fallocate(), fake it. First use
      ** ftruncate() to set the file size, then write a single byte to
      ** the last byte in each block within the extended region. This
      ** is the same technique used by glibc to implement posix_fallocate()
      ** on systems that do not have a real fallocate() system call.







|







 







|


|
|
<
<
|


<
>
|







 







|
|







367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
...
440
441
442
443
444
445
446
447
448
449
450
451


452
453
454

455
456
457
458
459
460
461
462
463
....
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
#define osFchmod    ((int(*)(int,mode_t))aSyscall[14].pCurrent)

#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
  { "fallocate",    (sqlite3_syscall_ptr)posix_fallocate,  0 },
#else
  { "fallocate",    (sqlite3_syscall_ptr)0,                0 },
#endif
#define osFallocate ((int(*)(int,off_t,off_t))aSyscall[15].pCurrent)

}; /* End of the overrideable system calls */

/*
** This is the xSetSystemCall() method of sqlite3_vfs for all of the
** "unix" VFSes.  Return SQLITE_OK opon successfully updating the
** system call pointer, or SQLITE_NOTFOUND if there is no configurable
................................................................................
/*
** Return the name of the first system call after zName.  If zName==NULL
** then return the name of the first system call.  Return NULL if zName
** is the last system call or if zName is not the name of a valid
** system call.
*/
static const char *unixNextSystemCall(sqlite3_vfs *p, const char *zName){
  int i = -1;

  UNUSED_PARAMETER(p);
  if( zName ){
    for(i=0; i<ArraySize(aSyscall)-1; i++){


      if( strcmp(zName, aSyscall[i].zName)==0 ) break;
    }
  }

  for(i++; i<ArraySize(aSyscall); i++){
    if( aSyscall[i].pCurrent!=0 ) return aSyscall[i].zName;
  }
  return 0;
}

/*
** Retry open() calls that fail due to EINTR
*/
................................................................................
    if( osFstat(pFile->h, &buf) ) return SQLITE_IOERR_FSTAT;

    nSize = ((nByte+pFile->szChunk-1) / pFile->szChunk) * pFile->szChunk;
    if( nSize>(i64)buf.st_size ){
#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
      int rc;
      do{
        rc = osFallocate(pFile->h, buf.st_size, nSize-buf.st_size);
      }while( rc<0 && errno==EINTR );
      if( rc ) return SQLITE_IOERR_WRITE;
#else
      /* If the OS does not have posix_fallocate(), fake it. First use
      ** ftruncate() to set the file size, then write a single byte to
      ** the last byte in each block within the extended region. This
      ** is the same technique used by glibc to implement posix_fallocate()
      ** on systems that do not have a real fallocate() system call.

Changes to src/test_syscall.c.

42
43
44
45
46
47
48





















49
50
51
52
53
54
55
56
57
58



59
60
61
62
63
64
65
...
395
396
397
398
399
400
401
402
403
404
405



























































406
407
408
409
410
411
412
...
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
**   test_syscall errno CALL ERRNO
**     Set the value that the global "errno" is set to following a fault
**     in call CALL. Argument CALL must be one of the system call names
**     listed above (under [test_syscall install]). ERRNO is a symbolic
**     name (i.e. "EACCES"). Not all errno codes are supported. Add extra
**     to the aErrno table in function test_syscall_errno() below as 
**     required.





















*/

#include "sqlite3.h"
#include "tcl.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#ifdef SQLITE_OS_UNIX




#include <sys/types.h>
#include <errno.h>

static struct TestSyscallGlobal {
  int bPersist;                   /* 1 for persistent errors, 0 for transient */
  int nCount;                     /* Fail after this many more calls */
  int nFail;                      /* Number of failures that have occurred */
................................................................................
    Tcl_WrongNumArgs(interp, 2, objv, "");
    return TCL_ERROR;
  }

  pVfs = sqlite3_vfs_find(0);
  for(i=0; aSyscall[i].zName; i++){
    if( aSyscall[i].xOrig ){
      pVfs->xSetSystemCall(pVfs, aSyscall[i].zName, aSyscall[i].xOrig);
      aSyscall[i].xOrig = 0;
    }
  }



























































  return TCL_OK;
}

static int test_syscall_fault(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
................................................................................
      objv[3], aErrno, sizeof(aErrno[0]), "errno", 0, &iErrno
  );
  if( rc!=TCL_OK ) return rc;

  aSyscall[iCall].custom_errno = aErrno[iErrno].i;
  return TCL_OK;
}































static int test_syscall(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
................................................................................
  struct SyscallCmd {
    const char *zName;
    Tcl_ObjCmdProc *xCmd;
  } aCmd[] = {
    { "fault",     test_syscall_fault },
    { "install",   test_syscall_install },
    { "uninstall", test_syscall_uninstall },

    { "errno",     test_syscall_errno },


    { 0, 0 }
  };
  int iCmd;
  int rc;

  if( objc<2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>










>
>
>







 







|



>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>

>
>







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
...
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
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
...
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
...
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
**   test_syscall errno CALL ERRNO
**     Set the value that the global "errno" is set to following a fault
**     in call CALL. Argument CALL must be one of the system call names
**     listed above (under [test_syscall install]). ERRNO is a symbolic
**     name (i.e. "EACCES"). Not all errno codes are supported. Add extra
**     to the aErrno table in function test_syscall_errno() below as 
**     required.
**
**   test_syscall reset ?SYSTEM-CALL?
**     With no argument, this is an alias for the [uninstall] command. However,
**     this command uses a VFS call of the form:
**
**       xSetSystemCall(pVfs, 0, 0);
**
**     To restore the default system calls. The [uninstall] command restores
**     each system call individually by calling (i.e.):
**
**       xSetSystemCall(pVfs, "open", 0);
**
**     With an argument, this command attempts to reset the system call named
**     by the parameter using the same method as [uninstall].
**
**   test_syscall exists SYSTEM-CALL
**     Return true if the named system call exists. Or false otherwise.
**
**   test_syscall list
**     Return a list of all system calls. The list is constructed using
**     the xNextSystemCall() VFS method.
*/

#include "sqlite3.h"
#include "tcl.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#ifdef SQLITE_OS_UNIX

/* From test1.c */
extern const char *sqlite3TestErrorName(int);

#include <sys/types.h>
#include <errno.h>

static struct TestSyscallGlobal {
  int bPersist;                   /* 1 for persistent errors, 0 for transient */
  int nCount;                     /* Fail after this many more calls */
  int nFail;                      /* Number of failures that have occurred */
................................................................................
    Tcl_WrongNumArgs(interp, 2, objv, "");
    return TCL_ERROR;
  }

  pVfs = sqlite3_vfs_find(0);
  for(i=0; aSyscall[i].zName; i++){
    if( aSyscall[i].xOrig ){
      pVfs->xSetSystemCall(pVfs, aSyscall[i].zName, 0);
      aSyscall[i].xOrig = 0;
    }
  }
  return TCL_OK;
}

static int test_syscall_reset(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite3_vfs *pVfs; 
  int i;
  int rc;

  if( objc!=2 && objc!=3 ){
    Tcl_WrongNumArgs(interp, 2, objv, "");
    return TCL_ERROR;
  }

  pVfs = sqlite3_vfs_find(0);
  if( objc==2 ){
    rc = pVfs->xSetSystemCall(pVfs, 0, 0);
    for(i=0; aSyscall[i].zName; i++) aSyscall[i].xOrig = 0;
  }else{
    int nFunc;
    char *zFunc = Tcl_GetStringFromObj(objv[2], &nFunc);
    rc = pVfs->xSetSystemCall(pVfs, Tcl_GetString(objv[2]), 0);
    for(i=0; rc==SQLITE_OK && aSyscall[i].zName; i++){
      if( strlen(aSyscall[i].zName)!=nFunc ) continue;
      if( memcmp(aSyscall[i].zName, zFunc, nFunc) ) continue;
      aSyscall[i].xOrig = 0;
    }
  }
  if( rc!=SQLITE_OK ){
    Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3TestErrorName(rc), -1));
    return TCL_ERROR;
  }

  Tcl_ResetResult(interp);
  return TCL_OK;
}

static int test_syscall_exists(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite3_vfs *pVfs; 
  sqlite3_syscall_ptr x;

  if( objc!=3 ){
    Tcl_WrongNumArgs(interp, 2, objv, "");
    return TCL_ERROR;
  }

  pVfs = sqlite3_vfs_find(0);
  x = pVfs->xGetSystemCall(pVfs, Tcl_GetString(objv[2]));

  Tcl_SetObjResult(interp, Tcl_NewBooleanObj(x!=0));
  return TCL_OK;
}

static int test_syscall_fault(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
................................................................................
      objv[3], aErrno, sizeof(aErrno[0]), "errno", 0, &iErrno
  );
  if( rc!=TCL_OK ) return rc;

  aSyscall[iCall].custom_errno = aErrno[iErrno].i;
  return TCL_OK;
}

static int test_syscall_list(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  const char *zSys;
  sqlite3_vfs *pVfs; 
  Tcl_Obj *pList;

  if( objc!=2 ){
    Tcl_WrongNumArgs(interp, 2, objv, "");
    return TCL_ERROR;
  }

  pVfs = sqlite3_vfs_find(0);
  pList = Tcl_NewObj();
  Tcl_IncrRefCount(pList);
  for(zSys = pVfs->xNextSystemCall(pVfs, 0); 
      zSys!=0;
      zSys = pVfs->xNextSystemCall(pVfs, zSys)
  ){
    Tcl_ListObjAppendElement(interp, pList, Tcl_NewStringObj(zSys, -1));
  }

  Tcl_SetObjResult(interp, pList);
  Tcl_DecrRefCount(pList);
  return TCL_OK;
}

static int test_syscall(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
................................................................................
  struct SyscallCmd {
    const char *zName;
    Tcl_ObjCmdProc *xCmd;
  } aCmd[] = {
    { "fault",     test_syscall_fault },
    { "install",   test_syscall_install },
    { "uninstall", test_syscall_uninstall },
    { "reset",     test_syscall_reset },
    { "errno",     test_syscall_errno },
    { "exists",    test_syscall_exists },
    { "list",      test_syscall_list },
    { 0, 0 }
  };
  int iCmd;
  int rc;

  if( objc<2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");

test/progress.test became executable.

Added test/syscall.test.





























































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
# 2011 March 29
#
# 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.
#
#***********************************************************************
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/lock_common.tcl
source $testdir/malloc_common.tcl

if {[llength [info commands test_syscall]]==0} {
  finish_test
  return
} 
set testprefix syscall


#-------------------------------------------------------------------------
# Tests for the xSetSystemCall method.
#
do_test 1.1.1 {
  list [catch { test_syscall reset open } msg] $msg
} {0 {}}
do_test 1.1.2 {
  list [catch { test_syscall reset nosuchcall } msg] $msg
} {1 SQLITE_NOTFOUND}
do_test 1.1.3 {
  list [catch { test_syscall reset open } msg] $msg
} {0 {}}
do_test 1.1.4 {
  list [catch { test_syscall reset ""} msg] $msg
} {1 SQLITE_NOTFOUND}

do_test 1.2 { test_syscall reset } {}

do_test 1.3.1 { test_syscall install {open getcwd access} } {}
do_test 1.3.2 { test_syscall reset } {}

#-------------------------------------------------------------------------
# Tests for the xGetSystemCall method.
#
do_test 2.1.1 { test_syscall exists open } 1
do_test 2.1.2 { test_syscall exists nosuchcall } 0

#-------------------------------------------------------------------------
# Tests for the xNextSystemCall method.
#
set syscall_list [list                                \
    open close access getcwd stat fstat ftruncate     \
    fcntl read pread write pwrite fchmod              \
]
if {[test_syscall exists fallocate]} {lappend syscall_list fallocate}
do_test 3.1 { test_syscall list } $syscall_list

finish_test

tool/mkopts.tcl became executable.