/ Check-in [db5b7b77]
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:Merging in cherry picked diffs for persist wal, alloc padding, wal-safe vacuum and sqlite3_file_control based lockstate checking
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | apple-osx-377
Files: files | file ages | folders
SHA1: db5b7b778c09c57501cb8266895a0ea4f2de7649
User & Date: adam 2011-10-10 22:11:44
References
2011-10-10
23:53
Forward port the Apple-specific changes from [db5b7b778c] in the apple-osx-377 branch. Fix this up so that it will compile and run on Linux. check-in: 6cb43f6c user: drh tags: apple-osx
Context
2011-10-11
00:09
Patches to the apple-osx-377 branch so that it will compile and run on non-Mac unix platforms. Leaf check-in: b431a634 user: drh tags: apple-osx-377
2011-10-10
23:53
Forward port the Apple-specific changes from [db5b7b778c] in the apple-osx-377 branch. Fix this up so that it will compile and run on Linux. check-in: 6cb43f6c user: drh tags: apple-osx
22:11
Merging in cherry picked diffs for persist wal, alloc padding, wal-safe vacuum and sqlite3_file_control based lockstate checking check-in: db5b7b77 user: adam tags: apple-osx-377
18:59
Cherrypick the sqlite_data_count() changes from [d4f95b3b6e] and [9913996e7b] into the apple-osx branch for version 3.7.7. check-in: aef7945c user: drh tags: apple-osx-377
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/backup.c.

413
414
415
416
417
418
419









420
421
422
423
424
425
426
    if( rc==SQLITE_DONE 
     && (rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1))==SQLITE_OK
    ){
      int nDestTruncate;
  
      if( p->pDestDb ){
        sqlite3ResetInternalSchema(p->pDestDb, -1);









      }

      /* Set nDestTruncate to the final number of pages in the destination
      ** database. The complication here is that the destination page
      ** size may be different to the source page size. 
      **
      ** If the source page size is smaller than the destination page size, 







>
>
>
>
>
>
>
>
>







413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
    if( rc==SQLITE_DONE 
     && (rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1))==SQLITE_OK
    ){
      int nDestTruncate;
  
      if( p->pDestDb ){
        sqlite3ResetInternalSchema(p->pDestDb, -1);
        }
      
      if( destMode==PAGER_JOURNALMODE_WAL ){
          /* This call cannot fail. The success of the BtreeUpdateMeta()
                    ** method above indicates that a write transaction has been opened
                    ** and page 1 is already dirty. Therefore this always succeeds.
                    */
          TESTONLY(int rc2 =) sqlite3BtreeSetVersion(p->pDest, 2);
          assert( rc2==SQLITE_OK );
      }

      /* Set nDestTruncate to the final number of pages in the destination
      ** database. The complication here is that the destination page
      ** size may be different to the source page size. 
      **
      ** If the source page size is smaller than the destination page size, 

Changes to src/btree.c.

8165
8166
8167
8168
8169
8170
8171
8172
8173
8174
8175
8176
8177
8178
8179
** "write version" (single byte at byte offset 19) fields in the database
** header to iVersion.
*/
int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){
  BtShared *pBt = pBtree->pBt;
  int rc;                         /* Return code */
 
  assert( pBtree->inTrans==TRANS_NONE );
  assert( iVersion==1 || iVersion==2 );

  /* If setting the version fields to 1, do not automatically open the
  ** WAL connection, even if the version fields are currently set to 2.
  */
  pBt->doNotUseWAL = (u8)(iVersion==1);








<







8165
8166
8167
8168
8169
8170
8171

8172
8173
8174
8175
8176
8177
8178
** "write version" (single byte at byte offset 19) fields in the database
** header to iVersion.
*/
int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){
  BtShared *pBt = pBtree->pBt;
  int rc;                         /* Return code */
 

  assert( iVersion==1 || iVersion==2 );

  /* If setting the version fields to 1, do not automatically open the
  ** WAL connection, even if the version fields are currently set to 2.
  */
  pBt->doNotUseWAL = (u8)(iVersion==1);

Changes to src/main.c.

2975
2976
2977
2978
2979
2980
2981
2982
2983
2984

2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073

3074
3075
3076
3077
3078
3079
3080
3081
3082



3083
3084


3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
    zFilename += sqlite3Strlen30(zFilename) + 1;
    if( x==0 ) return zFilename;
    zFilename += sqlite3Strlen30(zFilename) + 1;
  }
  return 0;
}

#if (SQLITE_ENABLE_APPLE_SPI>0)
#define SQLITE_FILE_HEADER_LEN 16
#include <fcntl.h>

#include "sqlite3_private.h"
#include "btreeInt.h"
#include <errno.h>
#include <sys/param.h>

/* Check for a conflicting lock.  If one is found, print an this
 ** on standard output using the format string given and return 1.
 ** If there are no conflicting locks, return 0.
 */
static int isLocked(
  pid_t pid,            /* PID to test for lock owner */
  int h,                /* File descriptor to check */
  int type,             /* F_RDLCK or F_WRLCK */
  unsigned int iOfst,   /* First byte of the lock */
  unsigned int iCnt,    /* Number of bytes in the lock range */
  const char *zType     /* Type of lock */
){
  struct flock lk;
  int err;
  
  memset(&lk, 0, sizeof(lk));
  lk.l_type = type;
  lk.l_whence = SEEK_SET;
  lk.l_start = iOfst;
  lk.l_len = iCnt;

  if( pid!=SQLITE_LOCKSTATE_ANYPID ){
#ifndef F_GETLKPID
# warning F_GETLKPID undefined, _sqlite3_lockstate falling back to F_GETLK
    err = fcntl(h, F_GETLK, &lk);
#else
    lk.l_pid = pid;
    err = fcntl(h, F_GETLKPID, &lk);
#endif
  }else{
    err = fcntl(h, F_GETLK, &lk);
  }

  if( err==(-1) ){
    fprintf(stderr, "fcntl(%d) failed: errno=%d\n", h, errno);
    return -1;
  }
  
  if( lk.l_type!=F_UNLCK && (pid==SQLITE_LOCKSTATE_ANYPID || lk.l_pid==pid) ){
#ifdef SQLITE_DEBUG
    fprintf(stderr, "%s lock held by %d\n", zType, (int)lk.l_pid);
#endif
    return 1;
  } 
  return 0;
}

/*
 ** Location of locking bytes in the database file
 */
#ifndef PENDING_BYTE
# define PENDING_BYTE      (0x40000000)
# define RESERVED_BYTE     (PENDING_BYTE+1)
# define SHARED_FIRST      (PENDING_BYTE+2)
# define SHARED_SIZE       510
#endif /* PENDING_BYTE */

/*
 ** Lock locations for shared-memory locks used by WAL mode.
 */
#ifndef SHM_BASE
# define SHM_BASE          120
# define SHM_WRITE         SHM_BASE
# define SHM_CHECKPOINT    (SHM_BASE+1)
# define SHM_RECOVER       (SHM_BASE+2)
# define SHM_READ_FIRST    (SHM_BASE+3)
# define SHM_READ_SIZE     5
#endif /* SHM_BASE */

/* 
** Testing a file path for sqlite locks held by a process ID. 
** Returns SQLITE_LOCKSTATE_ON if locks are present on path
** that would prevent writing to the database.
**
** This test only works for lock testing on unix/posix VFS.
** Adapted from tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
*/
int _sqlite3_lockstate(const char *path, pid_t pid){
  int hDb;        /* File descriptor for the open database file */
  int hShm;       /* File descriptor for WAL shared-memory file */
  ssize_t got;    /* Bytes read from header */
  int isWal;                 /* True if in WAL mode */
  int nLock = 0;             /* Number of locks held */
  unsigned char aHdr[100];   /* Database header */

  
  /* Open the file at path and make sure we are dealing with a database file */
  hDb = open(path, O_RDONLY | O_NOCTTY);
  if( hDb<0 ){
    return SQLITE_LOCKSTATE_ERROR;
  }
  assert( (strlen(SQLITE_FILE_HEADER)+1)==SQLITE_FILE_HEADER_LEN );
  got = pread(hDb, aHdr, 100, 0);
  if( got<0 ){



    close(hDb);
    return SQLITE_LOCKSTATE_ERROR;


  }
  if( got!=100 || memcmp(aHdr, SQLITE_FILE_HEADER, SQLITE_FILE_HEADER_LEN)!=0 ){
    close(hDb);
    return SQLITE_LOCKSTATE_NOTADB;
  }
  
  /* First check for an exclusive lock */
  nLock += isLocked(pid, hDb, F_RDLCK, SHARED_FIRST, SHARED_SIZE, "EXCLUSIVE");
  isWal = aHdr[18]==2;
  if( nLock==0 && isWal==0 ){
    /* Rollback mode */
    nLock += isLocked(pid, hDb, F_WRLCK, PENDING_BYTE, SHARED_SIZE+2, "PENDING|RESERVED|SHARED");
  }
  close(hDb);
  if( nLock==0 && isWal!=0 ){
    char zShm[MAXPATHLEN];
    
    close(hDb);
    /* WAL mode */
    strlcpy(zShm, path, MAXPATHLEN);
    strlcat(zShm, "-shm", MAXPATHLEN);
    hShm = open(zShm, O_RDONLY, 0);
    if( hShm<0 ){
      return SQLITE_LOCKSTATE_OFF;
    }
    if( isLocked(pid, hShm, F_RDLCK, SHM_RECOVER, 1, "WAL-RECOVERY") ||
       isLocked(pid, hShm, F_RDLCK, SHM_WRITE, 1, "WAL-WRITE") ){
      nLock = 1;
    }
    close(hShm);
  }
  if( nLock>0 ){
    return SQLITE_LOCKSTATE_ON;
  }
  return SQLITE_LOCKSTATE_OFF;
}

#endif /* SQLITE_ENABLE_APPLE_SPI */







|
<
<
>

<
<
<

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<



<
<
<


<
<
<
<
<
<
>

<
<
<
<
<
<
<
<
>
>
>
|
<
>
>

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
|
<
|
<

2975
2976
2977
2978
2979
2980
2981
2982


2983
2984



2985















































2986






















2987
2988
2989



2990
2991






2992
2993








2994
2995
2996
2997

2998
2999
3000































3001
3002

3003

3004
    zFilename += sqlite3Strlen30(zFilename) + 1;
    if( x==0 ) return zFilename;
    zFilename += sqlite3Strlen30(zFilename) + 1;
  }
  return 0;
}

#if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__)



#include "sqlite3_private.h"



















































/* 






















** Testing a file path for sqlite locks held by a process ID. 
** Returns SQLITE_LOCKSTATE_ON if locks are present on path
** that would prevent writing to the database.



*/
int _sqlite3_lockstate(const char *path, pid_t pid){






  sqlite3 *db = NULL;
  








  if( sqlite3_open_v2(path, &db, SQLITE_OPEN_READONLY, NULL) == SQLITE_OK ){
    LockstatePID lockstate = {pid, -1};
    sqlite3_file_control(db, NULL, SQLITE_FCNTL_LOCKSTATE_PID, &lockstate);
    sqlite3_close(db);

    int state = lockstate.state;
    return state;
  }































  return SQLITE_LOCKSTATE_ERROR;
}



#endif /* SQLITE_ENABLE_APPLE_SPI */

Changes to src/mem1.c.

41
42
43
44
45
46
47

48
49
50
51
52
53
54
..
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
..
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
...
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include <libkern/OSAtomic.h>

static malloc_zone_t* _sqliteZone_;

#define SQLITE_MALLOC(x) malloc_zone_malloc(_sqliteZone_, (x))
#define SQLITE_FREE(x) malloc_zone_free(_sqliteZone_, (x));
#define SQLITE_REALLOC(x,y) malloc_zone_realloc(_sqliteZone_, (x), (y))


#endif

/*
** Like malloc(), but remember the size of the allocation
** so that we can find it later using sqlite3MemSize().
**
................................................................................
** cases of nByte<=0 will be intercepted and dealt with by higher level
** routines.
*/
static void *sqlite3MemMalloc(int nByte){
  sqlite3_int64 *p;
  assert( nByte>0 );
  nByte = ROUND8(nByte);
  p = SQLITE_MALLOC( nByte+8 );
  if( p ){
    p[0] = nByte;
    p++;
  }else{
    testcase( sqlite3GlobalConfig.xLog!=0 );
    sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes of memory", nByte);
  }
  return (void *)p;
}

/*
................................................................................
** For this low-level routine, we already know that pPrior!=0 since
** cases where pPrior==0 will have been intecepted and dealt with
** by higher-level routines.
*/
static void sqlite3MemFree(void *pPrior){
  sqlite3_int64 *p = (sqlite3_int64*)pPrior;
  assert( pPrior!=0 );
  p--;
  SQLITE_FREE(p);
}

/*
** Report the allocated size of a prior return from xMalloc()
** or xRealloc().
*/
static int sqlite3MemSize(void *pPrior){
  sqlite3_int64 *p;
  if( pPrior==0 ) return 0;
  p = (sqlite3_int64*)pPrior;
  p--;
  return (int)p[0];
}

/*
** Like realloc().  Resize an allocation previously obtained from
** sqlite3MemMalloc().
**
** For this low-level interface, we know that pPrior!=0.  Cases where
................................................................................
** cases where nByte<=0 will have been intercepted by higher-level
** routines and redirected to xFree.
*/
static void *sqlite3MemRealloc(void *pPrior, int nByte){
  sqlite3_int64 *p = (sqlite3_int64*)pPrior;
  assert( pPrior!=0 && nByte>0 );
  assert( nByte==ROUND8(nByte) ); /* EV: R-46199-30249 */
  p--;
  p = SQLITE_REALLOC(p, nByte+8 );
  if( p ){
    p[0] = nByte;
    p++;
  }else{
    testcase( sqlite3GlobalConfig.xLog!=0 );
    sqlite3_log(SQLITE_NOMEM,
      "failed memory resize %u to %u bytes",
      sqlite3MemSize(pPrior), nByte);
  }
  return (void*)p;
}







>







 







|
|
<
<
<







 







<










<
<
|







 







<
|
|
<
<
<







41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
..
57
58
59
60
61
62
63
64
65



66
67
68
69
70
71
72
..
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
...
103
104
105
106
107
108
109

110
111



112
113
114
115
116
117
118
#include <libkern/OSAtomic.h>

static malloc_zone_t* _sqliteZone_;

#define SQLITE_MALLOC(x) malloc_zone_malloc(_sqliteZone_, (x))
#define SQLITE_FREE(x) malloc_zone_free(_sqliteZone_, (x));
#define SQLITE_REALLOC(x,y) malloc_zone_realloc(_sqliteZone_, (x), (y))
#define SQLITE_MALLOCSIZE(x) (_sqliteZone_ ? _sqliteZone_->size(_sqliteZone_,x) : malloc_size(x))

#endif

/*
** Like malloc(), but remember the size of the allocation
** so that we can find it later using sqlite3MemSize().
**
................................................................................
** cases of nByte<=0 will be intercepted and dealt with by higher level
** routines.
*/
static void *sqlite3MemMalloc(int nByte){
  sqlite3_int64 *p;
  assert( nByte>0 );
  nByte = ROUND8(nByte);
  p = SQLITE_MALLOC( nByte );
  if( !p ){



    testcase( sqlite3GlobalConfig.xLog!=0 );
    sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes of memory", nByte);
  }
  return (void *)p;
}

/*
................................................................................
** For this low-level routine, we already know that pPrior!=0 since
** cases where pPrior==0 will have been intecepted and dealt with
** by higher-level routines.
*/
static void sqlite3MemFree(void *pPrior){
  sqlite3_int64 *p = (sqlite3_int64*)pPrior;
  assert( pPrior!=0 );

  SQLITE_FREE(p);
}

/*
** Report the allocated size of a prior return from xMalloc()
** or xRealloc().
*/
static int sqlite3MemSize(void *pPrior){
  sqlite3_int64 *p;
  if( pPrior==0 ) return 0;


  return (int)SQLITE_MALLOCSIZE(pPrior);
}

/*
** Like realloc().  Resize an allocation previously obtained from
** sqlite3MemMalloc().
**
** For this low-level interface, we know that pPrior!=0.  Cases where
................................................................................
** cases where nByte<=0 will have been intercepted by higher-level
** routines and redirected to xFree.
*/
static void *sqlite3MemRealloc(void *pPrior, int nByte){
  sqlite3_int64 *p = (sqlite3_int64*)pPrior;
  assert( pPrior!=0 && nByte>0 );
  assert( nByte==ROUND8(nByte) ); /* EV: R-46199-30249 */

  p = SQLITE_REALLOC(p, nByte );
  if( !p ){



    testcase( sqlite3GlobalConfig.xLog!=0 );
    sqlite3_log(SQLITE_NOMEM,
      "failed memory resize %u to %u bytes",
      sqlite3MemSize(pPrior), nByte);
  }
  return (void*)p;
}

Changes to src/os_unix.c.

254
255
256
257
258
259
260
261
262

263
264
265
266
267
268
269
....
1535
1536
1537
1538
1539
1540
1541


1542
1543
1544
1545
1546
1547
1548
....
1555
1556
1557
1558
1559
1560
1561








1562
1563
1564
1565
1566
1567
1568
1569
....
1577
1578
1579
1580
1581
1582
1583


1584




1585
1586
1587
1588
1589
1590
1591
....
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
....
1916
1917
1918
1919
1920
1921
1922
1923
1924

1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
....
1940
1941
1942
1943
1944
1945
1946
1947
1948

1949



1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
....
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980

1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994



1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
....
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
....
3841
3842
3843
3844
3845
3846
3847










































































































































































































































3848
3849
3850
3851

3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866











3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899


3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954

3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965

3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140


4141
4142
4143
4144
4145
4146
4147
....
4466
4467
4468
4469
4470
4471
4472







4473
4474

4475
4476
4477
4478
4479
4480
4481
....
4842
4843
4844
4845
4846
4847
4848












































































































































































































4849
4850
4851
4852
4853
4854
4855
  char aPadding[32];
#endif
};

/*
** Allowed values for the unixFile.ctrlFlags bitmask:
*/
#define UNIXFILE_EXCL   0x01     /* Connections from one process only */
#define UNIXFILE_RDONLY 0x02     /* Connection is read only */


/*
** Include code that is common to all os_*.c files
*/
#include "os_common.h"

/*
................................................................................
  unixLeaveMutex();
  OSTRACE(("TEST WR-LOCK %d %d %d (unix)\n", pFile->h, rc, reserved));

  *pResOut = reserved;
  return rc;
}



/*
** Attempt to set a system-lock on the file pFile.  The lock is 
** described by pLock.
**
** If the pFile was opened read/write from unix-excl, then the only lock
** ever obtained is an exclusive lock, and it is obtained exactly once
** the first time any lock is attempted.  All subsequent system locking
................................................................................
** any VFS other than "unix-excl" or if pFile is opened on "unix-excl"
** and is read-only.
**
** Zero is returned if the call completes successfully, or -1 if a call
** to fcntl() fails. In this case, errno is set appropriately (by fcntl()).
*/
static int unixFileLock(unixFile *pFile, struct flock *pLock){








  int rc;
  unixInodeInfo *pInode = pFile->pInode;
  assert( unixMutexHeld() );
  assert( pInode!=0 );
  if( ((pFile->ctrlFlags & UNIXFILE_EXCL)!=0 || pInode->bProcessLock)
   && ((pFile->ctrlFlags & UNIXFILE_RDONLY)==0)
  ){
    if( pInode->bProcessLock==0 ){
................................................................................
      if( rc<0 ) return rc;
      pInode->bProcessLock = 1;
      pInode->nLock++;
    }else{
      rc = 0;
    }
  }else{


    rc = osFcntl(pFile->h, F_SETLK, pLock);




  }
  return rc;
}

/*
** Lock the file with the lock specified by parameter eFileLock - one
** of the following:
................................................................................
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
    }

    /* Drop the temporary PENDING lock */
    lock.l_start = PENDING_BYTE;
    lock.l_len = 1L;
    lock.l_type = F_UNLCK;
    if( unixFileLock(pFile, &lock) && rc==SQLITE_OK ){
      /* This could happen with a network mount */
      tErrno = errno;
#if OSLOCKING_CHECK_BUSY_IOERR
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); 
#else
      rc = SQLITE_IOERR_UNLOCK; 
#endif
................................................................................
    if( eFileLock==SHARED_LOCK ){

#if !defined(__APPLE__) || !SQLITE_ENABLE_LOCKING_STYLE
      (void)handleNFSUnlock;
      assert( handleNFSUnlock==0 );
#endif
#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
      if( handleNFSUnlock ){
        int tErrno;               /* Error code from system call errors */

        off_t divSize = SHARED_SIZE - 1;
        
        lock.l_type = F_UNLCK;
        lock.l_whence = SEEK_SET;
        lock.l_start = SHARED_FIRST;
        lock.l_len = divSize;
        if( unixFileLock(pFile, &lock)==(-1) ){
          tErrno = errno;
#if OSLOCKING_CHECK_BUSY_IOERR
          rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
#else
          rc = SQLITE_IOERR_UNLOCK;
#endif
          if( IS_LOCK_ERROR(rc) ){
................................................................................
          }
          goto end_unlock;
        }
        lock.l_type = F_RDLCK;
        lock.l_whence = SEEK_SET;
        lock.l_start = SHARED_FIRST;
        lock.l_len = divSize;
        if( unixFileLock(pFile, &lock)==(-1) ){
          tErrno = errno;

          rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);



          if( IS_LOCK_ERROR(rc) ){
            pFile->lastErrno = tErrno;
          }
          goto end_unlock;
        }
        lock.l_type = F_UNLCK;
        lock.l_whence = SEEK_SET;
        lock.l_start = SHARED_FIRST+divSize;
        lock.l_len = SHARED_SIZE-divSize;
        if( unixFileLock(pFile, &lock)==(-1) ){
          tErrno = errno;
#if OSLOCKING_CHECK_BUSY_IOERR
          rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
#else
          rc = SQLITE_IOERR_UNLOCK;
#endif
          if( IS_LOCK_ERROR(rc) ){
................................................................................
      }else
#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
      {
        lock.l_type = F_RDLCK;
        lock.l_whence = SEEK_SET;
        lock.l_start = SHARED_FIRST;
        lock.l_len = SHARED_SIZE;
        if( unixFileLock(pFile, &lock) ){
#if OSLOCKING_CHECK_BUSY_IOERR
          tErrno = errno;

          rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);
          if( IS_LOCK_ERROR(rc) ){
            pFile->lastErrno = tErrno;
          }
#else
          /* In theory, the call to unixFileLock() cannot fail because another
          ** process is holding an incompatible lock. If it does, this 
          ** indicates that the other process is not following the locking
          ** protocol. If this happens, return SQLITE_IOERR_RDLOCK. Returning
          ** SQLITE_BUSY would confuse the upper layer (in practice it causes 
          ** an assert to fail). */ 
          rc = SQLITE_IOERR_RDLOCK;
          pFile->lastErrno = errno;
#endif



          goto end_unlock;
        }
      }
    }
    lock.l_type = F_UNLCK;
    lock.l_whence = SEEK_SET;
    lock.l_start = PENDING_BYTE;
    lock.l_len = 2L;  assert( PENDING_BYTE+1==RESERVED_BYTE );
    if( unixFileLock(pFile, &lock)==0 ){
      pInode->eFileLock = SHARED_LOCK;
    }else{
#if OSLOCKING_CHECK_BUSY_IOERR
      tErrno = errno;
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
      if( IS_LOCK_ERROR(rc) ){
        pFile->lastErrno = tErrno;
................................................................................
    if( pInode->nShared==0 ){
      lock.l_type = F_UNLCK;
      lock.l_whence = SEEK_SET;
      lock.l_start = lock.l_len = 0L;
      SimulateIOErrorBenign(1);
      SimulateIOError( h=(-1) )
      SimulateIOErrorBenign(0);
      if( unixFileLock(pFile, &lock)==0 ){
        pInode->eFileLock = NO_LOCK;
      }else{
#if OSLOCKING_CHECK_BUSY_IOERR
        tErrno = errno;
        rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
        if( IS_LOCK_ERROR(rc) ){
          pFile->lastErrno = tErrno;
................................................................................
#if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__)
#include "sqlite3_private.h"
#include <copyfile.h>
static int getDbPathForUnixFile(unixFile *pFile, char *dbPath);
#endif
static int isProxyLockingMode(unixFile *);











































































































































































































































/*
** Information and control of an open file handle.
*/
static int unixFileControl(sqlite3_file *id, int op, void *pArg){

  switch( op ){
    case SQLITE_FCNTL_LOCKSTATE: {
      *(int*)pArg = ((unixFile*)id)->eFileLock;
      return SQLITE_OK;
    }
    case SQLITE_LAST_ERRNO: {
      *(int*)pArg = ((unixFile*)id)->lastErrno;
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_CHUNK_SIZE: {
      ((unixFile*)id)->szChunk = *(int *)pArg;
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_SIZE_HINT: {
      return fcntlSizeHint((unixFile *)id, *(i64 *)pArg);











    }
#ifndef NDEBUG
    /* The pager calls this method to signal that it has done
    ** a rollback and that the database is therefore unchanged and
    ** it hence it is OK for the transaction change counter to be
    ** unchanged.
    */
    case SQLITE_FCNTL_DB_UNCHANGED: {
      ((unixFile*)id)->dbUpdate = 0;
      return SQLITE_OK;
    }
#endif
#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
    case SQLITE_SET_LOCKPROXYFILE:
    case SQLITE_GET_LOCKPROXYFILE: {
      return proxyFileControl(id,op,pArg);
    }
#endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */
#if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__)
    case SQLITE_TRUNCATE_DATABASE: {
      unixFile *pFile = (unixFile*)id;
      int rc = SQLITE_OK;
      void *pLock = NULL;
      int flags = 0;
      int corruptFileLock = 0;
      int isCorrupt = 0;

#if SQLITE_ENABLE_DATA_PROTECTION
      flags |= pFile->protFlags;
#endif
#if SQLITE_ENABLE_LOCKING_STYLE
      if( isProxyLockingMode(pFile) ){
        flags |= SQLITE_OPEN_AUTOPROXY;


      }
#endif
      
      rc = sqlite3demo_superlock(pFile->zPath, 0, flags, 0, 0, &pLock);
      if( rc ){
        if( rc==SQLITE_CORRUPT || rc==SQLITE_NOTADB ){
          isCorrupt = 1;
          rc = sqlite3demo_superlock_corrupt(id, SQLITE_LOCK_EXCLUSIVE, &corruptFileLock);
        }
        if( rc ){
          return rc;
        }
      }
      rc = pFile->pMethod->xTruncate(id, ((pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS) != 0) ? 1L : 0L);

      if( rc==SQLITE_OK ){
        char jPath[MAXPATHLEN+9];
        int zLen = strlcpy(jPath, pFile->zPath, MAXPATHLEN+9);
        if( zLen<MAXPATHLEN ){
          size_t jLen;
          const char extensions[2][9] = { "-wal", "-journal" /*, "-shm" */ };
          int j = 0;
          for( j=0; j<2; j++ ){
            jLen = strlcpy(&jPath[zLen], extensions[j], 9);
            if( jLen < 9 ){
              int jfd = open(jPath, O_TRUNC);
              if( jfd==(-1) ){
                if ( errno!=ENOENT ){
                  perror(jPath);
                }
              } else {
                fsync(jfd);
                close(jfd);
              }
            }
          }
        }
        pFile->pMethod->xSync(id, SQLITE_SYNC_FULL);
      }
      if( isCorrupt ){
        sqlite3demo_superunlock_corrupt(id, corruptFileLock);
      }else{
        sqlite3demo_superunlock(pLock);
      }
      return rc;
    }
      
    case SQLITE_REPLACE_DATABASE: {
      unixFile *pFile = (unixFile*)id;
      sqlite3 *srcdb = (sqlite3 *)pArg;
      Btree *pSrcBtree = NULL;
      sqlite3_file *src_file = NULL;
      unixFile *pSrcFile = NULL;
      char srcWalPath[MAXPATHLEN+5];
      int srcWalFD = -1;

      int rc = SQLITE_OK;
      void *pLock = NULL;
      int flags = 0;
      sqlite3 *srcdb2 = NULL;
      copyfile_state_t s;
      int corruptSrcFileLock = 0;
      int corruptDstFileLock = 0;
      int isSrcCorrupt = 0;
      int isDstCorrupt = 0;

      if( !sqlite3SafetyCheckOk(srcdb) ){

        return SQLITE_MISUSE;
      }
      
#if SQLITE_ENABLE_DATA_PROTECTION
      flags |= pFile->protFlags;
#endif
#if SQLITE_ENABLE_LOCKING_STYLE
      if( isProxyLockingMode(pFile) ){
        flags |= SQLITE_OPEN_AUTOPROXY;
      }
#endif
      
      rc = sqlite3demo_superlock(pFile->zPath, 0, flags, 0, 0, &pLock);
      if( rc ){
        if( rc==SQLITE_CORRUPT || rc==SQLITE_NOTADB ){
          isDstCorrupt = 1;
          rc = sqlite3demo_superlock_corrupt(id, SQLITE_LOCK_EXCLUSIVE, &corruptDstFileLock);
        }
        if( rc ){
          return rc;
        }
      }
      /* get the src file descriptor adhering to the db struct access rules 
       ** this code is modeled after sqlite3_file_control() in main.c
       */ 
      sqlite3_mutex_enter(srcdb->mutex);
      if( srcdb->nDb>0 ){
        pSrcBtree = srcdb->aDb[0].pBt;
      }
      if( pSrcBtree ){
        Pager *pSrcPager;
        sqlite3BtreeEnter(pSrcBtree);
        pSrcPager = sqlite3BtreePager(pSrcBtree);
        assert( pSrcPager!=0 );
        src_file = sqlite3PagerFile(pSrcPager);
        assert( src_file!=0 );
        if( src_file->pMethods ){
          int srcFlags = 0;
          pSrcFile = (unixFile *)src_file;
          /* wal mode db cannot be opened readonly */
          if ((pSrcFile->openFlags & O_RDWR) == O_RDWR) {
            srcFlags = SQLITE_OPEN_READWRITE;
          } else {
            srcFlags = SQLITE_OPEN_READONLY;
          }
#if SQLITE_ENABLE_DATA_PROTECTION
          srcFlags |= pSrcFile->protFlags;
#endif
#if SQLITE_ENABLE_LOCKING_STYLE
          if( isProxyLockingMode(pSrcFile) ){
            srcFlags |= SQLITE_OPEN_AUTOPROXY;
          }
#endif
          rc = sqlite3_open_v2(pSrcFile->zPath, &srcdb2, srcFlags, 0);
          if( rc==SQLITE_OK ){
            /* start a deferred transaction and read to establish a read lock */
            rc = sqlite3_exec(srcdb2, "BEGIN DEFERRED; PRAGMA schema_version", 0, 0, 0);
            if( rc==SQLITE_CORRUPT || rc==SQLITE_NOTADB ){
              isSrcCorrupt = 1;
              rc = sqlite3demo_superlock_corrupt(src_file, SQLITE_LOCK_SHARED, &corruptSrcFileLock);
            }
          }
        }
      }
      if( !srcdb2 || pSrcFile==NULL || pSrcFile->h<0){
        rc = SQLITE_INTERNAL;
      }
      if( rc!=SQLITE_OK ){
        goto end_replace_database;
      }
      /* both databases are locked appropriately, copy the src wal journal if 
      ** one exists and then the actual database file
      */
      strlcpy(srcWalPath, pSrcFile->zPath, MAXPATHLEN+5);
      strlcat(srcWalPath, "-wal", MAXPATHLEN+5);
      srcWalFD = open(srcWalPath, O_RDONLY);
      if( !(srcWalFD<0) ){
        char dstWalPath[MAXPATHLEN+5];
        int dstWalFD = -1;
        strlcpy(dstWalPath, pFile->zPath, MAXPATHLEN+5);
        strlcat(dstWalPath, "-wal", MAXPATHLEN+5);
        dstWalFD = open(dstWalPath, O_RDWR|O_CREAT, SQLITE_DEFAULT_FILE_PERMISSIONS);
        if( !(dstWalFD<0) ){
          s = copyfile_state_alloc();
          lseek(srcWalFD, 0, SEEK_SET);
          lseek(dstWalFD, 0, SEEK_SET);
          if( fcopyfile(srcWalFD, dstWalFD, s, COPYFILE_ALL) ){
            int err=errno;
            switch(err) {
              case ENOMEM:
                rc = SQLITE_NOMEM;
                break;
              default:
                pFile->lastErrno = err;
                rc = SQLITE_IOERR;
            }
          }
          copyfile_state_free(s);
          close(dstWalFD);
        }
        close(srcWalFD);
      }
      if( rc==SQLITE_OK ){
        /* before we copy, ensure that the file change counter will be modified */
        uint32_t srcChange = 0;
        uint32_t dstChange = 0;
        pread(pSrcFile->h, &srcChange, 4, 24);
        pread(pFile->h, &dstChange, 4, 24);
        
        /* copy the actual database */
        s = copyfile_state_alloc();
        lseek(pSrcFile->h, 0, SEEK_SET);
        lseek(pFile->h, 0, SEEK_SET);
        if( fcopyfile(pSrcFile->h, pFile->h, s, COPYFILE_ALL) ){
          int err=errno;
          switch(err) {
            case ENOMEM:
              rc = SQLITE_NOMEM;
              break;
            default:
              pFile->lastErrno = err;
              rc = SQLITE_IOERR;
          }
        }
        copyfile_state_free(s);
        
        if (srcChange == dstChange) {
          /* modify the change counter to force page zero to be reloaded */
          dstChange ++;
          pwrite(pFile->h, &dstChange, 4, 24);
        }
      }
      if( isSrcCorrupt ){
        sqlite3demo_superunlock_corrupt(src_file, corruptSrcFileLock);
      }else{
        /* done with the source db so end the transaction */
        sqlite3_exec(srcdb2, "COMMIT", 0, 0, 0);
      }
      /* zero out any old journal clutter */
      if( rc==SQLITE_OK ){
        char jPath[MAXPATHLEN+9];
        int zLen = strlcpy(jPath, pFile->zPath, MAXPATHLEN+9);
        if( zLen<MAXPATHLEN ){
          size_t jLen;
          const char extensions[2][9] = { "-wal", "-journal" /* "-shm" */ };
          int j = (srcWalFD<0)?0:1; /* skip the wal if we replaced it */
          for( ; j<2; j++ ){
            jLen = strlcpy(&jPath[zLen], extensions[j], 9);
            if( jLen < 9 ){
              int jfd = open(jPath, O_TRUNC);
              if( jfd==(-1) ){
                if ( errno!=ENOENT ){
                  perror(jPath);
                }
              } else {
                fsync(jfd);
                close(jfd);
              }
            }
          }
        }
        pFile->pMethod->xSync(id, SQLITE_SYNC_FULL);
      }
      
    end_replace_database:
      if( pSrcBtree ){
        sqlite3_close(srcdb2);
        sqlite3BtreeLeave(pSrcBtree);
      }
      sqlite3_mutex_leave(srcdb->mutex);
      if( isDstCorrupt ){
        sqlite3demo_superunlock_corrupt(id, corruptDstFileLock);
      }else{
        sqlite3demo_superunlock(pLock);
      }


      return rc;
    }
#endif /* (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__) */
    case SQLITE_FCNTL_SYNC_OMITTED: {
      return SQLITE_OK;  /* A no-op */
    }
  }
................................................................................
    pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
    if( pShmNode->mutex==0 ){
      rc = SQLITE_NOMEM;
      goto shm_open_err;
    }

    if( pInode->bProcessLock==0 ){







      pShmNode->h = robust_open(zShmFilename, O_RDWR|O_CREAT,
                               (sStat.st_mode & 0777));

      if( pShmNode->h<0 ){
        const char *zRO;
        zRO = sqlite3_uri_parameter(pDbFd->zPath, "readonly_shm");
        if( zRO && sqlite3GetBoolean(zRO) ){
          pShmNode->h = robust_open(zShmFilename, O_RDONLY,
                                    (sStat.st_mode & 0777));
          pShmNode->isReadonly = 1;
................................................................................

#else
# define unixShmMap     0
# define unixShmLock    0
# define unixShmBarrier 0
# define unixShmUnmap   0
#endif /* #ifndef SQLITE_OMIT_WAL */













































































































































































































/*
** Here ends the implementation of all sqlite3_file methods.
**
********************** End sqlite3_file Methods *******************************
******************************************************************************/








|
|
>







 







>
>







 







>
>
>
>
>
>
>
>
|







 







>
>
|
>
>
>
>







 







|







 







<
|
>






|







 







|

>

>
>
>









|







 







|
<

>

<
<
<








|

>
>
>








|







 







|







 







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




>


|


|
|



|



|
>
>
>
>
>
>
>
>
>
>
>













|
|




|
|
<
<
<
<
<
|
<
<
<
<
<
<
>
>
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
<
>
|
<
<
<
<
<
<
<
<
|
<
>


<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
>
>







 







>
>
>
>
>
>
>
|

>







 







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







254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
....
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
....
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
....
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
....
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
....
1933
1934
1935
1936
1937
1938
1939

1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
....
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
....
1992
1993
1994
1995
1996
1997
1998
1999

2000
2001
2002



2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
....
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
....
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154





4155






4156
4157
4158














































4159







4160
4161








4162

4163
4164
4165













































































































































































4166
4167
4168
4169
4170
4171
4172
4173
4174
....
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
4516
....
4877
4878
4879
4880
4881
4882
4883
4884
4885
4886
4887
4888
4889
4890
4891
4892
4893
4894
4895
4896
4897
4898
4899
4900
4901
4902
4903
4904
4905
4906
4907
4908
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
4919
4920
4921
4922
4923
4924
4925
4926
4927
4928
4929
4930
4931
4932
4933
4934
4935
4936
4937
4938
4939
4940
4941
4942
4943
4944
4945
4946
4947
4948
4949
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967
4968
4969
4970
4971
4972
4973
4974
4975
4976
4977
4978
4979
4980
4981
4982
4983
4984
4985
4986
4987
4988
4989
4990
4991
4992
4993
4994
4995
4996
4997
4998
4999
5000
5001
5002
5003
5004
5005
5006
5007
5008
5009
5010
5011
5012
5013
5014
5015
5016
5017
5018
5019
5020
5021
5022
5023
5024
5025
5026
5027
5028
5029
5030
5031
5032
5033
5034
5035
5036
5037
5038
5039
5040
5041
5042
5043
5044
5045
5046
5047
5048
5049
5050
5051
5052
5053
5054
5055
5056
5057
5058
5059
5060
5061
5062
5063
5064
5065
5066
5067
5068
5069
5070
5071
5072
5073
5074
5075
5076
5077
5078
5079
5080
5081
5082
5083
5084
5085
5086
5087
5088
5089
5090
5091
5092
5093
5094
  char aPadding[32];
#endif
};

/*
** Allowed values for the unixFile.ctrlFlags bitmask:
*/
#define UNIXFILE_EXCL        0x01     /* Connections from one process only */
#define UNIXFILE_RDONLY      0x02     /* Connection is read only */
#define UNIXFILE_PERSIST_WAL 0x04     /* Persistent WAL mode */

/*
** Include code that is common to all os_*.c files
*/
#include "os_common.h"

/*
................................................................................
  unixLeaveMutex();
  OSTRACE(("TEST WR-LOCK %d %d %d (unix)\n", pFile->h, rc, reserved));

  *pResOut = reserved;
  return rc;
}

static int _unixFileLock(unixFile *pFile, struct flock *pLock, int retry);

/*
** Attempt to set a system-lock on the file pFile.  The lock is 
** described by pLock.
**
** If the pFile was opened read/write from unix-excl, then the only lock
** ever obtained is an exclusive lock, and it is obtained exactly once
** the first time any lock is attempted.  All subsequent system locking
................................................................................
** any VFS other than "unix-excl" or if pFile is opened on "unix-excl"
** and is read-only.
**
** Zero is returned if the call completes successfully, or -1 if a call
** to fcntl() fails. In this case, errno is set appropriately (by fcntl()).
*/
static int unixFileLock(unixFile *pFile, struct flock *pLock){
  return _unixFileLock(pFile, pLock, 0);
}

static int unixFileLock2(unixFile *pFile, struct flock *pLock){
  return _unixFileLock(pFile, pLock, 10);
}

static int _unixFileLock(unixFile *pFile, struct flock *pLock, int retry) {
  int rc = 0;
  unixInodeInfo *pInode = pFile->pInode;
  assert( unixMutexHeld() );
  assert( pInode!=0 );
  if( ((pFile->ctrlFlags & UNIXFILE_EXCL)!=0 || pInode->bProcessLock)
   && ((pFile->ctrlFlags & UNIXFILE_RDONLY)==0)
  ){
    if( pInode->bProcessLock==0 ){
................................................................................
      if( rc<0 ) return rc;
      pInode->bProcessLock = 1;
      pInode->nLock++;
    }else{
      rc = 0;
    }
  }else{
    int i = 0;                      
    do {
      rc = osFcntl(pFile->h, F_SETLK, pLock);
      if (rc && retry) {
        usleep(100 * (++i));
      }
    } while (!rc && retry--);
  }
  return rc;
}

/*
** Lock the file with the lock specified by parameter eFileLock - one
** of the following:
................................................................................
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
    }

    /* Drop the temporary PENDING lock */
    lock.l_start = PENDING_BYTE;
    lock.l_len = 1L;
    lock.l_type = F_UNLCK;
    if( unixFileLock2(pFile, &lock) && rc==SQLITE_OK ){
      /* This could happen with a network mount */
      tErrno = errno;
#if OSLOCKING_CHECK_BUSY_IOERR
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); 
#else
      rc = SQLITE_IOERR_UNLOCK; 
#endif
................................................................................
    if( eFileLock==SHARED_LOCK ){

#if !defined(__APPLE__) || !SQLITE_ENABLE_LOCKING_STYLE
      (void)handleNFSUnlock;
      assert( handleNFSUnlock==0 );
#endif
#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE

      int tErrno;               /* Error code from system call errors */
      if( handleNFSUnlock ){
        off_t divSize = SHARED_SIZE - 1;
        
        lock.l_type = F_UNLCK;
        lock.l_whence = SEEK_SET;
        lock.l_start = SHARED_FIRST;
        lock.l_len = divSize;
        if( unixFileLock2(pFile, &lock)==(-1) ){
          tErrno = errno;
#if OSLOCKING_CHECK_BUSY_IOERR
          rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
#else
          rc = SQLITE_IOERR_UNLOCK;
#endif
          if( IS_LOCK_ERROR(rc) ){
................................................................................
          }
          goto end_unlock;
        }
        lock.l_type = F_RDLCK;
        lock.l_whence = SEEK_SET;
        lock.l_start = SHARED_FIRST;
        lock.l_len = divSize;
        if( unixFileLock2(pFile, &lock)==(-1) ){
          tErrno = errno;
#if OSLOCKING_CHECK_BUSY_IOERR
          rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);
#else
          rc = SQLITE_IOERR_UNLOCK;
#endif
          if( IS_LOCK_ERROR(rc) ){
            pFile->lastErrno = tErrno;
          }
          goto end_unlock;
        }
        lock.l_type = F_UNLCK;
        lock.l_whence = SEEK_SET;
        lock.l_start = SHARED_FIRST+divSize;
        lock.l_len = SHARED_SIZE-divSize;
        if( unixFileLock2(pFile, &lock)==(-1) ){
          tErrno = errno;
#if OSLOCKING_CHECK_BUSY_IOERR
          rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
#else
          rc = SQLITE_IOERR_UNLOCK;
#endif
          if( IS_LOCK_ERROR(rc) ){
................................................................................
      }else
#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
      {
        lock.l_type = F_RDLCK;
        lock.l_whence = SEEK_SET;
        lock.l_start = SHARED_FIRST;
        lock.l_len = SHARED_SIZE;
        if( unixFileLock2(pFile, &lock) ){

          tErrno = errno;
#if OSLOCKING_CHECK_BUSY_IOERR
          rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);



#else
          /* In theory, the call to unixFileLock() cannot fail because another
          ** process is holding an incompatible lock. If it does, this 
          ** indicates that the other process is not following the locking
          ** protocol. If this happens, return SQLITE_IOERR_RDLOCK. Returning
          ** SQLITE_BUSY would confuse the upper layer (in practice it causes 
          ** an assert to fail). */ 
          rc = SQLITE_IOERR_RDLOCK;
          pFile->lastErrno = tErrno;
#endif
          if( IS_LOCK_ERROR(rc) ){
            pFile->lastErrno = tErrno;
          }
          goto end_unlock;
        }
      }
    }
    lock.l_type = F_UNLCK;
    lock.l_whence = SEEK_SET;
    lock.l_start = PENDING_BYTE;
    lock.l_len = 2L;  assert( PENDING_BYTE+1==RESERVED_BYTE );
    if( unixFileLock2(pFile, &lock)==0 ){
      pInode->eFileLock = SHARED_LOCK;
    }else{
#if OSLOCKING_CHECK_BUSY_IOERR
      tErrno = errno;
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
      if( IS_LOCK_ERROR(rc) ){
        pFile->lastErrno = tErrno;
................................................................................
    if( pInode->nShared==0 ){
      lock.l_type = F_UNLCK;
      lock.l_whence = SEEK_SET;
      lock.l_start = lock.l_len = 0L;
      SimulateIOErrorBenign(1);
      SimulateIOError( h=(-1) )
      SimulateIOErrorBenign(0);
      if( unixFileLock2(pFile, &lock)==0 ){
        pInode->eFileLock = NO_LOCK;
      }else{
#if OSLOCKING_CHECK_BUSY_IOERR
        tErrno = errno;
        rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
        if( IS_LOCK_ERROR(rc) ){
          pFile->lastErrno = tErrno;
................................................................................
#if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__)
#include "sqlite3_private.h"
#include <copyfile.h>
static int getDbPathForUnixFile(unixFile *pFile, char *dbPath);
#endif
static int isProxyLockingMode(unixFile *);

#if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__)
static int unixTruncateDatabase(unixFile *, int);

static int unixInvalidateSupportFiles(unixFile *, int);

static int unixReplaceDatabase(unixFile *pFile, sqlite3 *srcdb) {
  sqlite3_file *id = (sqlite3_file *)pFile;
  Btree *pSrcBtree = NULL;
  sqlite3_file *src_file = NULL;
  unixFile *pSrcFile = NULL;
  char srcWalPath[MAXPATHLEN+5];
  int srcWalFD = -1;
  int rc = SQLITE_OK;
  void *pLock = NULL;
  int flags = 0;
  sqlite3 *srcdb2 = NULL;
  copyfile_state_t s;
  int corruptSrcFileLock = 0;
  int corruptDstFileLock = 0;
  int isSrcCorrupt = 0;
  int isDstCorrupt = 0;
  
  if( !sqlite3SafetyCheckOk(srcdb) ){
    return SQLITE_MISUSE;
  }
    
#if SQLITE_ENABLE_DATA_PROTECTION
  flags |= pFile->protFlags;
#endif
#if SQLITE_ENABLE_LOCKING_STYLE
  if( isProxyLockingMode(pFile) ){
    flags |= SQLITE_OPEN_AUTOPROXY;
  }
#endif
  
  rc = sqlite3demo_superlock(pFile->zPath, 0, flags, 0, 0, &pLock);
  if( rc ){
    if( rc==SQLITE_CORRUPT || rc==SQLITE_NOTADB ){
      isDstCorrupt = 1;
      rc = sqlite3demo_superlock_corrupt(id, SQLITE_LOCK_EXCLUSIVE, &corruptDstFileLock);
    }
    if( rc ){
      return rc;
    }
  }
  /* get the src file descriptor adhering to the db struct access rules 
   ** this code is modeled after sqlite3_file_control() in main.c
   */ 
  sqlite3_mutex_enter(srcdb->mutex);
  if( srcdb->nDb>0 ){
    pSrcBtree = srcdb->aDb[0].pBt;
  }
  if( pSrcBtree ){
    Pager *pSrcPager;
    sqlite3BtreeEnter(pSrcBtree);
    pSrcPager = sqlite3BtreePager(pSrcBtree);
    assert( pSrcPager!=0 );
    src_file = sqlite3PagerFile(pSrcPager);
    assert( src_file!=0 );
    if( src_file->pMethods ){
      int srcFlags = 0;
      pSrcFile = (unixFile *)src_file;
      /* wal mode db cannot be opened readonly */
      if ((pSrcFile->openFlags & O_RDWR) == O_RDWR) {
        srcFlags = SQLITE_OPEN_READWRITE;
      } else {
        srcFlags = SQLITE_OPEN_READONLY;
      }
#if SQLITE_ENABLE_DATA_PROTECTION
      srcFlags |= pSrcFile->protFlags;
#endif
#if SQLITE_ENABLE_LOCKING_STYLE
      if( isProxyLockingMode(pSrcFile) ){
        srcFlags |= SQLITE_OPEN_AUTOPROXY;
      }
#endif
      rc = sqlite3_open_v2(pSrcFile->zPath, &srcdb2, srcFlags, 0);
      if( rc==SQLITE_OK ){
        /* start a deferred transaction and read to establish a read lock */
        rc = sqlite3_exec(srcdb2, "BEGIN DEFERRED; PRAGMA schema_version", 0, 0, 0);
        if( rc==SQLITE_CORRUPT || rc==SQLITE_NOTADB ){
          isSrcCorrupt = 1;
          rc = sqlite3demo_superlock_corrupt(src_file, SQLITE_LOCK_SHARED, &corruptSrcFileLock);
        }
      }
    }
  }
  if( !srcdb2 || pSrcFile==NULL || pSrcFile->h<0){
    rc = SQLITE_INTERNAL;
  }
  if( rc!=SQLITE_OK ){
    goto end_replace_database;
  }
  /* both databases are locked appropriately, copy the src wal journal if 
   ** one exists and then the actual database file
   */
  strlcpy(srcWalPath, pSrcFile->zPath, MAXPATHLEN+5);
  strlcat(srcWalPath, "-wal", MAXPATHLEN+5);
  srcWalFD = open(srcWalPath, O_RDONLY);
  if( !(srcWalFD<0) ){
    char dstWalPath[MAXPATHLEN+5];
    int dstWalFD = -1;
    strlcpy(dstWalPath, pFile->zPath, MAXPATHLEN+5);
    strlcat(dstWalPath, "-wal", MAXPATHLEN+5);
    dstWalFD = open(dstWalPath, O_RDWR|O_CREAT, SQLITE_DEFAULT_FILE_PERMISSIONS);
    if( !(dstWalFD<0) ){
      s = copyfile_state_alloc();
      lseek(srcWalFD, 0, SEEK_SET);
      lseek(dstWalFD, 0, SEEK_SET);
      if( fcopyfile(srcWalFD, dstWalFD, s, COPYFILE_ALL) ){
        int err=errno;
        switch(err) {
          case ENOMEM:
            rc = SQLITE_NOMEM;
            break;
          default:
            pFile->lastErrno = err;
            rc = SQLITE_IOERR;
        }
      }
      copyfile_state_free(s);
      close(dstWalFD);
    }
    close(srcWalFD);
  }
  if( rc==SQLITE_OK ){
    /* before we copy, ensure that the file change counter will be modified */
    uint32_t srcChange = 0;
    uint32_t dstChange = 0;
    pread(pSrcFile->h, &srcChange, 4, 24);
    pread(pFile->h, &dstChange, 4, 24);
    
    /* copy the actual database */
    s = copyfile_state_alloc();
    lseek(pSrcFile->h, 0, SEEK_SET);
    lseek(pFile->h, 0, SEEK_SET);
    if( fcopyfile(pSrcFile->h, pFile->h, s, COPYFILE_ALL) ){
      int err=errno;
      switch(err) {
        case ENOMEM:
          rc = SQLITE_NOMEM;
          break;
        default:
          pFile->lastErrno = err;
          rc = SQLITE_IOERR;
      }
    }
    copyfile_state_free(s);
    
    if (srcChange == dstChange) {
      /* modify the change counter to force page zero to be reloaded */
      dstChange ++;
      pwrite(pFile->h, &dstChange, 4, 24);
    }
  }
  if( isSrcCorrupt ){
    sqlite3demo_superunlock_corrupt(src_file, corruptSrcFileLock);
  }else{
    /* done with the source db so end the transaction */
    sqlite3_exec(srcdb2, "COMMIT", 0, 0, 0);
  }
  /* zero out any old journal clutter */
  if( rc==SQLITE_OK ){
    int skipWAL = (srcWalFD<0)?0:1;
    unixInvalidateSupportFiles(pFile, skipWAL);
  }
  
end_replace_database:
  if( pSrcBtree ){
    sqlite3_close(srcdb2);
    sqlite3BtreeLeave(pSrcBtree);
  }
  sqlite3_mutex_leave(srcdb->mutex);
  if( isDstCorrupt ){
    sqlite3demo_superunlock_corrupt(id, corruptDstFileLock);
  }else{
    sqlite3demo_superunlock(pLock);
  }
  return rc;
}

#define SQLITE_FILE_HEADER_LEN 16
#include "btreeInt.h"
/* Check for a conflicting lock.  If one is found, print an this
 ** on standard output using the format string given and return 1.
 ** If there are no conflicting locks, return 0.
 */
static int unixIsLocked(
  pid_t pid,            /* PID to test for lock owner */
  int h,                /* File descriptor to check */
  int type,             /* F_RDLCK or F_WRLCK */
  unsigned int iOfst,   /* First byte of the lock */
  unsigned int iCnt,    /* Number of bytes in the lock range */
  const char *zType     /* Type of lock */
){
  struct flock lk;
  int err;
  
  memset(&lk, 0, sizeof(lk));
  lk.l_type = type;
  lk.l_whence = SEEK_SET;
  lk.l_start = iOfst;
  lk.l_len = iCnt;
  
  if( pid!=SQLITE_LOCKSTATE_ANYPID ){
#ifndef F_GETLKPID
# warning F_GETLKPID undefined, _sqlite3_lockstate falling back to F_GETLK
    err = fcntl(h, F_GETLK, &lk);
#else
    lk.l_pid = pid;
    err = fcntl(h, F_GETLKPID, &lk);
#endif
  }else{
    err = fcntl(h, F_GETLK, &lk);
  }
  
  if( err==(-1) ){
    fprintf(stderr, "fcntl(%d) failed: errno=%d\n", h, errno);
    return -1;
  }
  
  if( lk.l_type!=F_UNLCK && (pid==SQLITE_LOCKSTATE_ANYPID || lk.l_pid==pid) ){
#ifdef SQLITE_DEBUG
    fprintf(stderr, "%s lock held by %d\n", zType, (int)lk.l_pid);
#endif
    return 1;
  } 
  return 0;
}

static int unixLockstatePid(unixFile *, pid_t, int *);

#endif /* (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__) */
                               
/*
** Information and control of an open file handle.
*/
static int unixFileControl(sqlite3_file *id, int op, void *pArg){
  unixFile *pFile = (unixFile*)id;
  switch( op ){
    case SQLITE_FCNTL_LOCKSTATE: {
      *(int*)pArg = pFile->eFileLock;
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_LAST_ERRNO: {
      *(int*)pArg = pFile->lastErrno;
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_CHUNK_SIZE: {
      pFile->szChunk = *(int *)pArg;
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_SIZE_HINT: {
      return fcntlSizeHint(pFile, *(i64 *)pArg);
    }
    case SQLITE_FCNTL_PERSIST_WAL: {
      int bPersist = *(int*)pArg;
      if( bPersist<0 ){
        *(int*)pArg = (pFile->ctrlFlags & UNIXFILE_PERSIST_WAL)!=0;
      }else if( bPersist==0 ){
        pFile->ctrlFlags &= ~UNIXFILE_PERSIST_WAL;
      }else{
        pFile->ctrlFlags |= UNIXFILE_PERSIST_WAL;
      }
      return SQLITE_OK;
    }
#ifndef NDEBUG
    /* The pager calls this method to signal that it has done
    ** a rollback and that the database is therefore unchanged and
    ** it hence it is OK for the transaction change counter to be
    ** unchanged.
    */
    case SQLITE_FCNTL_DB_UNCHANGED: {
      ((unixFile*)id)->dbUpdate = 0;
      return SQLITE_OK;
    }
#endif
#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
    case SQLITE_FCNTL_SET_LOCKPROXYFILE:
    case SQLITE_FCNTL_GET_LOCKPROXYFILE: {
      return proxyFileControl(id,op,pArg);
    }
#endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */
#if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__)
    case SQLITE_FCNTL_TRUNCATE_DATABASE: {
      return unixTruncateDatabase(pFile, (pArg ? (*(int *)pArg) : 0));





    }






    case SQLITE_FCNTL_REPLACE_DATABASE: {
      return unixReplaceDatabase(pFile, (sqlite3 *)pArg);
    }














































    case SQLITE_FCNTL_LOCKSTATE_PID: {







      LockstatePID *pLockstate;
      int rc;








      

      if( pArg==NULL ){
        return SQLITE_MISUSE;
      }













































































































































































      pLockstate = (LockstatePID *)pArg;
      rc = unixLockstatePid(pFile, pLockstate->pid, &(pLockstate->state));
      return rc;
    }
#endif /* (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__) */
    case SQLITE_FCNTL_SYNC_OMITTED: {
      return SQLITE_OK;  /* A no-op */
    }
  }
................................................................................
    pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
    if( pShmNode->mutex==0 ){
      rc = SQLITE_NOMEM;
      goto shm_open_err;
    }

    if( pInode->bProcessLock==0 ){
      const char *zRO;
      zRO = sqlite3_uri_parameter(pDbFd->zPath, "readonly_shm");
      if( zRO && sqlite3GetBoolean(zRO) ){
        pShmNode->h = robust_open(zShmFilename, O_RDONLY,
                                  (sStat.st_mode & 0777));
        pShmNode->isReadonly = 1;
      }else{
        pShmNode->h = robust_open(zShmFilename, O_RDWR|O_CREAT,
                               (sStat.st_mode & 0777));
      }
      if( pShmNode->h<0 ){
        const char *zRO;
        zRO = sqlite3_uri_parameter(pDbFd->zPath, "readonly_shm");
        if( zRO && sqlite3GetBoolean(zRO) ){
          pShmNode->h = robust_open(zShmFilename, O_RDONLY,
                                    (sStat.st_mode & 0777));
          pShmNode->isReadonly = 1;
................................................................................

#else
# define unixShmMap     0
# define unixShmLock    0
# define unixShmBarrier 0
# define unixShmUnmap   0
#endif /* #ifndef SQLITE_OMIT_WAL */

#if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__)
static const char *unixTempFileDir(void);

static int unixInvalidateSupportFiles(unixFile *pFile, int skipWAL) {
  char jPath[MAXPATHLEN+9];
  int zLen = strlcpy(jPath, pFile->zPath, MAXPATHLEN+9);
  if( zLen<MAXPATHLEN ){
    size_t jLen;
    const char extensions[3][9] = { "-wal", "-journal", "-shm" };
    int j = (skipWAL ? 1 : 0);
    for( ; j<3; j++ ){
      
      /* Check to see if the shm file is already opened for this pFile */
      if( j==2 ){
        unixEnterMutex(); /* Because pFile->pInode is shared across threads */
        unixShmNode *pShmNode = pFile->pInode->pShmNode;
        if( pShmNode && !pShmNode->isReadonly ){
          struct stat sStat;
          sqlite3_mutex_enter(pShmNode->mutex);
          
          if( pShmNode->h>=0 && !osFstat(pShmNode->h, &sStat) ){
            unsigned long size = (sStat.st_size<4) ? sStat.st_size : 4;
            if( size>0 ){
              bzero(pShmNode->apRegion[0], size);
              sqlite3_mutex_leave(pShmNode->mutex);
              unixLeaveMutex();
              continue;
            }
          }
          sqlite3_mutex_leave(pShmNode->mutex);
        }
        unixLeaveMutex();
      }
      jLen = strlcpy(&jPath[zLen], extensions[j], 9);
      if( jLen < 9 ){
        int jflags = (j<2) ? O_TRUNC : O_RDWR;
        int jfd = open(jPath, jflags);
        if( jfd==(-1) ){
          if( errno!=ENOENT ){
            perror(jPath);
          }
        } else {
          if( j==2 ){
            struct stat sStat;
            if( !osFstat(jfd, &sStat) ){
              unsigned long size = (sStat.st_size<4) ? sStat.st_size : 4;
              if( size>0 ){
                uint32_t zero = 0;
                pwrite(jfd, &zero, (size_t)size, 0);
              }
            }
          }
          fsync(jfd);
          close(jfd);
        }
      }
    }
  }
  return SQLITE_OK;
}

static int unixTruncateDatabase(unixFile *pFile, int bFlags) {
  sqlite3_file *id = (sqlite3_file *)pFile;
  int rc = SQLITE_OK;
  void *pLock = NULL;
  int flags = 0;
  int corruptFileLock = 0;
  int isCorrupt = 0;
    
#if SQLITE_ENABLE_DATA_PROTECTION
  flags |= pFile->protFlags;
#endif
#if SQLITE_ENABLE_LOCKING_STYLE
  if( isProxyLockingMode(pFile) ){
    flags |= SQLITE_OPEN_AUTOPROXY;
  }
#endif
  
  rc = sqlite3demo_superlock(pFile->zPath, 0, flags, 0, 0, &pLock);
  if( rc ){
    if( rc==SQLITE_CORRUPT || rc==SQLITE_NOTADB ){
      isCorrupt = 1;
      rc = sqlite3demo_superlock_corrupt(id, SQLITE_LOCK_EXCLUSIVE, &corruptFileLock);
    }
    if( rc ){
      return rc;
    }
  }
  rc = pFile->pMethod->xTruncate(id, ((pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS) != 0) ? 1L : 0L);
  if( rc==SQLITE_OK ){
    unixInvalidateSupportFiles(pFile, 0);
  }
  pFile->pMethod->xSync(id, SQLITE_SYNC_FULL);


  if( isCorrupt ){
    sqlite3demo_superunlock_corrupt(id, corruptFileLock);
  }else{
    sqlite3demo_superunlock(pLock);
  }
  return rc;
}

/*
 ** Lock locations for shared-memory locks used by WAL mode.
 */
#ifndef SHM_BASE
# define SHM_BASE          120
# define SHM_WRITE         SHM_BASE
# define SHM_CHECKPOINT    (SHM_BASE+1)
# define SHM_RECOVER       (SHM_BASE+2)
# define SHM_READ_FIRST    (SHM_BASE+3)
# define SHM_READ_SIZE     5
#endif /* SHM_BASE */

/*
** This test only works for lock testing on unix/posix VFS.
** Adapted from tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
*/
static int unixLockstatePid(unixFile *pFile, pid_t pid, int *pLockstate){
  int hDb;        /* File descriptor for the open database file */
  int hShm = -1;  /* File descriptor for WAL shared-memory file */
  ssize_t got;    /* Bytes read from header */
  int isWal;                 /* True if in WAL mode */
  int nLock = 0;             /* Number of locks held */
  unsigned char aHdr[100];   /* Database header */
  
  assert(pLockstate);
  
  /* make sure we are dealing with a database file */
  hDb = pFile->h;
  if( hDb<0 ){
    *pLockstate = SQLITE_LOCKSTATE_ERROR;
    return SQLITE_ERROR;
  }
  assert( (strlen(SQLITE_FILE_HEADER)+1)==SQLITE_FILE_HEADER_LEN );
  got = pread(hDb, aHdr, 100, 0);
  if( got<0 ){
    *pLockstate = SQLITE_LOCKSTATE_ERROR;
    return SQLITE_ERROR;
  }
  if( got!=100 || memcmp(aHdr, SQLITE_FILE_HEADER, SQLITE_FILE_HEADER_LEN)!=0 ){
    *pLockstate = SQLITE_LOCKSTATE_NOTADB;
    return SQLITE_NOTADB;
  }
  
  /* First check for an exclusive lock */
  nLock += unixIsLocked(pid, hDb, F_RDLCK, SHARED_FIRST, SHARED_SIZE, "EXCLUSIVE");
  isWal = aHdr[18]==2;
  if( nLock==0 && isWal==0 ){
    /* Rollback mode */
    nLock += unixIsLocked(pid, hDb, F_WRLCK, PENDING_BYTE, SHARED_SIZE+2, "PENDING|RESERVED|SHARED");
  }
  if( nLock==0 && isWal!=0 ){
    /* lookup the file descriptor for the shared memory file if we have it open in this process */
    unixEnterMutex(); /* Because pFile->pInode is shared across threads */
    unixShmNode *pShmNode = pFile->pInode->pShmNode;
    if( pShmNode ){
      sqlite3_mutex_enter(pShmNode->mutex);
      
      hShm = pShmNode->h;
      if( hShm >= 0){
        if( unixIsLocked(pid, hShm, F_RDLCK, SHM_RECOVER, 1, "WAL-RECOVERY") ||
           unixIsLocked(pid, hShm, F_RDLCK, SHM_WRITE, 1, "WAL-WRITE") ){
          nLock = 1;
        }
      }
      
      sqlite3_mutex_leave(pShmNode->mutex);
    } 
    
    if( hShm<0 ){
      /* the shared memory file isn't open in this process space, open our own FD */
      char zShm[MAXPATHLEN];
      
      /* WAL mode */
      strlcpy(zShm, pFile->zPath, MAXPATHLEN);
      strlcat(zShm, "-shm", MAXPATHLEN);
      hShm = open(zShm, O_RDONLY, 0);
      if( hShm<0 ){
        *pLockstate = SQLITE_LOCKSTATE_OFF;
        unixLeaveMutex();
        return SQLITE_OK;
      }
      if( unixIsLocked(pid, hShm, F_RDLCK, SHM_RECOVER, 1, "WAL-RECOVERY") ||
         unixIsLocked(pid, hShm, F_RDLCK, SHM_WRITE, 1, "WAL-WRITE") ){
        nLock = 1;
      }
      close(hShm);
    }
    unixLeaveMutex();
  }
  if( nLock>0 ){
    *pLockstate = SQLITE_LOCKSTATE_ON;
  } else {
    *pLockstate = SQLITE_LOCKSTATE_OFF;
  }
  return SQLITE_OK;
}

#endif /* (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__) */



/*
** Here ends the implementation of all sqlite3_file methods.
**
********************** End sqlite3_file Methods *******************************
******************************************************************************/

Changes to src/os_win.c.

98
99
100
101
102
103
104
105
106

107
108
109
110
111
112
113
....
1272
1273
1274
1275
1276
1277
1278

1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297









1298
1299
1300
1301
1302
1303
1304
** portability layer.
*/
typedef struct winFile winFile;
struct winFile {
  const sqlite3_io_methods *pMethod; /*** Must be first ***/
  sqlite3_vfs *pVfs;      /* The VFS used to open this file */
  HANDLE h;               /* Handle for accessing the file */
  unsigned char locktype; /* Type of lock currently held on this file */
  short sharedLockByte;   /* Randomly chosen byte used as a shared lock */

  DWORD lastErrno;        /* The Windows errno from the last I/O error */
  DWORD sectorSize;       /* Sector size of the device file is on */
  winShm *pShm;           /* Instance of shared memory on this file */
  const char *zPath;      /* Full pathname of this file */
  int szChunk;            /* Chunk size configured by FCNTL_CHUNK_SIZE */
#if SQLITE_OS_WINCE
  WCHAR *zDeleteOnClose;  /* Name of file to delete when closing */
................................................................................
  return rc;
}

/*
** Control and query of the open file handle.
*/
static int winFileControl(sqlite3_file *id, int op, void *pArg){

  switch( op ){
    case SQLITE_FCNTL_LOCKSTATE: {
      *(int*)pArg = ((winFile*)id)->locktype;
      return SQLITE_OK;
    }
    case SQLITE_LAST_ERRNO: {
      *(int*)pArg = (int)((winFile*)id)->lastErrno;
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_CHUNK_SIZE: {
      ((winFile*)id)->szChunk = *(int *)pArg;
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_SIZE_HINT: {
      sqlite3_int64 sz = *(sqlite3_int64*)pArg;
      SimulateIOErrorBenign(1);
      winTruncate(id, sz);
      SimulateIOErrorBenign(0);
      return SQLITE_OK;









    }
    case SQLITE_FCNTL_SYNC_OMITTED: {
      return SQLITE_OK;
    }
  }
  return SQLITE_NOTFOUND;
}







|

>







 







>


|



|



|








>
>
>
>
>
>
>
>
>







98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
....
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
** portability layer.
*/
typedef struct winFile winFile;
struct winFile {
  const sqlite3_io_methods *pMethod; /*** Must be first ***/
  sqlite3_vfs *pVfs;      /* The VFS used to open this file */
  HANDLE h;               /* Handle for accessing the file */
  u8 locktype;            /* Type of lock currently held on this file */
  short sharedLockByte;   /* Randomly chosen byte used as a shared lock */
  u8 bPersistWal;         /* True to persist WAL files */
  DWORD lastErrno;        /* The Windows errno from the last I/O error */
  DWORD sectorSize;       /* Sector size of the device file is on */
  winShm *pShm;           /* Instance of shared memory on this file */
  const char *zPath;      /* Full pathname of this file */
  int szChunk;            /* Chunk size configured by FCNTL_CHUNK_SIZE */
#if SQLITE_OS_WINCE
  WCHAR *zDeleteOnClose;  /* Name of file to delete when closing */
................................................................................
  return rc;
}

/*
** Control and query of the open file handle.
*/
static int winFileControl(sqlite3_file *id, int op, void *pArg){
  winFile *pFile = (winFile*)id;
  switch( op ){
    case SQLITE_FCNTL_LOCKSTATE: {
      *(int*)pArg = pFile->locktype;
      return SQLITE_OK;
    }
    case SQLITE_LAST_ERRNO: {
      *(int*)pArg = (int)pFile->lastErrno;
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_CHUNK_SIZE: {
      pFile->szChunk = *(int *)pArg;
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_SIZE_HINT: {
      sqlite3_int64 sz = *(sqlite3_int64*)pArg;
      SimulateIOErrorBenign(1);
      winTruncate(id, sz);
      SimulateIOErrorBenign(0);
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_PERSIST_WAL: {
      int bPersist = *(int*)pArg;
      if( bPersist<0 ){
        *(int*)pArg = pFile->bPersistWal;
      }else{
        pFile->bPersistWal = bPersist!=0;
      }
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_SYNC_OMITTED: {
      return SQLITE_OK;
    }
  }
  return SQLITE_NOTFOUND;
}

Changes to src/pager.c.

6735
6736
6737
6738
6739
6740
6741
6742
6743
6744
6745
6746
6747
6748
6749
6750
6751
6752
6753

  /* Open the connection to the log file. If this operation fails, 
  ** (e.g. due to malloc() failure), return an error code.
  */
  if( rc==SQLITE_OK ){
#if SQLITE_ENABLE_DATA_PROTECTION
    rc = sqlite3WalOpen(pPager->pVfs, pPager->fd, pPager->zWal, pPager->exclusiveMode,
        pPager->journalSizeLimit, (pPager->vfsFlags & SQLITE_OPEN_FILEPROTECTION_MASK), 
        &pPager->pWal);
#else
    rc = sqlite3WalOpen(pPager->pVfs, pPager->fd, pPager->zWal, pPager->exclusiveMode,
        pPager->journalSizeLimit, 0, &pPager->pWal);
#endif
  }

  return rc;
}









|



|







6735
6736
6737
6738
6739
6740
6741
6742
6743
6744
6745
6746
6747
6748
6749
6750
6751
6752
6753

  /* Open the connection to the log file. If this operation fails, 
  ** (e.g. due to malloc() failure), return an error code.
  */
  if( rc==SQLITE_OK ){
#if SQLITE_ENABLE_DATA_PROTECTION
    rc = sqlite3WalOpen(pPager->pVfs, pPager->fd, pPager->zWal, pPager->exclusiveMode,
        pPager->journalSizeLimit, (pPager->vfsFlags & (SQLITE_OPEN_FILEPROTECTION_MASK | SQLITE_OPEN_READONLY)), 
        &pPager->pWal);
#else
    rc = sqlite3WalOpen(pPager->pVfs, pPager->fd, pPager->zWal, pPager->exclusiveMode,
        pPager->journalSizeLimit, (pPager->vfsFlags & SQLITE_OPEN_READONLY), &pPager->pWal);
#endif
  }

  return rc;
}


Changes to src/sqlite.h.in.

733
734
735
736
737
738
739















740
741
742
743
744
745
746
747
748
749





750
751
752
753
754
755
756
** when the database connection has [PRAGMA synchronous] set to OFF.)^
** Some specialized VFSes need this signal in order to operate correctly
** when [PRAGMA synchronous | PRAGMA synchronous=OFF] is set, but most 
** VFSes do not need this signal and should silently ignore this opcode.
** Applications should not call [sqlite3_file_control()] with this
** opcode as doing so may disrupt the operation of the specialized VFSes
** that do require it.  















*/
#define SQLITE_FCNTL_LOCKSTATE        1
#define SQLITE_GET_LOCKPROXYFILE      2
#define SQLITE_SET_LOCKPROXYFILE      3
#define SQLITE_LAST_ERRNO             4
#define SQLITE_FCNTL_SIZE_HINT        5
#define SQLITE_FCNTL_CHUNK_SIZE       6
#define SQLITE_FCNTL_FILE_POINTER     7
#define SQLITE_FCNTL_SYNC_OMITTED     8







/*
** CAPI3REF: Mutex Handle
**
** The mutex module within SQLite defines [sqlite3_mutex] to be an
** abstract type for a mutex object.  The SQLite core never looks
** at the internal representation of an [sqlite3_mutex].  It only







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

|
|
|
|
|
|
|
|
<
>
>
>
>
>







733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763

764
765
766
767
768
769
770
771
772
773
774
775
** when the database connection has [PRAGMA synchronous] set to OFF.)^
** Some specialized VFSes need this signal in order to operate correctly
** when [PRAGMA synchronous | PRAGMA synchronous=OFF] is set, but most 
** VFSes do not need this signal and should silently ignore this opcode.
** Applications should not call [sqlite3_file_control()] with this
** opcode as doing so may disrupt the operation of the specialized VFSes
** that do require it.  
**
** ^The [SQLITE_FCNTL_PERSIST_WAL] opcode is used to set or query the
** persistent [WAL | Write AHead Log] setting.  By default, the auxiliary
** write ahead log and shared memory files used for transaction control
** are automatically deleted when the latest connection to the database
** closes.  Setting persistent WAL mode causes those files to persist after
** close.  Persisting the files is useful when other processes that do not
** have write permission on the directory containing the database file want
** to read the database file, as the WAL and shared memory files must exist
** in order for the database to be readable.  The fourth parameter to
** [sqlite3_file_control()] for this opcode should be a pointer to an integer.
** That integer is 0 to disable persistent WAL mode or 1 to enable persistent
** WAL mode.  If the integer is -1, then it is overwritten with the current
** WAL persistence setting.
**
*/
#define SQLITE_FCNTL_LOCKSTATE          1
#define SQLITE_FCNTL_GET_LOCKPROXYFILE  2
#define SQLITE_FCNTL_SET_LOCKPROXYFILE  3
#define SQLITE_FCNTL_LAST_ERRNO         4
#define SQLITE_FCNTL_SIZE_HINT          5
#define SQLITE_FCNTL_CHUNK_SIZE         6
#define SQLITE_FCNTL_FILE_POINTER       7
#define SQLITE_FCNTL_SYNC_OMITTED       8

#define SQLITE_FCNTL_PERSIST_WAL       10
/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE      SQLITE_FCNTL_GET_LOCKPROXYFILE
#define SQLITE_SET_LOCKPROXYFILE      SQLITE_FCNTL_SET_LOCKPROXYFILE
#define SQLITE_LAST_ERRNO             SQLITE_FCNTL_LAST_ERRNO

/*
** CAPI3REF: Mutex Handle
**
** The mutex module within SQLite defines [sqlite3_mutex] to be an
** abstract type for a mutex object.  The SQLite core never looks
** at the internal representation of an [sqlite3_mutex].  It only

Changes to src/sqlite3_private.h.

23
24
25
26
27
28
29








30
31
32
33

34
35
36
37
38
39
40

41
42
43
**
** There is no support for identifying db files encrypted via SEE encryption
** currently.  Zero byte files are tested for sqlite locks, but if no sqlite 
** locks are present then SQLITE_LOCKSTATE_NOTADB is returned.
*/
extern int _sqlite3_lockstate(const char *path, pid_t pid);









/*
** Pass the SQLITE_TRUNCATE_DATABASE operation code to sqlite3_file_control() 
** to truncate a database and its associated journal file to zero length.
*/

#define SQLITE_TRUNCATE_DATABASE      101

/*
** Pass the SQLITE_REPLACE_DATABASE operation code to sqlite3_file_control() 
** and a sqlite3 pointer to another open database file to safely copy the 
** contents of that database file into the receiving database.
*/

#define SQLITE_REPLACE_DATABASE       102

#endif







>
>
>
>
>
>
>
>




>
|






>
|


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
**
** There is no support for identifying db files encrypted via SEE encryption
** currently.  Zero byte files are tested for sqlite locks, but if no sqlite 
** locks are present then SQLITE_LOCKSTATE_NOTADB is returned.
*/
extern int _sqlite3_lockstate(const char *path, pid_t pid);

/*
** Test an open database connection for sqlite locks held by a process ID,
** if a process has an open database connection this will avoid trashing file
** locks by re-using open file descriptors for the database file and support
** files (-shm)
*/
#define SQLITE_FCNTL_LOCKSTATE_PID          103

/*
** Pass the SQLITE_TRUNCATE_DATABASE operation code to sqlite3_file_control() 
** to truncate a database and its associated journal file to zero length.
*/
#define SQLITE_FCNTL_TRUNCATE_DATABASE      101
#define SQLITE_TRUNCATE_DATABASE            SQLITE_FCNTL_TRUNCATE_DATABASE

/*
** Pass the SQLITE_REPLACE_DATABASE operation code to sqlite3_file_control() 
** and a sqlite3 pointer to another open database file to safely copy the 
** contents of that database file into the receiving database.
*/
#define SQLITE_FCNTL_REPLACE_DATABASE       102
#define SQLITE_REPLACE_DATABASE             SQLITE_FCNTL_REPLACE_DATABASE

#endif

Changes to src/sqliteInt.h.

3246
3247
3248
3249
3250
3251
3252

























3253
#endif
#define MEMTYPE_HEAP       0x01  /* General heap allocations */
#define MEMTYPE_LOOKASIDE  0x02  /* Might have been lookaside memory */
#define MEMTYPE_SCRATCH    0x04  /* Scratch allocations */
#define MEMTYPE_PCACHE     0x08  /* Page cache allocations */
#define MEMTYPE_DB         0x10  /* Uses sqlite3DbMalloc, not sqlite_malloc */


























#endif /* _SQLITEINT_H_ */







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

3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
#endif
#define MEMTYPE_HEAP       0x01  /* General heap allocations */
#define MEMTYPE_LOOKASIDE  0x02  /* Might have been lookaside memory */
#define MEMTYPE_SCRATCH    0x04  /* Scratch allocations */
#define MEMTYPE_PCACHE     0x08  /* Page cache allocations */
#define MEMTYPE_DB         0x10  /* Uses sqlite3DbMalloc, not sqlite_malloc */


#if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__)

/*
** An instance of the following structure is used to hold the process ID
** and return-by-reference lockstate value.  The SQLITE_FCNTL_LOCKSTATE_PID
** requires the 4th argument to sqlite3_file_control to be a pointer to an
** instance of LockstatePID initialized with a LockstatePID.pid value equal
** to a process ID to be tested, or the special value SQLITE_LOCKSTATE_ANYPID
** The Lockstate.state value is always set to one of the following values
** when sqlite3_file_control returns:
** 
**   SQLITE_LOCKSTATE_OFF    no active sqlite file locks match the specified pid
**   SQLITE_LOCKSTATE_ON     active sqlite file locks match the specified pid
**   SQLITE_LOCKSTATE_NOTADB path points to a file that is not an sqlite db file
**   SQLITE_LOCKSTATE_ERROR  path was not vaild or was unreadable
*/
typedef struct LockstatePID LockstatePID;
struct LockstatePID {
  pid_t pid;                 /* Process ID to test */
  int state;                 /* The state of the lock (return value) */
};

#endif

#endif /* _SQLITEINT_H_ */

Changes to src/test1.c.

4986
4987
4988
4989
4990
4991
4992

4993
4994
4995
4996
4997
4998
4999
5000
5001
5002



5003
5004
5005
5006
5007
5008
5009
5010
....
5278
5279
5280
5281
5282
5283
5284

































5285
5286
5287
5288
5289
5290
5291
....
5990
5991
5992
5993
5994
5995
5996

5997
5998
5999
6000
6001
6002
6003
static int file_control_truncate_test(
  ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int objc,              /* Number of arguments */
  Tcl_Obj *CONST objv[]  /* Command arguments */
){
  sqlite3 *db;

  int rc;
  
  if( objc!=2 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"",
                     Tcl_GetStringFromObj(objv[0], 0), " DB", 0);
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
    return TCL_ERROR;
  }



  rc = sqlite3_file_control(db, NULL, SQLITE_TRUNCATE_DATABASE, 0);
  if( rc ){ 
    Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); 
    return TCL_ERROR; 
  }
  return TCL_OK;  
}

................................................................................
  }
#else
  Tcl_SetObjResult(interp, Tcl_NewIntObj(0)); 
#endif
  
  return TCL_OK;  
}


































/*
** tclcmd:   sqlite3_vfs_list
**
**   Return a tcl list containing the names of all registered vfs's.
*/
static int vfs_list(
................................................................................
     { "file_control_lockproxy_test", file_control_lockproxy_test,  0   },
#ifdef __APPLE__
     { "file_control_truncate_test", file_control_truncate_test,  0   },
     { "file_control_replace_test", file_control_replace_test,  0   },
#endif 
     { "file_control_chunksize_test", file_control_chunksize_test,  0   },
     { "file_control_sizehint_test", file_control_sizehint_test,  0   },

     { "sqlite3_vfs_list",           vfs_list,     0   },
     { "sqlite3_create_function_v2", test_create_function_v2, 0 },
     { "path_is_local",              path_is_local,  0   },
     { "path_is_dos",                path_is_dos,  0   },

     /* Functions from os.h */
#ifndef SQLITE_OMIT_UTF16







>


|

|





>
>
>
|







 







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







 







>







4986
4987
4988
4989
4990
4991
4992
4993
4994
4995
4996
4997
4998
4999
5000
5001
5002
5003
5004
5005
5006
5007
5008
5009
5010
5011
5012
5013
5014
....
5282
5283
5284
5285
5286
5287
5288
5289
5290
5291
5292
5293
5294
5295
5296
5297
5298
5299
5300
5301
5302
5303
5304
5305
5306
5307
5308
5309
5310
5311
5312
5313
5314
5315
5316
5317
5318
5319
5320
5321
5322
5323
5324
5325
5326
5327
5328
....
6027
6028
6029
6030
6031
6032
6033
6034
6035
6036
6037
6038
6039
6040
6041
static int file_control_truncate_test(
  ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int objc,              /* Number of arguments */
  Tcl_Obj *CONST objv[]  /* Command arguments */
){
  sqlite3 *db;
  int flags;
  int rc;
  
  if( objc!=3 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"",
                     Tcl_GetStringFromObj(objv[0], 0), " DB FLAGS", 0);
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
    return TCL_ERROR;
  }
  if( Tcl_GetIntFromObj(interp, objv[2], &flags) ){
    return TCL_ERROR;
  }
  rc = sqlite3_file_control(db, NULL, SQLITE_TRUNCATE_DATABASE, &flags);
  if( rc ){ 
    Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); 
    return TCL_ERROR; 
  }
  return TCL_OK;  
}

................................................................................
  }
#else
  Tcl_SetObjResult(interp, Tcl_NewIntObj(0)); 
#endif
  
  return TCL_OK;  
}

/*
** tclcmd:   file_control_persist_wal DB PERSIST-FLAG
**
** This TCL command runs the sqlite3_file_control interface with
** the SQLITE_FCNTL_PERSIST_WAL opcode.
*/
static int file_control_persist_wal(
  ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int objc,              /* Number of arguments */
  Tcl_Obj *CONST objv[]  /* Command arguments */
){
  sqlite3 *db;
  int rc;
  int bPersist;
  char z[100];
  
  if( objc!=3 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"",
                     Tcl_GetStringFromObj(objv[0], 0), " DB FLAG", 0);
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
    return TCL_ERROR;
  }
  if( Tcl_GetIntFromObj(interp, objv[2], &bPersist) ) return TCL_ERROR;
  rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_PERSIST_WAL, (void*)&bPersist);
  sqlite3_snprintf(sizeof(z), z, "%d %d", rc, bPersist);
  Tcl_AppendResult(interp, z, (char*)0);
  return TCL_OK;  
}


/*
** tclcmd:   sqlite3_vfs_list
**
**   Return a tcl list containing the names of all registered vfs's.
*/
static int vfs_list(
................................................................................
     { "file_control_lockproxy_test", file_control_lockproxy_test,  0   },
#ifdef __APPLE__
     { "file_control_truncate_test", file_control_truncate_test,  0   },
     { "file_control_replace_test", file_control_replace_test,  0   },
#endif 
     { "file_control_chunksize_test", file_control_chunksize_test,  0   },
     { "file_control_sizehint_test", file_control_sizehint_test,  0   },
     { "file_control_persist_wal",    file_control_persist_wal,     0   },
     { "sqlite3_vfs_list",           vfs_list,     0   },
     { "sqlite3_create_function_v2", test_create_function_v2, 0 },
     { "path_is_local",              path_is_local,  0   },
     { "path_is_dos",                path_is_dos,  0   },

     /* Functions from os.h */
#ifndef SQLITE_OMIT_UTF16

Changes to src/vdbeaux.c.

1504
1505
1506
1507
1508
1509
1510


1511
1512
1513
1514
1515
1516
1517
  if( pParse->explain && nMem<10 ){
    nMem = 10;
  }
  memset(zCsr, 0, zEnd-zCsr);
  zCsr += (zCsr - (u8*)0)&7;
  assert( EIGHT_BYTE_ALIGNMENT(zCsr) );



  /* Memory for registers, parameters, cursor, etc, is allocated in two
  ** passes.  On the first pass, we try to reuse unused space at the 
  ** end of the opcode array.  If we are unable to satisfy all memory
  ** requirements by reusing the opcode array tail, then the second
  ** pass will fill in the rest using a fresh allocation.  
  **
  ** This two-pass approach that reuses as much memory as possible from







>
>







1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
  if( pParse->explain && nMem<10 ){
    nMem = 10;
  }
  memset(zCsr, 0, zEnd-zCsr);
  zCsr += (zCsr - (u8*)0)&7;
  assert( EIGHT_BYTE_ALIGNMENT(zCsr) );

  p->expired = 0;
  
  /* Memory for registers, parameters, cursor, etc, is allocated in two
  ** passes.  On the first pass, we try to reuse unused space at the 
  ** end of the opcode array.  If we are unable to satisfy all memory
  ** requirements by reusing the opcode array tail, then the second
  ** pass will fill in the rest using a fresh allocation.  
  **
  ** This two-pass approach that reuses as much memory as possible from

Changes to src/wal.c.

1281
1282
1283
1284
1285
1286
1287



1288

1289
1290
1291
1292
1293
1294
1295
....
1801
1802
1803
1804
1805
1806
1807

1808
1809
1810
1811
1812
1813

1814
1815
1816
1817
1818
1819
1820
1821
....
1860
1861
1862
1863
1864
1865
1866



1867
1868
1869
1870
1871
1872
1873
....
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
  pRet->pDbFd = pDbFd;
  pRet->readLock = -1;
  pRet->mxWalSize = mxWalSize;
  pRet->zWalName = zWalName;
  pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE);

  /* Open file handle on the write-ahead log file. */



  vfsFlags = flags | (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL);

  rc = sqlite3OsOpen(pVfs, zWalName, pRet->pWalFd, vfsFlags, &vfsFlags);
  if( rc==SQLITE_OK && vfsFlags&SQLITE_OPEN_READONLY ){
    pRet->readOnly = WAL_RDONLY;
  }

  if( rc!=SQLITE_OK ){
    walIndexClose(pRet, 0);
................................................................................
    ** the database. In this case checkpoint the database and unlink both
    ** the wal and wal-index files.
    **
    ** The EXCLUSIVE lock is not released before returning.
    */
    rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE);
    if( rc==SQLITE_OK ){

      if( pWal->exclusiveMode==WAL_NORMAL_MODE ){
        pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
      }
      rc = sqlite3WalCheckpoint(
          pWal, SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0
      );

      if( rc==SQLITE_OK ){
        isDelete = 1;
      }
    }

    walIndexClose(pWal, isDelete);
    sqlite3OsClose(pWal->pWalFd);
    if( isDelete ){
................................................................................
  **
  ** There are two copies of the header at the beginning of the wal-index.
  ** When reading, read [0] first then [1].  Writes are in the reverse order.
  ** Memory barriers are used to prevent the compiler or the hardware from
  ** reordering the reads and writes.
  */
  aHdr = walIndexHdr(pWal);



  memcpy(&h1, (void *)&aHdr[0], sizeof(h1));
  walShmBarrier(pWal);
  memcpy(&h2, (void *)&aHdr[1], sizeof(h2));

  if( memcmp(&h1, &h2, sizeof(h1))!=0 ){
    return 1;   /* Dirty read */
  }  
................................................................................
  ** is more of a scheduler yield than an actual delay.  But on the 10th
  ** an subsequent retries, the delays start becoming longer and longer, 
  ** so that on the 100th (and last) RETRY we delay for 21 milliseconds.
  ** The total delay time before giving up is less than 1 second.
  */
  if( cnt>5 ){
    int nDelay = 1;                      /* Pause time in microseconds */
    if( cnt>100 ){
      VVA_ONLY( pWal->lockError = 1; )
      return SQLITE_PROTOCOL;
    }
    if( cnt>=10 ) nDelay = (cnt-9)*238;  /* Max delay 21ms. Total delay 996ms */
    sqlite3OsSleep(pWal->pVfs, nDelay);
  }








>
>
>
|
>







 







>






>
|







 







>
>
>







 







|







1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
....
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
....
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
....
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
  pRet->pDbFd = pDbFd;
  pRet->readLock = -1;
  pRet->mxWalSize = mxWalSize;
  pRet->zWalName = zWalName;
  pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE);

  /* Open file handle on the write-ahead log file. */
  if( flags&SQLITE_OPEN_READONLY ){
    vfsFlags = flags | SQLITE_OPEN_WAL;
  } else {
    vfsFlags = flags | (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL);
  }
  rc = sqlite3OsOpen(pVfs, zWalName, pRet->pWalFd, vfsFlags, &vfsFlags);
  if( rc==SQLITE_OK && vfsFlags&SQLITE_OPEN_READONLY ){
    pRet->readOnly = WAL_RDONLY;
  }

  if( rc!=SQLITE_OK ){
    walIndexClose(pRet, 0);
................................................................................
    ** the database. In this case checkpoint the database and unlink both
    ** the wal and wal-index files.
    **
    ** The EXCLUSIVE lock is not released before returning.
    */
    rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE);
    if( rc==SQLITE_OK ){
      int bPersistWal = -1;
      if( pWal->exclusiveMode==WAL_NORMAL_MODE ){
        pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
      }
      rc = sqlite3WalCheckpoint(
          pWal, SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0
      );
      sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_PERSIST_WAL, &bPersistWal);
      if( rc==SQLITE_OK && bPersistWal!=1 ){
        isDelete = 1;
      }
    }

    walIndexClose(pWal, isDelete);
    sqlite3OsClose(pWal->pWalFd);
    if( isDelete ){
................................................................................
  **
  ** There are two copies of the header at the beginning of the wal-index.
  ** When reading, read [0] first then [1].  Writes are in the reverse order.
  ** Memory barriers are used to prevent the compiler or the hardware from
  ** reordering the reads and writes.
  */
  aHdr = walIndexHdr(pWal);
  if( aHdr==NULL ){
    return 1; /* Shouldn't be getting NULL from walIndexHdr, but we are */
  }
  memcpy(&h1, (void *)&aHdr[0], sizeof(h1));
  walShmBarrier(pWal);
  memcpy(&h2, (void *)&aHdr[1], sizeof(h2));

  if( memcmp(&h1, &h2, sizeof(h1))!=0 ){
    return 1;   /* Dirty read */
  }  
................................................................................
  ** is more of a scheduler yield than an actual delay.  But on the 10th
  ** an subsequent retries, the delays start becoming longer and longer, 
  ** so that on the 100th (and last) RETRY we delay for 21 milliseconds.
  ** The total delay time before giving up is less than 1 second.
  */
  if( cnt>5 ){
    int nDelay = 1;                      /* Pause time in microseconds */
    if( cnt>500 ){
      VVA_ONLY( pWal->lockError = 1; )
      return SQLITE_PROTOCOL;
    }
    if( cnt>=10 ) nDelay = (cnt-9)*238;  /* Max delay 21ms. Total delay 996ms */
    sqlite3OsSleep(pWal->pVfs, nDelay);
  }

Added test/walpersist.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
63
64
65
66
67
68
# 2011 July 26
#
# 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 tests for using WAL with persistent WAL file mode.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/lock_common.tcl
set ::testprefix walpersist

do_test walpersist-1.0 {
  db eval {
    PRAGMA journal_mode=WAL;
    CREATE TABLE t1(a);
    INSERT INTO t1 VALUES(randomblob(5000));
  }
  file exists test.db-wal
} {1}
do_test walpersist-1.1 {
  file exists test.db-shm
} {1}
do_test walpersist-1.2 {
  db close
  list [file exists test.db] [file exists test.db-wal] [file exists test.db-shm]
} {1 0 0}
do_test walpersist-1.3 {
  sqlite3 db test.db
  db eval {SELECT length(a) FROM t1}
} {5000}
do_test walpersist-1.4 {
  list [file exists test.db] [file exists test.db-wal] [file exists test.db-shm]
} {1 1 1}
do_test walpersist-1.5 {
  file_control_persist_wal db -1
} {0 0}
do_test walpersist-1.6 {
  file_control_persist_wal db 1
} {0 1}
do_test walpersist-1.7 {
  file_control_persist_wal db -1
} {0 1}
do_test walpersist-1.8 {
  file_control_persist_wal db 0
} {0 0}
do_test walpersist-1.9 {
  file_control_persist_wal db -1
} {0 0}
do_test walpersist-1.10 {
  file_control_persist_wal db 1
} {0 1}
do_test walpersist-1.11 {
  db close
  list [file exists test.db] [file exists test.db-wal] [file exists test.db-shm]
} {1 1 1}

  


finish_test