Fossil SCM

Merge from trunk.

jan 2011-03-29 19:28 jan-clientcert merge
Commit 2ac7b3e140683910a8618b47010352fe3c5943d2
+25 -25
--- src/add.c
+++ src/add.c
@@ -266,10 +266,12 @@
266266
int isDir;
267267
268268
zName = mprintf("%/", g.argv[i]);
269269
isDir = file_isdir(zName);
270270
if( isDir==1 ){
271
+ int sz = strlen(zName);
272
+ if( sz>0 && zName[sz-1]=='/' ){ zName[sz-1] = 0; }
271273
add_directory(zName, vid, &repo, pIgnore);
272274
}else if( isDir==0 ){
273275
fossil_fatal("not found: %s", zName);
274276
}else if( access(zName, R_OK) ){
275277
fossil_fatal("cannot open %s", zName);
@@ -280,10 +282,29 @@
280282
}
281283
if( pIgnore ) db_finalize(pIgnore);
282284
db_end_transaction(0);
283285
}
284286
287
+
288
+/*
289
+** Unmangage a single file.
290
+*/
291
+void delete_one_file(const char *zName){
292
+ char *zPath;
293
+ Blob pathname;
294
+ file_tree_name(zName, &pathname, 1);
295
+ zPath = blob_str(&pathname);
296
+ if( !db_exists(
297
+ "SELECT 1 FROM vfile WHERE pathname=%Q AND NOT deleted", zPath) ){
298
+ fossil_fatal("not in the repository: %s", zName);
299
+ }else{
300
+ db_multi_exec("UPDATE vfile SET deleted=1 WHERE pathname=%Q", zPath);
301
+ printf("DELETED %s\n", zPath);
302
+ }
303
+ blob_reset(&pathname);
304
+}
305
+
285306
/*
286307
** Remove all contents of zDir
287308
*/
288309
void del_directory_content(const char *zDir){
289310
DIR *d;
@@ -306,23 +327,11 @@
306327
blob_appendf(&path, "/%s", pEntry->d_name);
307328
zPath = blob_str(&path);
308329
if( file_isdir(zPath)==1 ){
309330
del_directory_content(zPath);
310331
}else if( file_isfile(zPath) ){
311
- char *zFilePath;
312
- Blob pathname;
313
- file_tree_name(zPath, &pathname, 1);
314
- zFilePath = blob_str(&pathname);
315
- if( !db_exists(
316
- "SELECT 1 FROM vfile WHERE pathname=%Q AND NOT deleted", zFilePath)
317
- ){
318
- printf("SKIPPED %s\n", zPath);
319
- }else{
320
- db_multi_exec("UPDATE vfile SET deleted=1 WHERE pathname=%Q", zPath);
321
- printf("DELETED %s\n", zPath);
322
- }
323
- blob_reset(&pathname);
332
+ delete_one_file(zPath);
324333
}
325334
blob_resize(&path, origSize);
326335
}
327336
closedir(d);
328337
}
@@ -355,24 +364,15 @@
355364
for(i=2; i<g.argc; i++){
356365
char *zName;
357366
358367
zName = mprintf("%/", g.argv[i]);
359368
if( file_isdir(zName) == 1 ){
369
+ int sz = strlen(zName);
370
+ if( sz>0 && zName[sz-1]=='/' ){ zName[sz-1] = 0; }
360371
del_directory_content(zName);
361372
} else {
362
- char *zPath;
363
- Blob pathname;
364
- file_tree_name(zName, &pathname, 1);
365
- zPath = blob_str(&pathname);
366
- if( !db_exists(
367
- "SELECT 1 FROM vfile WHERE pathname=%Q AND NOT deleted", zPath) ){
368
- fossil_fatal("not in the repository: %s", zName);
369
- }else{
370
- db_multi_exec("UPDATE vfile SET deleted=1 WHERE pathname=%Q", zPath);
371
- printf("DELETED %s\n", zPath);
372
- }
373
- blob_reset(&pathname);
373
+ delete_one_file(zName);
374374
}
375375
free(zName);
376376
}
377377
db_multi_exec("DELETE FROM vfile WHERE deleted AND rid=0");
378378
db_end_transaction(0);
379379
--- src/add.c
+++ src/add.c
@@ -266,10 +266,12 @@
266 int isDir;
267
268 zName = mprintf("%/", g.argv[i]);
269 isDir = file_isdir(zName);
270 if( isDir==1 ){
 
 
271 add_directory(zName, vid, &repo, pIgnore);
272 }else if( isDir==0 ){
273 fossil_fatal("not found: %s", zName);
274 }else if( access(zName, R_OK) ){
275 fossil_fatal("cannot open %s", zName);
@@ -280,10 +282,29 @@
280 }
281 if( pIgnore ) db_finalize(pIgnore);
282 db_end_transaction(0);
283 }
284
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
285 /*
286 ** Remove all contents of zDir
287 */
288 void del_directory_content(const char *zDir){
289 DIR *d;
@@ -306,23 +327,11 @@
306 blob_appendf(&path, "/%s", pEntry->d_name);
307 zPath = blob_str(&path);
308 if( file_isdir(zPath)==1 ){
309 del_directory_content(zPath);
310 }else if( file_isfile(zPath) ){
311 char *zFilePath;
312 Blob pathname;
313 file_tree_name(zPath, &pathname, 1);
314 zFilePath = blob_str(&pathname);
315 if( !db_exists(
316 "SELECT 1 FROM vfile WHERE pathname=%Q AND NOT deleted", zFilePath)
317 ){
318 printf("SKIPPED %s\n", zPath);
319 }else{
320 db_multi_exec("UPDATE vfile SET deleted=1 WHERE pathname=%Q", zPath);
321 printf("DELETED %s\n", zPath);
322 }
323 blob_reset(&pathname);
324 }
325 blob_resize(&path, origSize);
326 }
327 closedir(d);
328 }
@@ -355,24 +364,15 @@
355 for(i=2; i<g.argc; i++){
356 char *zName;
357
358 zName = mprintf("%/", g.argv[i]);
359 if( file_isdir(zName) == 1 ){
 
 
360 del_directory_content(zName);
361 } else {
362 char *zPath;
363 Blob pathname;
364 file_tree_name(zName, &pathname, 1);
365 zPath = blob_str(&pathname);
366 if( !db_exists(
367 "SELECT 1 FROM vfile WHERE pathname=%Q AND NOT deleted", zPath) ){
368 fossil_fatal("not in the repository: %s", zName);
369 }else{
370 db_multi_exec("UPDATE vfile SET deleted=1 WHERE pathname=%Q", zPath);
371 printf("DELETED %s\n", zPath);
372 }
373 blob_reset(&pathname);
374 }
375 free(zName);
376 }
377 db_multi_exec("DELETE FROM vfile WHERE deleted AND rid=0");
378 db_end_transaction(0);
379
--- src/add.c
+++ src/add.c
@@ -266,10 +266,12 @@
266 int isDir;
267
268 zName = mprintf("%/", g.argv[i]);
269 isDir = file_isdir(zName);
270 if( isDir==1 ){
271 int sz = strlen(zName);
272 if( sz>0 && zName[sz-1]=='/' ){ zName[sz-1] = 0; }
273 add_directory(zName, vid, &repo, pIgnore);
274 }else if( isDir==0 ){
275 fossil_fatal("not found: %s", zName);
276 }else if( access(zName, R_OK) ){
277 fossil_fatal("cannot open %s", zName);
@@ -280,10 +282,29 @@
282 }
283 if( pIgnore ) db_finalize(pIgnore);
284 db_end_transaction(0);
285 }
286
287
288 /*
289 ** Unmangage a single file.
290 */
291 void delete_one_file(const char *zName){
292 char *zPath;
293 Blob pathname;
294 file_tree_name(zName, &pathname, 1);
295 zPath = blob_str(&pathname);
296 if( !db_exists(
297 "SELECT 1 FROM vfile WHERE pathname=%Q AND NOT deleted", zPath) ){
298 fossil_fatal("not in the repository: %s", zName);
299 }else{
300 db_multi_exec("UPDATE vfile SET deleted=1 WHERE pathname=%Q", zPath);
301 printf("DELETED %s\n", zPath);
302 }
303 blob_reset(&pathname);
304 }
305
306 /*
307 ** Remove all contents of zDir
308 */
309 void del_directory_content(const char *zDir){
310 DIR *d;
@@ -306,23 +327,11 @@
327 blob_appendf(&path, "/%s", pEntry->d_name);
328 zPath = blob_str(&path);
329 if( file_isdir(zPath)==1 ){
330 del_directory_content(zPath);
331 }else if( file_isfile(zPath) ){
332 delete_one_file(zPath);
 
 
 
 
 
 
 
 
 
 
 
 
333 }
334 blob_resize(&path, origSize);
335 }
336 closedir(d);
337 }
@@ -355,24 +364,15 @@
364 for(i=2; i<g.argc; i++){
365 char *zName;
366
367 zName = mprintf("%/", g.argv[i]);
368 if( file_isdir(zName) == 1 ){
369 int sz = strlen(zName);
370 if( sz>0 && zName[sz-1]=='/' ){ zName[sz-1] = 0; }
371 del_directory_content(zName);
372 } else {
373 delete_one_file(zName);
 
 
 
 
 
 
 
 
 
 
 
374 }
375 free(zName);
376 }
377 db_multi_exec("DELETE FROM vfile WHERE deleted AND rid=0");
378 db_end_transaction(0);
379
+12 -318
--- src/bisect.c
+++ src/bisect.c
@@ -21,198 +21,23 @@
2121
*/
2222
#include "config.h"
2323
#include "bisect.h"
2424
#include <assert.h>
2525
26
-#if INTERFACE
27
-/* Nodes for the shortest path algorithm.
28
-*/
29
-struct BisectNode {
30
- int rid; /* ID for this node */
31
- int fromIsParent; /* True if pFrom is the parent of rid */
32
- BisectNode *pFrom; /* Node we came from */
33
- union {
34
- BisectNode *pPeer; /* List of nodes of the same generation */
35
- BisectNode *pTo; /* Next on path from beginning to end */
36
- } u;
37
- BisectNode *pAll; /* List of all nodes */
38
-};
39
-#endif
40
-
4126
/*
4227
** Local variables for this module
4328
*/
4429
static struct {
45
- BisectNode *pCurrent; /* Current generation of nodes */
46
- BisectNode *pAll; /* All nodes */
47
- Bag seen; /* Nodes seen before */
4830
int bad; /* The bad version */
4931
int good; /* The good version */
50
- int nStep; /* Number of steps from good to bad */
51
- BisectNode *pStart; /* Earliest node (bad) */
52
- BisectNode *pEnd; /* Most recent (good) */
5332
} bisect;
5433
55
-/*
56
-** Create a new node
57
-*/
58
-static BisectNode *bisect_new_node(int rid, BisectNode *pFrom, int isParent){
59
- BisectNode *p;
60
-
61
- p = fossil_malloc( sizeof(*p) );
62
- p->rid = rid;
63
- p->fromIsParent = isParent;
64
- p->pFrom = pFrom;
65
- p->u.pPeer = bisect.pCurrent;
66
- bisect.pCurrent = p;
67
- p->pAll = bisect.pAll;
68
- bisect.pAll = p;
69
- bisect.pEnd = p;
70
- bag_insert(&bisect.seen, rid);
71
- return p;
72
-}
73
-
74
-/*
75
-** Reset memory used by the shortest path algorithm.
76
-*/
77
-void bisect_reset(void){
78
- BisectNode *p;
79
- while( bisect.pAll ){
80
- p = bisect.pAll;
81
- bisect.pAll = p->pAll;
82
- fossil_free(p);
83
- }
84
- bag_clear(&bisect.seen);
85
- bisect.pCurrent = 0;
86
- bisect.pAll = 0;
87
- bisect.pEnd = 0;
88
- bisect.nStep = 0;
89
-}
90
-
91
-/*
92
-** Compute the shortest path from iFrom to iTo
93
-**
94
-** If directOnly is true, then use only the "primary" links from parent to
95
-** child. In other words, ignore merges.
96
-*/
97
-BisectNode *bisect_shortest_path(int iFrom, int iTo, int directOnly){
98
- Stmt s;
99
- BisectNode *pPrev;
100
- BisectNode *p;
101
-
102
- bisect_reset();
103
- bisect.pStart = bisect_new_node(iFrom, 0, 0);
104
- if( iTo==iFrom ) return bisect.pStart;
105
- if( directOnly ){
106
- db_prepare(&s,
107
- "SELECT cid, 1 FROM plink WHERE pid=:pid AND isprim "
108
- "UNION ALL "
109
- "SELECT pid, 0 FROM plink WHERE cid=:pid AND isprim"
110
- );
111
- }else{
112
- db_prepare(&s,
113
- "SELECT cid, 1 FROM plink WHERE pid=:pid "
114
- "UNION ALL "
115
- "SELECT pid, 0 FROM plink WHERE cid=:pid"
116
- );
117
- }
118
- while( bisect.pCurrent ){
119
- bisect.nStep++;
120
- pPrev = bisect.pCurrent;
121
- bisect.pCurrent = 0;
122
- while( pPrev ){
123
- db_bind_int(&s, ":pid", pPrev->rid);
124
- while( db_step(&s)==SQLITE_ROW ){
125
- int cid = db_column_int(&s, 0);
126
- int isParent = db_column_int(&s, 1);
127
- if( bag_find(&bisect.seen, cid) ) continue;
128
- p = bisect_new_node(cid, pPrev, isParent);
129
- if( cid==iTo ){
130
- db_finalize(&s);
131
- return p;
132
- }
133
- }
134
- db_reset(&s);
135
- pPrev = pPrev->u.pPeer;
136
- }
137
- }
138
- bisect_reset();
139
- return 0;
140
-}
141
-
142
-/*
143
-** Construct the path from bisect.pStart to bisect.pEnd in the u.pTo fields.
144
-*/
145
-BisectNode *bisect_reverse_path(void){
146
- BisectNode *p;
147
- for(p=bisect.pEnd; p && p->pFrom; p = p->pFrom){
148
- p->pFrom->u.pTo = p;
149
- }
150
- bisect.pEnd->u.pTo = 0;
151
- assert( p==bisect.pStart );
152
- return p;
153
-}
154
-
155
-/*
156
-** COMMAND: test-shortest-path
157
-**
158
-** Usage: %fossil test-shortest-path ?--no-merge? VERSION1 VERSION2
159
-**
160
-** Report the shortest path between two checkins. If the --no-merge flag
161
-** is used, follow only direct parent-child paths and omit merge links.
162
-*/
163
-void shortest_path_test_cmd(void){
164
- int iFrom;
165
- int iTo;
166
- BisectNode *p;
167
- int n;
168
- int directOnly;
169
-
170
- db_find_and_open_repository(0,0);
171
- directOnly = find_option("no-merge",0,0)!=0;
172
- if( g.argc!=4 ) usage("VERSION1 VERSION2");
173
- iFrom = name_to_rid(g.argv[2]);
174
- iTo = name_to_rid(g.argv[3]);
175
- p = bisect_shortest_path(iFrom, iTo, directOnly);
176
- if( p==0 ){
177
- fossil_fatal("no path from %s to %s", g.argv[1], g.argv[2]);
178
- }
179
- bisect_reverse_path();
180
- for(n=1, p=bisect.pStart; p; p=p->u.pTo, n++){
181
- char *z;
182
- z = db_text(0,
183
- "SELECT substr(uuid,1,12) || ' ' || datetime(mtime)"
184
- " FROM blob, event"
185
- " WHERE blob.rid=%d AND event.objid=%d AND event.type='ci'",
186
- p->rid, p->rid);
187
- printf("%4d: %s", n, z);
188
- fossil_free(z);
189
- if( p->u.pTo ){
190
- printf(" is a %s of\n", p->u.pTo->fromIsParent ? "parent" : "child");
191
- }else{
192
- printf("\n");
193
- }
194
- }
195
-}
196
-
197
-/*
198
-** WEBPAGE: path
199
-**
200
-** example: /path?from=trunk&to=experimental&nomerge
201
-**
202
-** Show a timeline of all changes along a path between two versions.
203
-*/
204
-void path_page(void){
205
- login_check_credentials();
206
- if( !g.okRead ){ login_needed(); return; }
207
-}
208
-
20934
/*
21035
** Find the shortest path between bad and good.
21136
*/
212
-static BisectNode *bisect_path(void){
213
- BisectNode *p;
37
+void bisect_path(void){
38
+ PathNode *p;
21439
bisect.bad = db_lget_int("bisect-bad", 0);
21540
if( bisect.bad==0 ){
21641
bisect.bad = db_int(0, "SELECT cid FROM plink ORDER BY mtime DESC LIMIT 1");
21742
db_lset_int("bisect-bad", bisect.bad);
21843
}
@@ -219,21 +44,18 @@
21944
bisect.good = db_lget_int("bisect-good", 0);
22045
if( bisect.good==0 ){
22146
bisect.good = db_int(0,"SELECT pid FROM plink ORDER BY mtime LIMIT 1");
22247
db_lset_int("bisect-good", bisect.good);
22348
}
224
- p = bisect_shortest_path(bisect.good, bisect.bad, 0);
49
+ p = path_shortest(bisect.good, bisect.bad, 0);
22550
if( p==0 ){
22651
char *zBad = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", bisect.bad);
22752
char *zGood = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", bisect.good);
22853
fossil_fatal("no path from good ([%S]) to bad ([%S]) or back",
22954
zGood, zBad);
23055
}
231
- return p;
23256
}
233
-
234
-
23557
23658
/*
23759
** COMMAND: bisect
23860
**
23961
** Usage: %fossil bisect SUBCOMMAND ...
@@ -286,19 +108,18 @@
286108
}else{
287109
ridGood = name_to_rid(g.argv[3]);
288110
}
289111
db_lset_int("bisect-good", ridGood);
290112
}else if( memcmp(zCmd, "next", n)==0 ){
291
- BisectNode *p;
292
- int n;
113
+ PathNode *pMid;
293114
bisect_path();
294
- if( bisect.nStep<2 ){
115
+ pMid = path_midpoint();
116
+ if( pMid==0 ){
295117
fossil_fatal("bisect is done - there are no more intermediate versions");
296118
}
297
- for(p=bisect.pEnd, n=0; p && n<bisect.nStep/2; p=p->pFrom, n++){}
298119
g.argv[1] = "update";
299
- g.argv[2] = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", p->rid);
120
+ g.argv[2] = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", pMid->rid);
300121
g.argc = 3;
301122
g.fNoSync = 1;
302123
update_cmd();
303124
}else if( memcmp(zCmd, "reset", n)==0 ){
304125
db_multi_exec(
@@ -306,162 +127,35 @@
306127
" SELECT 'bisect-good', pid FROM plink ORDER BY mtime LIMIT 1;"
307128
"REPLACE INTO vvar(name, value) "
308129
" SELECT 'bisect-bad', cid FROM plink ORDER BY mtime DESC LIMIT 1;"
309130
);
310131
}else if( memcmp(zCmd, "vlist", n)==0 ){
311
- BisectNode *p;
132
+ PathNode *p;
312133
int vid = db_lget_int("checkout", 0);
313134
int n;
314135
Stmt s;
136
+ int nStep;
315137
bisect_path();
316138
db_prepare(&s, "SELECT substr(blob.uuid,1,20) || ' ' || "
317139
" datetime(event.mtime) FROM blob, event"
318140
" WHERE blob.rid=:rid AND event.objid=:rid"
319141
" AND event.type='ci'");
320
- for(p=bisect.pEnd, n=0; p; p=p->pFrom, n++){
142
+ nStep = path_length();
143
+ for(p=path_last(), n=0; p; p=p->pFrom, n++){
321144
const char *z;
322145
db_bind_int(&s, ":rid", p->rid);
323146
if( db_step(&s)==SQLITE_ROW ){
324147
z = db_column_text(&s, 0);
325148
printf("%s", z);
326149
if( p->rid==bisect.good ) printf(" GOOD");
327150
if( p->rid==bisect.bad ) printf(" BAD");
328151
if( p->rid==vid ) printf(" CURRENT");
329
- if( bisect.nStep>1 && n==bisect.nStep/2 ) printf(" NEXT");
152
+ if( nStep>1 && n==nStep/2 ) printf(" NEXT");
330153
printf("\n");
331154
}
332155
db_reset(&s);
333156
}
334157
db_finalize(&s);
335158
}else{
336159
usage("bad|good|next|reset|vlist ...");
337160
}
338161
}
339
-
340
-/*
341
-** A record of a file rename operation.
342
-*/
343
-typedef struct NameChange NameChange;
344
-struct NameChange {
345
- int origName; /* Original name of file */
346
- int curName; /* Current name of the file */
347
- int newName; /* Name of file in next version */
348
- NameChange *pNext; /* List of all name changes */
349
-};
350
-
351
-/*
352
-** Compute all file name changes that occur going from checkin iFrom
353
-** to checkin iTo.
354
-**
355
-** The number of name changes is written into *pnChng. For each name
356
-** change, two integers are allocated for *piChng. The first is the
357
-** filename.fnid for the original name and the second is for new name.
358
-** Space to hold *piChng is obtained from fossil_malloc() and should
359
-** be released by the caller.
360
-**
361
-** This routine really has nothing to do with bisection. It is located
362
-** in this bisect.c module in order to leverage some of the bisect
363
-** infrastructure.
364
-*/
365
-void find_filename_changes(
366
- int iFrom,
367
- int iTo,
368
- int *pnChng,
369
- int **aiChng
370
-){
371
- BisectNode *p; /* For looping over path from iFrom to iTo */
372
- NameChange *pAll = 0; /* List of all name changes seen so far */
373
- NameChange *pChng; /* For looping through the name change list */
374
- int nChng = 0; /* Number of files whose names have changed */
375
- int *aChng; /* Two integers per name change */
376
- int i; /* Loop counter */
377
- Stmt q1; /* Query of name changes */
378
-
379
- *pnChng = 0;
380
- *aiChng = 0;
381
- bisect_reset();
382
- p = bisect_shortest_path(iFrom, iTo, 0);
383
- if( p==0 ) return;
384
- bisect_reverse_path();
385
- db_prepare(&q1,
386
- "SELECT pfnid, fnid FROM mlink WHERE mid=:mid AND pfnid>0"
387
- );
388
- for(p=bisect.pStart; p; p=p->u.pTo){
389
- int fnid, pfnid;
390
- if( !p->fromIsParent && (p->u.pTo==0 || p->u.pTo->fromIsParent) ){
391
- /* Skip nodes where the parent is not on the path */
392
- continue;
393
- }
394
- db_bind_int(&q1, ":mid", p->rid);
395
- while( db_step(&q1)==SQLITE_ROW ){
396
- if( p->fromIsParent ){
397
- fnid = db_column_int(&q1, 1);
398
- pfnid = db_column_int(&q1, 0);
399
- }else{
400
- fnid = db_column_int(&q1, 0);
401
- pfnid = db_column_int(&q1, 1);
402
- }
403
- for(pChng=pAll; pChng; pChng=pChng->pNext){
404
- if( pChng->curName==pfnid ){
405
- pChng->newName = fnid;
406
- break;
407
- }
408
- }
409
- if( pChng==0 ){
410
- pChng = fossil_malloc( sizeof(*pChng) );
411
- pChng->pNext = pAll;
412
- pAll = pChng;
413
- pChng->origName = pfnid;
414
- pChng->curName = pfnid;
415
- pChng->newName = fnid;
416
- nChng++;
417
- }
418
- }
419
- for(pChng=pAll; pChng; pChng=pChng->pNext) pChng->curName = pChng->newName;
420
- db_reset(&q1);
421
- }
422
- db_finalize(&q1);
423
- if( nChng ){
424
- *pnChng = nChng;
425
- aChng = *aiChng = fossil_malloc( nChng*2*sizeof(int) );
426
- for(pChng=pAll, i=0; pChng; pChng=pChng->pNext, i+=2){
427
- aChng[i] = pChng->origName;
428
- aChng[i+1] = pChng->newName;
429
- }
430
- while( pAll ){
431
- pChng = pAll;
432
- pAll = pAll->pNext;
433
- fossil_free(pChng);
434
- }
435
- }
436
-}
437
-
438
-/*
439
-** COMMAND: test-name-changes
440
-**
441
-** Usage: %fossil test-name-changes VERSION1 VERSION2
442
-**
443
-** Show all filename changes that occur going from VERSION1 to VERSION2
444
-*/
445
-void test_name_change(void){
446
- int iFrom;
447
- int iTo;
448
- int *aChng;
449
- int nChng;
450
- int i;
451
-
452
- db_find_and_open_repository(0,0);
453
- if( g.argc!=4 ) usage("VERSION1 VERSION2");
454
- iFrom = name_to_rid(g.argv[2]);
455
- iTo = name_to_rid(g.argv[3]);
456
- find_filename_changes(iFrom, iTo, &nChng, &aChng);
457
- for(i=0; i<nChng; i++){
458
- char *zFrom, *zTo;
459
-
460
- zFrom = db_text(0, "SELECT name FROM filename WHERE fnid=%d", aChng[i*2]);
461
- zTo = db_text(0, "SELECT name FROM filename WHERE fnid=%d", aChng[i*2+1]);
462
- printf("[%s] -> [%s]\n", zFrom, zTo);
463
- fossil_free(zFrom);
464
- fossil_free(zTo);
465
- }
466
- fossil_free(aChng);
467
-}
468162
--- src/bisect.c
+++ src/bisect.c
@@ -21,198 +21,23 @@
21 */
22 #include "config.h"
23 #include "bisect.h"
24 #include <assert.h>
25
26 #if INTERFACE
27 /* Nodes for the shortest path algorithm.
28 */
29 struct BisectNode {
30 int rid; /* ID for this node */
31 int fromIsParent; /* True if pFrom is the parent of rid */
32 BisectNode *pFrom; /* Node we came from */
33 union {
34 BisectNode *pPeer; /* List of nodes of the same generation */
35 BisectNode *pTo; /* Next on path from beginning to end */
36 } u;
37 BisectNode *pAll; /* List of all nodes */
38 };
39 #endif
40
41 /*
42 ** Local variables for this module
43 */
44 static struct {
45 BisectNode *pCurrent; /* Current generation of nodes */
46 BisectNode *pAll; /* All nodes */
47 Bag seen; /* Nodes seen before */
48 int bad; /* The bad version */
49 int good; /* The good version */
50 int nStep; /* Number of steps from good to bad */
51 BisectNode *pStart; /* Earliest node (bad) */
52 BisectNode *pEnd; /* Most recent (good) */
53 } bisect;
54
55 /*
56 ** Create a new node
57 */
58 static BisectNode *bisect_new_node(int rid, BisectNode *pFrom, int isParent){
59 BisectNode *p;
60
61 p = fossil_malloc( sizeof(*p) );
62 p->rid = rid;
63 p->fromIsParent = isParent;
64 p->pFrom = pFrom;
65 p->u.pPeer = bisect.pCurrent;
66 bisect.pCurrent = p;
67 p->pAll = bisect.pAll;
68 bisect.pAll = p;
69 bisect.pEnd = p;
70 bag_insert(&bisect.seen, rid);
71 return p;
72 }
73
74 /*
75 ** Reset memory used by the shortest path algorithm.
76 */
77 void bisect_reset(void){
78 BisectNode *p;
79 while( bisect.pAll ){
80 p = bisect.pAll;
81 bisect.pAll = p->pAll;
82 fossil_free(p);
83 }
84 bag_clear(&bisect.seen);
85 bisect.pCurrent = 0;
86 bisect.pAll = 0;
87 bisect.pEnd = 0;
88 bisect.nStep = 0;
89 }
90
91 /*
92 ** Compute the shortest path from iFrom to iTo
93 **
94 ** If directOnly is true, then use only the "primary" links from parent to
95 ** child. In other words, ignore merges.
96 */
97 BisectNode *bisect_shortest_path(int iFrom, int iTo, int directOnly){
98 Stmt s;
99 BisectNode *pPrev;
100 BisectNode *p;
101
102 bisect_reset();
103 bisect.pStart = bisect_new_node(iFrom, 0, 0);
104 if( iTo==iFrom ) return bisect.pStart;
105 if( directOnly ){
106 db_prepare(&s,
107 "SELECT cid, 1 FROM plink WHERE pid=:pid AND isprim "
108 "UNION ALL "
109 "SELECT pid, 0 FROM plink WHERE cid=:pid AND isprim"
110 );
111 }else{
112 db_prepare(&s,
113 "SELECT cid, 1 FROM plink WHERE pid=:pid "
114 "UNION ALL "
115 "SELECT pid, 0 FROM plink WHERE cid=:pid"
116 );
117 }
118 while( bisect.pCurrent ){
119 bisect.nStep++;
120 pPrev = bisect.pCurrent;
121 bisect.pCurrent = 0;
122 while( pPrev ){
123 db_bind_int(&s, ":pid", pPrev->rid);
124 while( db_step(&s)==SQLITE_ROW ){
125 int cid = db_column_int(&s, 0);
126 int isParent = db_column_int(&s, 1);
127 if( bag_find(&bisect.seen, cid) ) continue;
128 p = bisect_new_node(cid, pPrev, isParent);
129 if( cid==iTo ){
130 db_finalize(&s);
131 return p;
132 }
133 }
134 db_reset(&s);
135 pPrev = pPrev->u.pPeer;
136 }
137 }
138 bisect_reset();
139 return 0;
140 }
141
142 /*
143 ** Construct the path from bisect.pStart to bisect.pEnd in the u.pTo fields.
144 */
145 BisectNode *bisect_reverse_path(void){
146 BisectNode *p;
147 for(p=bisect.pEnd; p && p->pFrom; p = p->pFrom){
148 p->pFrom->u.pTo = p;
149 }
150 bisect.pEnd->u.pTo = 0;
151 assert( p==bisect.pStart );
152 return p;
153 }
154
155 /*
156 ** COMMAND: test-shortest-path
157 **
158 ** Usage: %fossil test-shortest-path ?--no-merge? VERSION1 VERSION2
159 **
160 ** Report the shortest path between two checkins. If the --no-merge flag
161 ** is used, follow only direct parent-child paths and omit merge links.
162 */
163 void shortest_path_test_cmd(void){
164 int iFrom;
165 int iTo;
166 BisectNode *p;
167 int n;
168 int directOnly;
169
170 db_find_and_open_repository(0,0);
171 directOnly = find_option("no-merge",0,0)!=0;
172 if( g.argc!=4 ) usage("VERSION1 VERSION2");
173 iFrom = name_to_rid(g.argv[2]);
174 iTo = name_to_rid(g.argv[3]);
175 p = bisect_shortest_path(iFrom, iTo, directOnly);
176 if( p==0 ){
177 fossil_fatal("no path from %s to %s", g.argv[1], g.argv[2]);
178 }
179 bisect_reverse_path();
180 for(n=1, p=bisect.pStart; p; p=p->u.pTo, n++){
181 char *z;
182 z = db_text(0,
183 "SELECT substr(uuid,1,12) || ' ' || datetime(mtime)"
184 " FROM blob, event"
185 " WHERE blob.rid=%d AND event.objid=%d AND event.type='ci'",
186 p->rid, p->rid);
187 printf("%4d: %s", n, z);
188 fossil_free(z);
189 if( p->u.pTo ){
190 printf(" is a %s of\n", p->u.pTo->fromIsParent ? "parent" : "child");
191 }else{
192 printf("\n");
193 }
194 }
195 }
196
197 /*
198 ** WEBPAGE: path
199 **
200 ** example: /path?from=trunk&to=experimental&nomerge
201 **
202 ** Show a timeline of all changes along a path between two versions.
203 */
204 void path_page(void){
205 login_check_credentials();
206 if( !g.okRead ){ login_needed(); return; }
207 }
208
209 /*
210 ** Find the shortest path between bad and good.
211 */
212 static BisectNode *bisect_path(void){
213 BisectNode *p;
214 bisect.bad = db_lget_int("bisect-bad", 0);
215 if( bisect.bad==0 ){
216 bisect.bad = db_int(0, "SELECT cid FROM plink ORDER BY mtime DESC LIMIT 1");
217 db_lset_int("bisect-bad", bisect.bad);
218 }
@@ -219,21 +44,18 @@
219 bisect.good = db_lget_int("bisect-good", 0);
220 if( bisect.good==0 ){
221 bisect.good = db_int(0,"SELECT pid FROM plink ORDER BY mtime LIMIT 1");
222 db_lset_int("bisect-good", bisect.good);
223 }
224 p = bisect_shortest_path(bisect.good, bisect.bad, 0);
225 if( p==0 ){
226 char *zBad = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", bisect.bad);
227 char *zGood = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", bisect.good);
228 fossil_fatal("no path from good ([%S]) to bad ([%S]) or back",
229 zGood, zBad);
230 }
231 return p;
232 }
233
234
235
236 /*
237 ** COMMAND: bisect
238 **
239 ** Usage: %fossil bisect SUBCOMMAND ...
@@ -286,19 +108,18 @@
286 }else{
287 ridGood = name_to_rid(g.argv[3]);
288 }
289 db_lset_int("bisect-good", ridGood);
290 }else if( memcmp(zCmd, "next", n)==0 ){
291 BisectNode *p;
292 int n;
293 bisect_path();
294 if( bisect.nStep<2 ){
 
295 fossil_fatal("bisect is done - there are no more intermediate versions");
296 }
297 for(p=bisect.pEnd, n=0; p && n<bisect.nStep/2; p=p->pFrom, n++){}
298 g.argv[1] = "update";
299 g.argv[2] = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", p->rid);
300 g.argc = 3;
301 g.fNoSync = 1;
302 update_cmd();
303 }else if( memcmp(zCmd, "reset", n)==0 ){
304 db_multi_exec(
@@ -306,162 +127,35 @@
306 " SELECT 'bisect-good', pid FROM plink ORDER BY mtime LIMIT 1;"
307 "REPLACE INTO vvar(name, value) "
308 " SELECT 'bisect-bad', cid FROM plink ORDER BY mtime DESC LIMIT 1;"
309 );
310 }else if( memcmp(zCmd, "vlist", n)==0 ){
311 BisectNode *p;
312 int vid = db_lget_int("checkout", 0);
313 int n;
314 Stmt s;
 
315 bisect_path();
316 db_prepare(&s, "SELECT substr(blob.uuid,1,20) || ' ' || "
317 " datetime(event.mtime) FROM blob, event"
318 " WHERE blob.rid=:rid AND event.objid=:rid"
319 " AND event.type='ci'");
320 for(p=bisect.pEnd, n=0; p; p=p->pFrom, n++){
 
321 const char *z;
322 db_bind_int(&s, ":rid", p->rid);
323 if( db_step(&s)==SQLITE_ROW ){
324 z = db_column_text(&s, 0);
325 printf("%s", z);
326 if( p->rid==bisect.good ) printf(" GOOD");
327 if( p->rid==bisect.bad ) printf(" BAD");
328 if( p->rid==vid ) printf(" CURRENT");
329 if( bisect.nStep>1 && n==bisect.nStep/2 ) printf(" NEXT");
330 printf("\n");
331 }
332 db_reset(&s);
333 }
334 db_finalize(&s);
335 }else{
336 usage("bad|good|next|reset|vlist ...");
337 }
338 }
339
340 /*
341 ** A record of a file rename operation.
342 */
343 typedef struct NameChange NameChange;
344 struct NameChange {
345 int origName; /* Original name of file */
346 int curName; /* Current name of the file */
347 int newName; /* Name of file in next version */
348 NameChange *pNext; /* List of all name changes */
349 };
350
351 /*
352 ** Compute all file name changes that occur going from checkin iFrom
353 ** to checkin iTo.
354 **
355 ** The number of name changes is written into *pnChng. For each name
356 ** change, two integers are allocated for *piChng. The first is the
357 ** filename.fnid for the original name and the second is for new name.
358 ** Space to hold *piChng is obtained from fossil_malloc() and should
359 ** be released by the caller.
360 **
361 ** This routine really has nothing to do with bisection. It is located
362 ** in this bisect.c module in order to leverage some of the bisect
363 ** infrastructure.
364 */
365 void find_filename_changes(
366 int iFrom,
367 int iTo,
368 int *pnChng,
369 int **aiChng
370 ){
371 BisectNode *p; /* For looping over path from iFrom to iTo */
372 NameChange *pAll = 0; /* List of all name changes seen so far */
373 NameChange *pChng; /* For looping through the name change list */
374 int nChng = 0; /* Number of files whose names have changed */
375 int *aChng; /* Two integers per name change */
376 int i; /* Loop counter */
377 Stmt q1; /* Query of name changes */
378
379 *pnChng = 0;
380 *aiChng = 0;
381 bisect_reset();
382 p = bisect_shortest_path(iFrom, iTo, 0);
383 if( p==0 ) return;
384 bisect_reverse_path();
385 db_prepare(&q1,
386 "SELECT pfnid, fnid FROM mlink WHERE mid=:mid AND pfnid>0"
387 );
388 for(p=bisect.pStart; p; p=p->u.pTo){
389 int fnid, pfnid;
390 if( !p->fromIsParent && (p->u.pTo==0 || p->u.pTo->fromIsParent) ){
391 /* Skip nodes where the parent is not on the path */
392 continue;
393 }
394 db_bind_int(&q1, ":mid", p->rid);
395 while( db_step(&q1)==SQLITE_ROW ){
396 if( p->fromIsParent ){
397 fnid = db_column_int(&q1, 1);
398 pfnid = db_column_int(&q1, 0);
399 }else{
400 fnid = db_column_int(&q1, 0);
401 pfnid = db_column_int(&q1, 1);
402 }
403 for(pChng=pAll; pChng; pChng=pChng->pNext){
404 if( pChng->curName==pfnid ){
405 pChng->newName = fnid;
406 break;
407 }
408 }
409 if( pChng==0 ){
410 pChng = fossil_malloc( sizeof(*pChng) );
411 pChng->pNext = pAll;
412 pAll = pChng;
413 pChng->origName = pfnid;
414 pChng->curName = pfnid;
415 pChng->newName = fnid;
416 nChng++;
417 }
418 }
419 for(pChng=pAll; pChng; pChng=pChng->pNext) pChng->curName = pChng->newName;
420 db_reset(&q1);
421 }
422 db_finalize(&q1);
423 if( nChng ){
424 *pnChng = nChng;
425 aChng = *aiChng = fossil_malloc( nChng*2*sizeof(int) );
426 for(pChng=pAll, i=0; pChng; pChng=pChng->pNext, i+=2){
427 aChng[i] = pChng->origName;
428 aChng[i+1] = pChng->newName;
429 }
430 while( pAll ){
431 pChng = pAll;
432 pAll = pAll->pNext;
433 fossil_free(pChng);
434 }
435 }
436 }
437
438 /*
439 ** COMMAND: test-name-changes
440 **
441 ** Usage: %fossil test-name-changes VERSION1 VERSION2
442 **
443 ** Show all filename changes that occur going from VERSION1 to VERSION2
444 */
445 void test_name_change(void){
446 int iFrom;
447 int iTo;
448 int *aChng;
449 int nChng;
450 int i;
451
452 db_find_and_open_repository(0,0);
453 if( g.argc!=4 ) usage("VERSION1 VERSION2");
454 iFrom = name_to_rid(g.argv[2]);
455 iTo = name_to_rid(g.argv[3]);
456 find_filename_changes(iFrom, iTo, &nChng, &aChng);
457 for(i=0; i<nChng; i++){
458 char *zFrom, *zTo;
459
460 zFrom = db_text(0, "SELECT name FROM filename WHERE fnid=%d", aChng[i*2]);
461 zTo = db_text(0, "SELECT name FROM filename WHERE fnid=%d", aChng[i*2+1]);
462 printf("[%s] -> [%s]\n", zFrom, zTo);
463 fossil_free(zFrom);
464 fossil_free(zTo);
465 }
466 fossil_free(aChng);
467 }
468
--- src/bisect.c
+++ src/bisect.c
@@ -21,198 +21,23 @@
21 */
22 #include "config.h"
23 #include "bisect.h"
24 #include <assert.h>
25
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26 /*
27 ** Local variables for this module
28 */
29 static struct {
 
 
 
30 int bad; /* The bad version */
31 int good; /* The good version */
 
 
 
32 } bisect;
33
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34 /*
35 ** Find the shortest path between bad and good.
36 */
37 void bisect_path(void){
38 PathNode *p;
39 bisect.bad = db_lget_int("bisect-bad", 0);
40 if( bisect.bad==0 ){
41 bisect.bad = db_int(0, "SELECT cid FROM plink ORDER BY mtime DESC LIMIT 1");
42 db_lset_int("bisect-bad", bisect.bad);
43 }
@@ -219,21 +44,18 @@
44 bisect.good = db_lget_int("bisect-good", 0);
45 if( bisect.good==0 ){
46 bisect.good = db_int(0,"SELECT pid FROM plink ORDER BY mtime LIMIT 1");
47 db_lset_int("bisect-good", bisect.good);
48 }
49 p = path_shortest(bisect.good, bisect.bad, 0);
50 if( p==0 ){
51 char *zBad = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", bisect.bad);
52 char *zGood = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", bisect.good);
53 fossil_fatal("no path from good ([%S]) to bad ([%S]) or back",
54 zGood, zBad);
55 }
 
56 }
 
 
57
58 /*
59 ** COMMAND: bisect
60 **
61 ** Usage: %fossil bisect SUBCOMMAND ...
@@ -286,19 +108,18 @@
108 }else{
109 ridGood = name_to_rid(g.argv[3]);
110 }
111 db_lset_int("bisect-good", ridGood);
112 }else if( memcmp(zCmd, "next", n)==0 ){
113 PathNode *pMid;
 
114 bisect_path();
115 pMid = path_midpoint();
116 if( pMid==0 ){
117 fossil_fatal("bisect is done - there are no more intermediate versions");
118 }
 
119 g.argv[1] = "update";
120 g.argv[2] = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", pMid->rid);
121 g.argc = 3;
122 g.fNoSync = 1;
123 update_cmd();
124 }else if( memcmp(zCmd, "reset", n)==0 ){
125 db_multi_exec(
@@ -306,162 +127,35 @@
127 " SELECT 'bisect-good', pid FROM plink ORDER BY mtime LIMIT 1;"
128 "REPLACE INTO vvar(name, value) "
129 " SELECT 'bisect-bad', cid FROM plink ORDER BY mtime DESC LIMIT 1;"
130 );
131 }else if( memcmp(zCmd, "vlist", n)==0 ){
132 PathNode *p;
133 int vid = db_lget_int("checkout", 0);
134 int n;
135 Stmt s;
136 int nStep;
137 bisect_path();
138 db_prepare(&s, "SELECT substr(blob.uuid,1,20) || ' ' || "
139 " datetime(event.mtime) FROM blob, event"
140 " WHERE blob.rid=:rid AND event.objid=:rid"
141 " AND event.type='ci'");
142 nStep = path_length();
143 for(p=path_last(), n=0; p; p=p->pFrom, n++){
144 const char *z;
145 db_bind_int(&s, ":rid", p->rid);
146 if( db_step(&s)==SQLITE_ROW ){
147 z = db_column_text(&s, 0);
148 printf("%s", z);
149 if( p->rid==bisect.good ) printf(" GOOD");
150 if( p->rid==bisect.bad ) printf(" BAD");
151 if( p->rid==vid ) printf(" CURRENT");
152 if( nStep>1 && n==nStep/2 ) printf(" NEXT");
153 printf("\n");
154 }
155 db_reset(&s);
156 }
157 db_finalize(&s);
158 }else{
159 usage("bad|good|next|reset|vlist ...");
160 }
161 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
+18 -6
--- src/branch.c
+++ src/branch.c
@@ -39,13 +39,15 @@
3939
Blob branch; /* manifest for the new branch */
4040
Manifest *pParent; /* Parsed parent manifest */
4141
Blob mcksum; /* Self-checksum on the manifest */
4242
const char *zDateOvrd; /* Override date string */
4343
const char *zUserOvrd; /* Override user name */
44
+ int isPrivate = 0; /* True if the branch should be private */
4445
4546
noSign = find_option("nosign","",0)!=0;
4647
zColor = find_option("bgcolor","c",1);
48
+ isPrivate = find_option("private",0,0)!=0;
4749
zDateOvrd = find_option("date-override",0,1);
4850
zUserOvrd = find_option("user-override",0,1);
4951
verify_all_options();
5052
if( g.argc<5 ){
5153
usage("new BRANCH-NAME CHECK-IN ?-bgcolor COLOR?");
@@ -99,20 +101,28 @@
99101
}
100102
blob_append(&branch, "\n", 1);
101103
}
102104
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rootid);
103105
blob_appendf(&branch, "P %s\n", zUuid);
104
- blob_appendf(&branch, "R %s\n", pParent->zRepoCksum);
106
+ if( pParent->zRepoCksum ){
107
+ blob_appendf(&branch, "R %s\n", pParent->zRepoCksum);
108
+ }
105109
manifest_destroy(pParent);
106110
107111
/* Add the symbolic branch name and the "branch" tag to identify
108112
** this as a new branch */
113
+ if( content_is_private(rootid) ) isPrivate = 1;
114
+ if( isPrivate && zColor==0 ) zColor = "#fec084";
109115
if( zColor!=0 ){
110116
blob_appendf(&branch, "T *bgcolor * %F\n", zColor);
111117
}
112118
blob_appendf(&branch, "T *branch * %F\n", zBranch);
113119
blob_appendf(&branch, "T *sym-%F *\n", zBranch);
120
+ if( isPrivate ){
121
+ blob_appendf(&branch, "T +private *\n");
122
+ noSign = 1;
123
+ }
114124
115125
/* Cancel all other symbolic tags */
116126
db_prepare(&q,
117127
"SELECT tagname FROM tagxref, tag"
118128
" WHERE tagxref.rid=%d AND tagxref.tagid=tag.tagid"
@@ -175,32 +185,34 @@
175185
** Usage: %fossil branch SUBCOMMAND ... ?-R|--repository FILE?
176186
**
177187
** Run various subcommands to manage branches of the open repository or
178188
** of the repository identified by the -R or --repository option.
179189
**
180
-** %fossil branch new BRANCH-NAME BASIS ?-bgcolor COLOR?
190
+** %fossil branch new BRANCH-NAME BASIS ?--bgcolor COLOR? ?--private?
181191
**
182192
** Create a new branch BRANCH-NAME off of check-in BASIS.
183
-** You can optionally give the branch a default color.
193
+** You can optionally give the branch a default color. The
194
+** --private option makes the branch private.
184195
**
185196
** %fossil branch list
197
+** %fossil branch ls
186198
**
187199
** List all branches
188200
**
189201
*/
190202
void branch_cmd(void){
191203
int n;
192204
const char *zCmd = "list";
193205
db_find_and_open_repository(0, 0);
194206
if( g.argc<2 ){
195
- usage("new|list ...");
207
+ usage("new|list|ls ...");
196208
}
197209
if( g.argc>=3 ) zCmd = g.argv[2];
198210
n = strlen(zCmd);
199211
if( strncmp(zCmd,"new",n)==0 ){
200212
branch_new();
201
- }else if( strncmp(zCmd,"list",n)==0 ){
213
+ }else if( (strncmp(zCmd,"list",n)==0)||(strncmp(zCmd, "ls", n)==0) ){
202214
Stmt q;
203215
int vid;
204216
char *zCurrent = 0;
205217
206218
if( g.localOpen ){
@@ -222,11 +234,11 @@
222234
printf("%s%s\n", (isCur ? "* " : " "), zBr);
223235
}
224236
db_finalize(&q);
225237
}else{
226238
fossil_panic("branch subcommand should be one of: "
227
- "new list");
239
+ "new list ls");
228240
}
229241
}
230242
231243
/*
232244
** WEBPAGE: brlist
233245
--- src/branch.c
+++ src/branch.c
@@ -39,13 +39,15 @@
39 Blob branch; /* manifest for the new branch */
40 Manifest *pParent; /* Parsed parent manifest */
41 Blob mcksum; /* Self-checksum on the manifest */
42 const char *zDateOvrd; /* Override date string */
43 const char *zUserOvrd; /* Override user name */
 
44
45 noSign = find_option("nosign","",0)!=0;
46 zColor = find_option("bgcolor","c",1);
 
47 zDateOvrd = find_option("date-override",0,1);
48 zUserOvrd = find_option("user-override",0,1);
49 verify_all_options();
50 if( g.argc<5 ){
51 usage("new BRANCH-NAME CHECK-IN ?-bgcolor COLOR?");
@@ -99,20 +101,28 @@
99 }
100 blob_append(&branch, "\n", 1);
101 }
102 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rootid);
103 blob_appendf(&branch, "P %s\n", zUuid);
104 blob_appendf(&branch, "R %s\n", pParent->zRepoCksum);
 
 
105 manifest_destroy(pParent);
106
107 /* Add the symbolic branch name and the "branch" tag to identify
108 ** this as a new branch */
 
 
109 if( zColor!=0 ){
110 blob_appendf(&branch, "T *bgcolor * %F\n", zColor);
111 }
112 blob_appendf(&branch, "T *branch * %F\n", zBranch);
113 blob_appendf(&branch, "T *sym-%F *\n", zBranch);
 
 
 
 
114
115 /* Cancel all other symbolic tags */
116 db_prepare(&q,
117 "SELECT tagname FROM tagxref, tag"
118 " WHERE tagxref.rid=%d AND tagxref.tagid=tag.tagid"
@@ -175,32 +185,34 @@
175 ** Usage: %fossil branch SUBCOMMAND ... ?-R|--repository FILE?
176 **
177 ** Run various subcommands to manage branches of the open repository or
178 ** of the repository identified by the -R or --repository option.
179 **
180 ** %fossil branch new BRANCH-NAME BASIS ?-bgcolor COLOR?
181 **
182 ** Create a new branch BRANCH-NAME off of check-in BASIS.
183 ** You can optionally give the branch a default color.
 
184 **
185 ** %fossil branch list
 
186 **
187 ** List all branches
188 **
189 */
190 void branch_cmd(void){
191 int n;
192 const char *zCmd = "list";
193 db_find_and_open_repository(0, 0);
194 if( g.argc<2 ){
195 usage("new|list ...");
196 }
197 if( g.argc>=3 ) zCmd = g.argv[2];
198 n = strlen(zCmd);
199 if( strncmp(zCmd,"new",n)==0 ){
200 branch_new();
201 }else if( strncmp(zCmd,"list",n)==0 ){
202 Stmt q;
203 int vid;
204 char *zCurrent = 0;
205
206 if( g.localOpen ){
@@ -222,11 +234,11 @@
222 printf("%s%s\n", (isCur ? "* " : " "), zBr);
223 }
224 db_finalize(&q);
225 }else{
226 fossil_panic("branch subcommand should be one of: "
227 "new list");
228 }
229 }
230
231 /*
232 ** WEBPAGE: brlist
233
--- src/branch.c
+++ src/branch.c
@@ -39,13 +39,15 @@
39 Blob branch; /* manifest for the new branch */
40 Manifest *pParent; /* Parsed parent manifest */
41 Blob mcksum; /* Self-checksum on the manifest */
42 const char *zDateOvrd; /* Override date string */
43 const char *zUserOvrd; /* Override user name */
44 int isPrivate = 0; /* True if the branch should be private */
45
46 noSign = find_option("nosign","",0)!=0;
47 zColor = find_option("bgcolor","c",1);
48 isPrivate = find_option("private",0,0)!=0;
49 zDateOvrd = find_option("date-override",0,1);
50 zUserOvrd = find_option("user-override",0,1);
51 verify_all_options();
52 if( g.argc<5 ){
53 usage("new BRANCH-NAME CHECK-IN ?-bgcolor COLOR?");
@@ -99,20 +101,28 @@
101 }
102 blob_append(&branch, "\n", 1);
103 }
104 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rootid);
105 blob_appendf(&branch, "P %s\n", zUuid);
106 if( pParent->zRepoCksum ){
107 blob_appendf(&branch, "R %s\n", pParent->zRepoCksum);
108 }
109 manifest_destroy(pParent);
110
111 /* Add the symbolic branch name and the "branch" tag to identify
112 ** this as a new branch */
113 if( content_is_private(rootid) ) isPrivate = 1;
114 if( isPrivate && zColor==0 ) zColor = "#fec084";
115 if( zColor!=0 ){
116 blob_appendf(&branch, "T *bgcolor * %F\n", zColor);
117 }
118 blob_appendf(&branch, "T *branch * %F\n", zBranch);
119 blob_appendf(&branch, "T *sym-%F *\n", zBranch);
120 if( isPrivate ){
121 blob_appendf(&branch, "T +private *\n");
122 noSign = 1;
123 }
124
125 /* Cancel all other symbolic tags */
126 db_prepare(&q,
127 "SELECT tagname FROM tagxref, tag"
128 " WHERE tagxref.rid=%d AND tagxref.tagid=tag.tagid"
@@ -175,32 +185,34 @@
185 ** Usage: %fossil branch SUBCOMMAND ... ?-R|--repository FILE?
186 **
187 ** Run various subcommands to manage branches of the open repository or
188 ** of the repository identified by the -R or --repository option.
189 **
190 ** %fossil branch new BRANCH-NAME BASIS ?--bgcolor COLOR? ?--private?
191 **
192 ** Create a new branch BRANCH-NAME off of check-in BASIS.
193 ** You can optionally give the branch a default color. The
194 ** --private option makes the branch private.
195 **
196 ** %fossil branch list
197 ** %fossil branch ls
198 **
199 ** List all branches
200 **
201 */
202 void branch_cmd(void){
203 int n;
204 const char *zCmd = "list";
205 db_find_and_open_repository(0, 0);
206 if( g.argc<2 ){
207 usage("new|list|ls ...");
208 }
209 if( g.argc>=3 ) zCmd = g.argv[2];
210 n = strlen(zCmd);
211 if( strncmp(zCmd,"new",n)==0 ){
212 branch_new();
213 }else if( (strncmp(zCmd,"list",n)==0)||(strncmp(zCmd, "ls", n)==0) ){
214 Stmt q;
215 int vid;
216 char *zCurrent = 0;
217
218 if( g.localOpen ){
@@ -222,11 +234,11 @@
234 printf("%s%s\n", (isCur ? "* " : " "), zBr);
235 }
236 db_finalize(&q);
237 }else{
238 fossil_panic("branch subcommand should be one of: "
239 "new list ls");
240 }
241 }
242
243 /*
244 ** WEBPAGE: brlist
245
+6 -3
--- src/cgi.c
+++ src/cgi.c
@@ -342,18 +342,21 @@
342342
** The URL must be relative to the base of the fossil server.
343343
*/
344344
void cgi_redirect(const char *zURL){
345345
char *zLocation;
346346
CGIDEBUG(("redirect to %s\n", zURL));
347
- if( strncmp(zURL,"http:",5)==0 || strncmp(zURL,"https:",6)==0 || *zURL=='/' ){
347
+ if( strncmp(zURL,"http:",5)==0 || strncmp(zURL,"https:",6)==0 ){
348348
zLocation = mprintf("Location: %s\r\n", zURL);
349
+ }else if( *zURL=='/' ){
350
+ zLocation = mprintf("Location: %.*s%s\r\n",
351
+ strlen(g.zBaseURL)-strlen(g.zTop), g.zBaseURL, zURL);
349352
}else{
350
- zLocation = mprintf("Location: %s/%s\r\n", g.zTop, zURL);
353
+ zLocation = mprintf("Location: %s/%s\r\n", g.zBaseURL, zURL);
351354
}
352355
cgi_append_header(zLocation);
353356
cgi_reset_content();
354
- cgi_printf("<html>\n<p>Redirect to %h</p>\n</html>\n", zURL);
357
+ cgi_printf("<html>\n<p>Redirect to %h</p>\n</html>\n", zLocation);
355358
cgi_set_status(302, "Moved Temporarily");
356359
free(zLocation);
357360
cgi_reply();
358361
fossil_exit(0);
359362
}
360363
--- src/cgi.c
+++ src/cgi.c
@@ -342,18 +342,21 @@
342 ** The URL must be relative to the base of the fossil server.
343 */
344 void cgi_redirect(const char *zURL){
345 char *zLocation;
346 CGIDEBUG(("redirect to %s\n", zURL));
347 if( strncmp(zURL,"http:",5)==0 || strncmp(zURL,"https:",6)==0 || *zURL=='/' ){
348 zLocation = mprintf("Location: %s\r\n", zURL);
 
 
 
349 }else{
350 zLocation = mprintf("Location: %s/%s\r\n", g.zTop, zURL);
351 }
352 cgi_append_header(zLocation);
353 cgi_reset_content();
354 cgi_printf("<html>\n<p>Redirect to %h</p>\n</html>\n", zURL);
355 cgi_set_status(302, "Moved Temporarily");
356 free(zLocation);
357 cgi_reply();
358 fossil_exit(0);
359 }
360
--- src/cgi.c
+++ src/cgi.c
@@ -342,18 +342,21 @@
342 ** The URL must be relative to the base of the fossil server.
343 */
344 void cgi_redirect(const char *zURL){
345 char *zLocation;
346 CGIDEBUG(("redirect to %s\n", zURL));
347 if( strncmp(zURL,"http:",5)==0 || strncmp(zURL,"https:",6)==0 ){
348 zLocation = mprintf("Location: %s\r\n", zURL);
349 }else if( *zURL=='/' ){
350 zLocation = mprintf("Location: %.*s%s\r\n",
351 strlen(g.zBaseURL)-strlen(g.zTop), g.zBaseURL, zURL);
352 }else{
353 zLocation = mprintf("Location: %s/%s\r\n", g.zBaseURL, zURL);
354 }
355 cgi_append_header(zLocation);
356 cgi_reset_content();
357 cgi_printf("<html>\n<p>Redirect to %h</p>\n</html>\n", zLocation);
358 cgi_set_status(302, "Moved Temporarily");
359 free(zLocation);
360 cgi_reply();
361 fossil_exit(0);
362 }
363
+6 -1
--- src/db.c
+++ src/db.c
@@ -920,11 +920,12 @@
920920
** issue a fatal error and die.
921921
*/
922922
void db_verify_schema(void){
923923
if( db_schema_is_outofdate() ){
924924
fossil_warning("incorrect repository schema version");
925
- fossil_warning("you have version \"%s\" but you need version \"%s\"",
925
+ fossil_warning("your repository has schema version \"%s\" "
926
+ "but this binary expects version \"%s\"",
926927
db_get("aux-schema",0), AUX_SCHEMA);
927928
fossil_fatal("run \"fossil rebuild\" to fix this problem");
928929
}
929930
}
930931
@@ -1636,10 +1637,11 @@
16361637
{ "diff-command", 0, 16, "" },
16371638
{ "dont-push", 0, 0, "off" },
16381639
{ "editor", 0, 16, "" },
16391640
{ "gdiff-command", 0, 16, "gdiff" },
16401641
{ "gmerge-command",0, 40, "" },
1642
+ { "https-login", 0, 0, "off" },
16411643
{ "ignore-glob", 0, 40, "" },
16421644
{ "http-port", 0, 16, "8080" },
16431645
{ "localauth", 0, 0, "off" },
16441646
{ "main-branch", 0, 40, "trunk" },
16451647
{ "manifest", 0, 0, "off" },
@@ -1714,10 +1716,13 @@
17141716
** Ex: xxdiff "%original" "%baseline" "%merge" -M "%output"
17151717
** Ex: meld "%baseline" "%original" "%merge" "%output"
17161718
**
17171719
** http-port The TCP/IP port number to use by the "server"
17181720
** and "ui" commands. Default: 8080
1721
+**
1722
+** https-login Send login creditials using HTTPS instead of HTTP
1723
+** even if the login page request came via HTTP.
17191724
**
17201725
** ignore-glob The VALUE is a comma-separated list of GLOB patterns
17211726
** specifying files that the "extra" command will ignore.
17221727
** Example: *.o,*.obj,*.exe
17231728
**
17241729
--- src/db.c
+++ src/db.c
@@ -920,11 +920,12 @@
920 ** issue a fatal error and die.
921 */
922 void db_verify_schema(void){
923 if( db_schema_is_outofdate() ){
924 fossil_warning("incorrect repository schema version");
925 fossil_warning("you have version \"%s\" but you need version \"%s\"",
 
926 db_get("aux-schema",0), AUX_SCHEMA);
927 fossil_fatal("run \"fossil rebuild\" to fix this problem");
928 }
929 }
930
@@ -1636,10 +1637,11 @@
1636 { "diff-command", 0, 16, "" },
1637 { "dont-push", 0, 0, "off" },
1638 { "editor", 0, 16, "" },
1639 { "gdiff-command", 0, 16, "gdiff" },
1640 { "gmerge-command",0, 40, "" },
 
1641 { "ignore-glob", 0, 40, "" },
1642 { "http-port", 0, 16, "8080" },
1643 { "localauth", 0, 0, "off" },
1644 { "main-branch", 0, 40, "trunk" },
1645 { "manifest", 0, 0, "off" },
@@ -1714,10 +1716,13 @@
1714 ** Ex: xxdiff "%original" "%baseline" "%merge" -M "%output"
1715 ** Ex: meld "%baseline" "%original" "%merge" "%output"
1716 **
1717 ** http-port The TCP/IP port number to use by the "server"
1718 ** and "ui" commands. Default: 8080
 
 
 
1719 **
1720 ** ignore-glob The VALUE is a comma-separated list of GLOB patterns
1721 ** specifying files that the "extra" command will ignore.
1722 ** Example: *.o,*.obj,*.exe
1723 **
1724
--- src/db.c
+++ src/db.c
@@ -920,11 +920,12 @@
920 ** issue a fatal error and die.
921 */
922 void db_verify_schema(void){
923 if( db_schema_is_outofdate() ){
924 fossil_warning("incorrect repository schema version");
925 fossil_warning("your repository has schema version \"%s\" "
926 "but this binary expects version \"%s\"",
927 db_get("aux-schema",0), AUX_SCHEMA);
928 fossil_fatal("run \"fossil rebuild\" to fix this problem");
929 }
930 }
931
@@ -1636,10 +1637,11 @@
1637 { "diff-command", 0, 16, "" },
1638 { "dont-push", 0, 0, "off" },
1639 { "editor", 0, 16, "" },
1640 { "gdiff-command", 0, 16, "gdiff" },
1641 { "gmerge-command",0, 40, "" },
1642 { "https-login", 0, 0, "off" },
1643 { "ignore-glob", 0, 40, "" },
1644 { "http-port", 0, 16, "8080" },
1645 { "localauth", 0, 0, "off" },
1646 { "main-branch", 0, 40, "trunk" },
1647 { "manifest", 0, 0, "off" },
@@ -1714,10 +1716,13 @@
1716 ** Ex: xxdiff "%original" "%baseline" "%merge" -M "%output"
1717 ** Ex: meld "%baseline" "%original" "%merge" "%output"
1718 **
1719 ** http-port The TCP/IP port number to use by the "server"
1720 ** and "ui" commands. Default: 8080
1721 **
1722 ** https-login Send login creditials using HTTPS instead of HTTP
1723 ** even if the login page request came via HTTP.
1724 **
1725 ** ignore-glob The VALUE is a comma-separated list of GLOB patterns
1726 ** specifying files that the "extra" command will ignore.
1727 ** Example: *.o,*.obj,*.exe
1728 **
1729
--- src/descendants.c
+++ src/descendants.c
@@ -162,12 +162,12 @@
162162
Bag seen;
163163
PQueue queue;
164164
bag_init(&seen);
165165
pqueue_init(&queue);
166166
bag_insert(&seen, rid);
167
- pqueue_insert(&queue, rid, 0.0);
168
- while( (N--)>0 && (rid = pqueue_extract(&queue))!=0 ){
167
+ pqueue_insert(&queue, rid, 0.0, 0);
168
+ while( (N--)>0 && (rid = pqueue_extract(&queue, 0))!=0 ){
169169
Stmt q;
170170
db_multi_exec("INSERT OR IGNORE INTO ok VALUES(%d)", rid);
171171
db_prepare(&q,
172172
"SELECT a.pid, b.mtime FROM plink a LEFT JOIN plink b ON b.cid=a.pid"
173173
" WHERE a.cid=%d", rid
@@ -174,11 +174,11 @@
174174
);
175175
while( db_step(&q)==SQLITE_ROW ){
176176
int pid = db_column_int(&q, 0);
177177
double mtime = db_column_double(&q, 1);
178178
if( bag_insert(&seen, pid) ){
179
- pqueue_insert(&queue, pid, -mtime);
179
+ pqueue_insert(&queue, pid, -mtime, 0);
180180
}
181181
}
182182
db_finalize(&q);
183183
}
184184
bag_clear(&seen);
@@ -193,20 +193,20 @@
193193
Bag seen;
194194
PQueue queue;
195195
bag_init(&seen);
196196
pqueue_init(&queue);
197197
bag_insert(&seen, rid);
198
- pqueue_insert(&queue, rid, 0.0);
199
- while( (N--)>0 && (rid = pqueue_extract(&queue))!=0 ){
198
+ pqueue_insert(&queue, rid, 0.0, 0);
199
+ while( (N--)>0 && (rid = pqueue_extract(&queue, 0))!=0 ){
200200
Stmt q;
201201
db_multi_exec("INSERT OR IGNORE INTO ok VALUES(%d)", rid);
202202
db_prepare(&q,"SELECT cid, mtime FROM plink WHERE pid=%d", rid);
203203
while( db_step(&q)==SQLITE_ROW ){
204204
int pid = db_column_int(&q, 0);
205205
double mtime = db_column_double(&q, 1);
206206
if( bag_insert(&seen, pid) ){
207
- pqueue_insert(&queue, pid, mtime);
207
+ pqueue_insert(&queue, pid, mtime, 0);
208208
}
209209
}
210210
db_finalize(&q);
211211
}
212212
bag_clear(&seen);
213213
--- src/descendants.c
+++ src/descendants.c
@@ -162,12 +162,12 @@
162 Bag seen;
163 PQueue queue;
164 bag_init(&seen);
165 pqueue_init(&queue);
166 bag_insert(&seen, rid);
167 pqueue_insert(&queue, rid, 0.0);
168 while( (N--)>0 && (rid = pqueue_extract(&queue))!=0 ){
169 Stmt q;
170 db_multi_exec("INSERT OR IGNORE INTO ok VALUES(%d)", rid);
171 db_prepare(&q,
172 "SELECT a.pid, b.mtime FROM plink a LEFT JOIN plink b ON b.cid=a.pid"
173 " WHERE a.cid=%d", rid
@@ -174,11 +174,11 @@
174 );
175 while( db_step(&q)==SQLITE_ROW ){
176 int pid = db_column_int(&q, 0);
177 double mtime = db_column_double(&q, 1);
178 if( bag_insert(&seen, pid) ){
179 pqueue_insert(&queue, pid, -mtime);
180 }
181 }
182 db_finalize(&q);
183 }
184 bag_clear(&seen);
@@ -193,20 +193,20 @@
193 Bag seen;
194 PQueue queue;
195 bag_init(&seen);
196 pqueue_init(&queue);
197 bag_insert(&seen, rid);
198 pqueue_insert(&queue, rid, 0.0);
199 while( (N--)>0 && (rid = pqueue_extract(&queue))!=0 ){
200 Stmt q;
201 db_multi_exec("INSERT OR IGNORE INTO ok VALUES(%d)", rid);
202 db_prepare(&q,"SELECT cid, mtime FROM plink WHERE pid=%d", rid);
203 while( db_step(&q)==SQLITE_ROW ){
204 int pid = db_column_int(&q, 0);
205 double mtime = db_column_double(&q, 1);
206 if( bag_insert(&seen, pid) ){
207 pqueue_insert(&queue, pid, mtime);
208 }
209 }
210 db_finalize(&q);
211 }
212 bag_clear(&seen);
213
--- src/descendants.c
+++ src/descendants.c
@@ -162,12 +162,12 @@
162 Bag seen;
163 PQueue queue;
164 bag_init(&seen);
165 pqueue_init(&queue);
166 bag_insert(&seen, rid);
167 pqueue_insert(&queue, rid, 0.0, 0);
168 while( (N--)>0 && (rid = pqueue_extract(&queue, 0))!=0 ){
169 Stmt q;
170 db_multi_exec("INSERT OR IGNORE INTO ok VALUES(%d)", rid);
171 db_prepare(&q,
172 "SELECT a.pid, b.mtime FROM plink a LEFT JOIN plink b ON b.cid=a.pid"
173 " WHERE a.cid=%d", rid
@@ -174,11 +174,11 @@
174 );
175 while( db_step(&q)==SQLITE_ROW ){
176 int pid = db_column_int(&q, 0);
177 double mtime = db_column_double(&q, 1);
178 if( bag_insert(&seen, pid) ){
179 pqueue_insert(&queue, pid, -mtime, 0);
180 }
181 }
182 db_finalize(&q);
183 }
184 bag_clear(&seen);
@@ -193,20 +193,20 @@
193 Bag seen;
194 PQueue queue;
195 bag_init(&seen);
196 pqueue_init(&queue);
197 bag_insert(&seen, rid);
198 pqueue_insert(&queue, rid, 0.0, 0);
199 while( (N--)>0 && (rid = pqueue_extract(&queue, 0))!=0 ){
200 Stmt q;
201 db_multi_exec("INSERT OR IGNORE INTO ok VALUES(%d)", rid);
202 db_prepare(&q,"SELECT cid, mtime FROM plink WHERE pid=%d", rid);
203 while( db_step(&q)==SQLITE_ROW ){
204 int pid = db_column_int(&q, 0);
205 double mtime = db_column_double(&q, 1);
206 if( bag_insert(&seen, pid) ){
207 pqueue_insert(&queue, pid, mtime, 0);
208 }
209 }
210 db_finalize(&q);
211 }
212 bag_clear(&seen);
213
+3 -2
--- src/file.c
+++ src/file.c
@@ -299,12 +299,13 @@
299299
#endif
300300
301301
/* Removing trailing "/" characters */
302302
while( n>1 && z[n-1]=='/' ){ n--; }
303303
304
- /* Remove duplicate '/' characters */
305
- for(i=j=0; i<n; i++){
304
+ /* Remove duplicate '/' characters. Except, two // at the beginning
305
+ ** of a pathname is allowed since this is important on windows. */
306
+ for(i=j=1; i<n; i++){
306307
z[j++] = z[i];
307308
while( z[i]=='/' && i<n-1 && z[i+1]=='/' ) i++;
308309
}
309310
n = j;
310311
311312
--- src/file.c
+++ src/file.c
@@ -299,12 +299,13 @@
299 #endif
300
301 /* Removing trailing "/" characters */
302 while( n>1 && z[n-1]=='/' ){ n--; }
303
304 /* Remove duplicate '/' characters */
305 for(i=j=0; i<n; i++){
 
306 z[j++] = z[i];
307 while( z[i]=='/' && i<n-1 && z[i+1]=='/' ) i++;
308 }
309 n = j;
310
311
--- src/file.c
+++ src/file.c
@@ -299,12 +299,13 @@
299 #endif
300
301 /* Removing trailing "/" characters */
302 while( n>1 && z[n-1]=='/' ){ n--; }
303
304 /* Remove duplicate '/' characters. Except, two // at the beginning
305 ** of a pathname is allowed since this is important on windows. */
306 for(i=j=1; i<n; i++){
307 z[j++] = z[i];
308 while( z[i]=='/' && i<n-1 && z[i+1]=='/' ) i++;
309 }
310 n = j;
311
312
+11 -11
--- src/finfo.c
+++ src/finfo.c
@@ -39,24 +39,23 @@
3939
** The -p form, there's an optional flag "-r|--revision REVISION". The
4040
** specified version (or the latest checked out version) is printed to
4141
** stdout.
4242
*/
4343
void finfo_cmd(void){
44
- int vid;
45
-
4644
db_must_be_within_tree();
47
- vid = db_lget_int("checkout", 0);
48
- if( vid==0 ){
49
- fossil_panic("no checkout to finfo files in");
50
- }
51
- vfile_check_signature(vid, 1, 0);
5245
if (find_option("status","s",0)) {
5346
Stmt q;
5447
Blob line;
5548
Blob fname;
49
+ int vid;
5650
5751
if( g.argc!=3 ) usage("-s|--status FILENAME");
52
+ vid = db_lget_int("checkout", 0);
53
+ if( vid==0 ){
54
+ fossil_panic("no checkout to finfo files in");
55
+ }
56
+ vfile_check_signature(vid, 1, 0);
5857
file_tree_name(g.argv[2], &fname, 1);
5958
db_prepare(&q,
6059
"SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)"
6160
" FROM vfile WHERE vfile.pathname=%B", &fname);
6261
blob_zero(&line);
@@ -142,12 +141,13 @@
142141
zFilename = blob_str(&fname);
143142
db_prepare(&q,
144143
"SELECT b.uuid, ci.uuid, date(event.mtime,'localtime'),"
145144
" coalesce(event.ecomment, event.comment),"
146145
" coalesce(event.euser, event.user)"
147
- " FROM mlink, blob b, event, blob ci"
148
- " WHERE mlink.fnid=(SELECT fnid FROM filename WHERE name=%Q)"
146
+ " FROM mlink, blob b, event, blob ci, filename"
147
+ " WHERE filename.name=%Q"
148
+ " AND mlink.fnid=filename.fnid"
149149
" AND b.rid=mlink.fid"
150150
" AND event.objid=mlink.mid"
151151
" AND event.objid=ci.rid"
152152
" ORDER BY event.mtime DESC LIMIT %d OFFSET %d",
153153
zFilename, iLimit, iOffset
@@ -246,11 +246,11 @@
246246
int gidx;
247247
char zTime[10];
248248
char zShort[20];
249249
char zShortCkin[20];
250250
if( zBr==0 ) zBr = "trunk";
251
- gidx = graph_add_row(pGraph, frid, fpid>0 ? 1 : 0, &fpid, zBr, zBgClr);
251
+ gidx = graph_add_row(pGraph, frid, fpid>0 ? 1 : 0, &fpid, zBr, zBgClr, 1);
252252
if( memcmp(zDate, zPrevDate, 10) ){
253253
sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate);
254254
@ <tr><td>
255255
@ <div class="divider">%s(zPrevDate)</div>
256256
@ </td></tr>
@@ -301,8 +301,8 @@
301301
@ <tr><td></td><td><div style="width:%d(pGraph->mxRail*20+30)px;"></div>
302302
@ </td></tr>
303303
}
304304
}
305305
@ </table>
306
- timeline_output_graph_javascript(pGraph);
306
+ timeline_output_graph_javascript(pGraph, 1);
307307
style_footer();
308308
}
309309
--- src/finfo.c
+++ src/finfo.c
@@ -39,24 +39,23 @@
39 ** The -p form, there's an optional flag "-r|--revision REVISION". The
40 ** specified version (or the latest checked out version) is printed to
41 ** stdout.
42 */
43 void finfo_cmd(void){
44 int vid;
45
46 db_must_be_within_tree();
47 vid = db_lget_int("checkout", 0);
48 if( vid==0 ){
49 fossil_panic("no checkout to finfo files in");
50 }
51 vfile_check_signature(vid, 1, 0);
52 if (find_option("status","s",0)) {
53 Stmt q;
54 Blob line;
55 Blob fname;
 
56
57 if( g.argc!=3 ) usage("-s|--status FILENAME");
 
 
 
 
 
58 file_tree_name(g.argv[2], &fname, 1);
59 db_prepare(&q,
60 "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)"
61 " FROM vfile WHERE vfile.pathname=%B", &fname);
62 blob_zero(&line);
@@ -142,12 +141,13 @@
142 zFilename = blob_str(&fname);
143 db_prepare(&q,
144 "SELECT b.uuid, ci.uuid, date(event.mtime,'localtime'),"
145 " coalesce(event.ecomment, event.comment),"
146 " coalesce(event.euser, event.user)"
147 " FROM mlink, blob b, event, blob ci"
148 " WHERE mlink.fnid=(SELECT fnid FROM filename WHERE name=%Q)"
 
149 " AND b.rid=mlink.fid"
150 " AND event.objid=mlink.mid"
151 " AND event.objid=ci.rid"
152 " ORDER BY event.mtime DESC LIMIT %d OFFSET %d",
153 zFilename, iLimit, iOffset
@@ -246,11 +246,11 @@
246 int gidx;
247 char zTime[10];
248 char zShort[20];
249 char zShortCkin[20];
250 if( zBr==0 ) zBr = "trunk";
251 gidx = graph_add_row(pGraph, frid, fpid>0 ? 1 : 0, &fpid, zBr, zBgClr);
252 if( memcmp(zDate, zPrevDate, 10) ){
253 sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate);
254 @ <tr><td>
255 @ <div class="divider">%s(zPrevDate)</div>
256 @ </td></tr>
@@ -301,8 +301,8 @@
301 @ <tr><td></td><td><div style="width:%d(pGraph->mxRail*20+30)px;"></div>
302 @ </td></tr>
303 }
304 }
305 @ </table>
306 timeline_output_graph_javascript(pGraph);
307 style_footer();
308 }
309
--- src/finfo.c
+++ src/finfo.c
@@ -39,24 +39,23 @@
39 ** The -p form, there's an optional flag "-r|--revision REVISION". The
40 ** specified version (or the latest checked out version) is printed to
41 ** stdout.
42 */
43 void finfo_cmd(void){
 
 
44 db_must_be_within_tree();
 
 
 
 
 
45 if (find_option("status","s",0)) {
46 Stmt q;
47 Blob line;
48 Blob fname;
49 int vid;
50
51 if( g.argc!=3 ) usage("-s|--status FILENAME");
52 vid = db_lget_int("checkout", 0);
53 if( vid==0 ){
54 fossil_panic("no checkout to finfo files in");
55 }
56 vfile_check_signature(vid, 1, 0);
57 file_tree_name(g.argv[2], &fname, 1);
58 db_prepare(&q,
59 "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)"
60 " FROM vfile WHERE vfile.pathname=%B", &fname);
61 blob_zero(&line);
@@ -142,12 +141,13 @@
141 zFilename = blob_str(&fname);
142 db_prepare(&q,
143 "SELECT b.uuid, ci.uuid, date(event.mtime,'localtime'),"
144 " coalesce(event.ecomment, event.comment),"
145 " coalesce(event.euser, event.user)"
146 " FROM mlink, blob b, event, blob ci, filename"
147 " WHERE filename.name=%Q"
148 " AND mlink.fnid=filename.fnid"
149 " AND b.rid=mlink.fid"
150 " AND event.objid=mlink.mid"
151 " AND event.objid=ci.rid"
152 " ORDER BY event.mtime DESC LIMIT %d OFFSET %d",
153 zFilename, iLimit, iOffset
@@ -246,11 +246,11 @@
246 int gidx;
247 char zTime[10];
248 char zShort[20];
249 char zShortCkin[20];
250 if( zBr==0 ) zBr = "trunk";
251 gidx = graph_add_row(pGraph, frid, fpid>0 ? 1 : 0, &fpid, zBr, zBgClr, 1);
252 if( memcmp(zDate, zPrevDate, 10) ){
253 sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate);
254 @ <tr><td>
255 @ <div class="divider">%s(zPrevDate)</div>
256 @ </td></tr>
@@ -301,8 +301,8 @@
301 @ <tr><td></td><td><div style="width:%d(pGraph->mxRail*20+30)px;"></div>
302 @ </td></tr>
303 }
304 }
305 @ </table>
306 timeline_output_graph_javascript(pGraph, 1);
307 style_footer();
308 }
309
+88 -30
--- src/graph.c
+++ src/graph.c
@@ -42,15 +42,17 @@
4242
4343
int idx; /* Row index. First is 1. 0 used for "none" */
4444
int idxTop; /* Direct descendent highest up on the graph */
4545
GraphRow *pChild; /* Child immediately above this node */
4646
u8 isDup; /* True if this is duplicate of a prior entry */
47
+ u8 isLeaf; /* True if this is a leaf node */
48
+ u8 timeWarp; /* Child is earlier in time */
4749
u8 bDescender; /* True if riser from bottom of graph to here. */
4850
i8 iRail; /* Which rail this check-in appears on. 0-based.*/
4951
i8 mergeOut; /* Merge out to this rail. -1 if no merge-out */
52
+ u8 mergeIn[GR_MAX_RAIL]; /* Merge in from non-zero rails */
5053
int aiRiser[GR_MAX_RAIL]; /* Risers from this node to a higher row. */
51
- u32 mergeIn; /* Merge in from other rails on this bitmask */
5254
int mergeUpto; /* Draw the mergeOut rail up to this level */
5355
u32 mergeDown; /* Draw merge lines up from bottom of graph */
5456
5557
u32 railInUse; /* Mask of occupied rails at this row */
5658
};
@@ -87,13 +89,13 @@
8789
GraphContext *graph_init(void){
8890
return (GraphContext*)safeMalloc( sizeof(GraphContext) );
8991
}
9092
9193
/*
92
-** Destroy a GraphContext;
94
+** Clear all content from a graph
9395
*/
94
-void graph_free(GraphContext *p){
96
+static void graph_clear(GraphContext *p){
9597
int i;
9698
GraphRow *pRow;
9799
while( p->pFirst ){
98100
pRow = p->pFirst;
99101
p->pFirst = pRow->pNext;
@@ -100,10 +102,19 @@
100102
free(pRow);
101103
}
102104
for(i=0; i<p->nBranch; i++) free(p->azBranch[i]);
103105
free(p->azBranch);
104106
free(p->apHash);
107
+ memset(p, 0, sizeof(*p));
108
+ p->nErr = 1;
109
+}
110
+
111
+/*
112
+** Destroy a GraphContext;
113
+*/
114
+void graph_free(GraphContext *p){
115
+ graph_clear(p);
105116
free(p);
106117
}
107118
108119
/*
109120
** Insert a row into the hash table. pRow->rid is the key. Keys must
@@ -163,11 +174,12 @@
163174
GraphContext *p, /* The context to which the row is added */
164175
int rid, /* RID for the check-in */
165176
int nParent, /* Number of parents */
166177
int *aParent, /* Array of parents */
167178
const char *zBranch, /* Branch for this check-in */
168
- const char *zBgClr /* Background color. NULL or "" for white. */
179
+ const char *zBgClr, /* Background color. NULL or "" for white. */
180
+ int isLeaf /* True if this row is a leaf */
169181
){
170182
GraphRow *pRow;
171183
int nByte;
172184
173185
if( p->nErr ) return 0;
@@ -176,10 +188,12 @@
176188
pRow = (GraphRow*)safeMalloc( nByte );
177189
pRow->aParent = (int*)&pRow[1];
178190
pRow->rid = rid;
179191
pRow->nParent = nParent;
180192
pRow->zBranch = persistBranchName(p, zBranch);
193
+ pRow->isLeaf = isLeaf;
194
+ memset(pRow->aiRiser, -1, sizeof(pRow->aiRiser));
181195
if( zBgClr==0 || zBgClr[0]==0 ) zBgClr = "white";
182196
pRow->zBgClr = persistBranchName(p, zBgClr);
183197
memcpy(pRow->aParent, aParent, sizeof(aParent[0])*nParent);
184198
if( p->pFirst==0 ){
185199
p->pFirst = pRow;
@@ -224,10 +238,11 @@
224238
iBest = i;
225239
}
226240
}
227241
}
228242
if( iBestDist>1000 ) p->nErr++;
243
+ if( iBest>p->mxRail ) p->mxRail = iBest;
229244
return iBest;
230245
}
231246
232247
/*
233248
** Assign all children of node pBottom to the same rail as pBottom.
@@ -253,10 +268,48 @@
253268
assert( pPrior!=0 );
254269
}
255270
}
256271
}
257272
273
+/*
274
+** Create a merge-arrow riser going from pParent up to pChild.
275
+*/
276
+static void createMergeRiser(
277
+ GraphContext *p,
278
+ GraphRow *pParent,
279
+ GraphRow *pChild
280
+){
281
+ int u;
282
+ u32 mask;
283
+ GraphRow *pLoop;
284
+
285
+ if( pParent->mergeOut<0 ){
286
+ u = pParent->aiRiser[pParent->iRail];
287
+ if( u>=0 && u<pChild->idx ){
288
+ /* The thick arrow up to the next primary child of pDesc goes
289
+ ** further up than the thin merge arrow riser, so draw them both
290
+ ** on the same rail. */
291
+ pParent->mergeOut = pParent->iRail*4;
292
+ if( pParent->iRail<pChild->iRail ) pParent->mergeOut += 2;
293
+ pParent->mergeUpto = pChild->idx;
294
+ }else{
295
+ /* The thin merge arrow riser is taller than the thick primary
296
+ ** child riser, so use separate rails. */
297
+ int iTarget = pParent->iRail;
298
+ pParent->mergeOut = findFreeRail(p, pChild->idx, pParent->idx-1,
299
+ 0, iTarget)*4 + 1;
300
+ pParent->mergeUpto = pChild->idx;
301
+ mask = 1<<(pParent->mergeOut/4);
302
+ for(pLoop=pChild->pNext; pLoop && pLoop->rid!=pParent->rid;
303
+ pLoop=pLoop->pNext){
304
+ pLoop->railInUse |= mask;
305
+ }
306
+ }
307
+ }
308
+ pChild->mergeIn[pParent->mergeOut/4] = (pParent->mergeOut&3)+1;
309
+}
310
+
258311
259312
/*
260313
** Compute the complete graph
261314
*/
262315
void graph_finish(GraphContext *p, int omitDescenders){
@@ -266,10 +319,11 @@
266319
u32 inUse;
267320
int hasDup = 0; /* True if one or more isDup entries */
268321
const char *zTrunk;
269322
270323
if( p==0 || p->pFirst==0 || p->nErr ) return;
324
+ p->nErr = 1; /* Assume an error until proven otherwise */
271325
272326
/* Initialize all rows */
273327
p->nHash = p->nRow*2 + 1;
274328
p->apHash = safeMalloc( sizeof(p->apHash[0])*p->nHash );
275329
for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
@@ -318,11 +372,14 @@
318372
if( pRow->isDup ) continue;
319373
if( pRow->nParent==0 ) continue; /* Root node */
320374
pParent = hashFind(p, pRow->aParent[0]);
321375
if( pParent==0 ) continue; /* Parent off-screen */
322376
if( pParent->zBranch!=pRow->zBranch ) continue; /* Different branch */
323
- if( pParent->idx <= pRow->idx ) continue; /* Time-warp */
377
+ if( pParent->idx <= pRow->idx ){
378
+ pParent->timeWarp = 1;
379
+ continue; /* Time-warp */
380
+ }
324381
if( pRow->idxTop < pParent->idxTop ){
325382
pParent->pChild = pRow;
326383
pParent->idxTop = pRow->idxTop;
327384
}
328385
}
@@ -344,10 +401,11 @@
344401
if( omitDescenders ){
345402
pRow->iRail = findFreeRail(p, pRow->idxTop, pRow->idx, 0, 0);
346403
}else{
347404
pRow->iRail = ++p->mxRail;
348405
}
406
+ if( p->mxRail>=GR_MAX_RAIL ) return;
349407
mask = 1<<(pRow->iRail);
350408
if( !omitDescenders ){
351409
pRow->bDescender = pRow->nParent>0;
352410
for(pLoop=pRow; pLoop; pLoop=pLoop->pNext){
353411
pLoop->railInUse |= mask;
@@ -363,40 +421,55 @@
363421
inUse = (1<<(p->mxRail+1))-1;
364422
for(pRow=p->pLast; pRow; pRow=pRow->pPrev){
365423
int parentRid;
366424
367425
if( pRow->iRail>=0 ){
368
- if( pRow->pChild==0 ) inUse &= ~(1<<pRow->iRail);
426
+ if( pRow->pChild==0 && !pRow->timeWarp ){
427
+ if( pRow->isLeaf || omitDescenders ){
428
+ inUse &= ~(1<<pRow->iRail);
429
+ }else{
430
+ pRow->aiRiser[pRow->iRail] = 0;
431
+ mask = 1<<pRow->iRail;
432
+ for(pLoop=pRow; pLoop; pLoop=pLoop->pPrev){
433
+ pLoop->railInUse |= mask;
434
+ }
435
+ }
436
+ }
369437
continue;
370438
}
371439
if( pRow->isDup ){
372440
pRow->iRail = findFreeRail(p, pRow->idx, pRow->idx, inUse, 0);
441
+ if( p->mxRail>=GR_MAX_RAIL ) return;
373442
pDesc = pRow;
374443
pParent = 0;
375444
}else{
376445
assert( pRow->nParent>0 );
377446
parentRid = pRow->aParent[0];
378447
pParent = hashFind(p, parentRid);
379448
if( pParent==0 ){
380449
pRow->iRail = ++p->mxRail;
450
+ if( p->mxRail>=GR_MAX_RAIL ) return;
381451
pRow->railInUse = 1<<pRow->iRail;
382452
continue;
383453
}
384454
if( pParent->idx>pRow->idx ){
385455
/* Common case: Child occurs after parent and is above the
386456
** parent in the timeline */
387457
pRow->iRail = findFreeRail(p, 0, pParent->idx, inUse, pParent->iRail);
458
+ if( p->mxRail>=GR_MAX_RAIL ) return;
388459
pParent->aiRiser[pRow->iRail] = pRow->idx;
389460
}else{
390461
/* Timewarp case: Child occurs earlier in time than parent and
391462
** appears below the parent in the timeline. */
392463
int iDownRail = ++p->mxRail;
393464
if( iDownRail<1 ) iDownRail = ++p->mxRail;
394465
pRow->iRail = ++p->mxRail;
466
+ if( p->mxRail>=GR_MAX_RAIL ) return;
395467
pRow->railInUse = 1<<pRow->iRail;
396468
pParent->aiRiser[iDownRail] = pRow->idx;
397469
mask = 1<<iDownRail;
470
+ inUse |= mask;
398471
for(pLoop=p->pFirst; pLoop; pLoop=pLoop->pNext){
399472
pLoop->railInUse |= mask;
400473
}
401474
}
402475
}
@@ -423,29 +496,21 @@
423496
int parentRid = pRow->aParent[i];
424497
pDesc = hashFind(p, parentRid);
425498
if( pDesc==0 ){
426499
/* Merge from a node that is off-screen */
427500
int iMrail = findFreeRail(p, pRow->idx, p->nRow, 0, 0);
501
+ if( p->mxRail>=GR_MAX_RAIL ) return;
428502
mask = 1<<iMrail;
429
- pRow->mergeIn |= mask;
503
+ pRow->mergeIn[iMrail] = 2;
430504
pRow->mergeDown |= mask;
431505
for(pLoop=pRow->pNext; pLoop; pLoop=pLoop->pNext){
432506
pLoop->railInUse |= mask;
433507
}
434508
}else{
435509
/* Merge from an on-screen node */
436
- if( pDesc->mergeOut<0 ){
437
- int iTarget = (pRow->iRail + pDesc->iRail)/2;
438
- pDesc->mergeOut = findFreeRail(p, pRow->idx, pDesc->idx-1,0,iTarget);
439
- pDesc->mergeUpto = pRow->idx;
440
- mask = 1<<pDesc->mergeOut;
441
- for(pLoop=pRow->pNext; pLoop && pLoop->rid!=parentRid;
442
- pLoop=pLoop->pNext){
443
- pLoop->railInUse |= mask;
444
- }
445
- }
446
- pRow->mergeIn |= 1<<pDesc->mergeOut;
510
+ createMergeRiser(p, pDesc, pRow);
511
+ if( p->mxRail>=GR_MAX_RAIL ) return;
447512
}
448513
}
449514
}
450515
451516
/*
@@ -454,30 +519,23 @@
454519
if( hasDup ){
455520
for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
456521
if( !pRow->isDup ) continue;
457522
pDesc = hashFind(p, pRow->rid);
458523
assert( pDesc!=0 && pDesc!=pRow );
459
- if( pDesc->mergeOut<0 ){
460
- int iTarget = (pRow->iRail + pDesc->iRail)/2;
461
- pDesc->mergeOut = findFreeRail(p, pRow->idx, pDesc->idx-1, 0, iTarget);
462
- pDesc->mergeUpto = pRow->idx;
463
- mask = 1<<pDesc->mergeOut;
464
- for(pLoop=pRow->pNext; pLoop && pLoop!=pDesc; pLoop=pLoop->pNext){
465
- pLoop->railInUse |= mask;
466
- }
467
- }
468
- pRow->mergeIn |= 1<<pDesc->mergeOut;
469
- }
524
+ createMergeRiser(p, pDesc, pRow);
525
+ }
526
+ if( p->mxRail>=GR_MAX_RAIL ) return;
470527
}
471528
472529
/*
473530
** Find the maximum rail number.
474531
*/
475532
p->mxRail = 0;
476533
for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
477534
if( pRow->iRail>p->mxRail ) p->mxRail = pRow->iRail;
478
- if( pRow->mergeOut>p->mxRail ) p->mxRail = pRow->mergeOut;
535
+ if( pRow->mergeOut/4>p->mxRail ) p->mxRail = pRow->mergeOut/4;
479536
while( p->mxRail<GR_MAX_RAIL && pRow->mergeDown>((1<<(p->mxRail+1))-1) ){
480537
p->mxRail++;
481538
}
482539
}
540
+ p->nErr = 0;
483541
}
484542
--- src/graph.c
+++ src/graph.c
@@ -42,15 +42,17 @@
42
43 int idx; /* Row index. First is 1. 0 used for "none" */
44 int idxTop; /* Direct descendent highest up on the graph */
45 GraphRow *pChild; /* Child immediately above this node */
46 u8 isDup; /* True if this is duplicate of a prior entry */
 
 
47 u8 bDescender; /* True if riser from bottom of graph to here. */
48 i8 iRail; /* Which rail this check-in appears on. 0-based.*/
49 i8 mergeOut; /* Merge out to this rail. -1 if no merge-out */
 
50 int aiRiser[GR_MAX_RAIL]; /* Risers from this node to a higher row. */
51 u32 mergeIn; /* Merge in from other rails on this bitmask */
52 int mergeUpto; /* Draw the mergeOut rail up to this level */
53 u32 mergeDown; /* Draw merge lines up from bottom of graph */
54
55 u32 railInUse; /* Mask of occupied rails at this row */
56 };
@@ -87,13 +89,13 @@
87 GraphContext *graph_init(void){
88 return (GraphContext*)safeMalloc( sizeof(GraphContext) );
89 }
90
91 /*
92 ** Destroy a GraphContext;
93 */
94 void graph_free(GraphContext *p){
95 int i;
96 GraphRow *pRow;
97 while( p->pFirst ){
98 pRow = p->pFirst;
99 p->pFirst = pRow->pNext;
@@ -100,10 +102,19 @@
100 free(pRow);
101 }
102 for(i=0; i<p->nBranch; i++) free(p->azBranch[i]);
103 free(p->azBranch);
104 free(p->apHash);
 
 
 
 
 
 
 
 
 
105 free(p);
106 }
107
108 /*
109 ** Insert a row into the hash table. pRow->rid is the key. Keys must
@@ -163,11 +174,12 @@
163 GraphContext *p, /* The context to which the row is added */
164 int rid, /* RID for the check-in */
165 int nParent, /* Number of parents */
166 int *aParent, /* Array of parents */
167 const char *zBranch, /* Branch for this check-in */
168 const char *zBgClr /* Background color. NULL or "" for white. */
 
169 ){
170 GraphRow *pRow;
171 int nByte;
172
173 if( p->nErr ) return 0;
@@ -176,10 +188,12 @@
176 pRow = (GraphRow*)safeMalloc( nByte );
177 pRow->aParent = (int*)&pRow[1];
178 pRow->rid = rid;
179 pRow->nParent = nParent;
180 pRow->zBranch = persistBranchName(p, zBranch);
 
 
181 if( zBgClr==0 || zBgClr[0]==0 ) zBgClr = "white";
182 pRow->zBgClr = persistBranchName(p, zBgClr);
183 memcpy(pRow->aParent, aParent, sizeof(aParent[0])*nParent);
184 if( p->pFirst==0 ){
185 p->pFirst = pRow;
@@ -224,10 +238,11 @@
224 iBest = i;
225 }
226 }
227 }
228 if( iBestDist>1000 ) p->nErr++;
 
229 return iBest;
230 }
231
232 /*
233 ** Assign all children of node pBottom to the same rail as pBottom.
@@ -253,10 +268,48 @@
253 assert( pPrior!=0 );
254 }
255 }
256 }
257
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
258
259 /*
260 ** Compute the complete graph
261 */
262 void graph_finish(GraphContext *p, int omitDescenders){
@@ -266,10 +319,11 @@
266 u32 inUse;
267 int hasDup = 0; /* True if one or more isDup entries */
268 const char *zTrunk;
269
270 if( p==0 || p->pFirst==0 || p->nErr ) return;
 
271
272 /* Initialize all rows */
273 p->nHash = p->nRow*2 + 1;
274 p->apHash = safeMalloc( sizeof(p->apHash[0])*p->nHash );
275 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
@@ -318,11 +372,14 @@
318 if( pRow->isDup ) continue;
319 if( pRow->nParent==0 ) continue; /* Root node */
320 pParent = hashFind(p, pRow->aParent[0]);
321 if( pParent==0 ) continue; /* Parent off-screen */
322 if( pParent->zBranch!=pRow->zBranch ) continue; /* Different branch */
323 if( pParent->idx <= pRow->idx ) continue; /* Time-warp */
 
 
 
324 if( pRow->idxTop < pParent->idxTop ){
325 pParent->pChild = pRow;
326 pParent->idxTop = pRow->idxTop;
327 }
328 }
@@ -344,10 +401,11 @@
344 if( omitDescenders ){
345 pRow->iRail = findFreeRail(p, pRow->idxTop, pRow->idx, 0, 0);
346 }else{
347 pRow->iRail = ++p->mxRail;
348 }
 
349 mask = 1<<(pRow->iRail);
350 if( !omitDescenders ){
351 pRow->bDescender = pRow->nParent>0;
352 for(pLoop=pRow; pLoop; pLoop=pLoop->pNext){
353 pLoop->railInUse |= mask;
@@ -363,40 +421,55 @@
363 inUse = (1<<(p->mxRail+1))-1;
364 for(pRow=p->pLast; pRow; pRow=pRow->pPrev){
365 int parentRid;
366
367 if( pRow->iRail>=0 ){
368 if( pRow->pChild==0 ) inUse &= ~(1<<pRow->iRail);
 
 
 
 
 
 
 
 
 
 
369 continue;
370 }
371 if( pRow->isDup ){
372 pRow->iRail = findFreeRail(p, pRow->idx, pRow->idx, inUse, 0);
 
373 pDesc = pRow;
374 pParent = 0;
375 }else{
376 assert( pRow->nParent>0 );
377 parentRid = pRow->aParent[0];
378 pParent = hashFind(p, parentRid);
379 if( pParent==0 ){
380 pRow->iRail = ++p->mxRail;
 
381 pRow->railInUse = 1<<pRow->iRail;
382 continue;
383 }
384 if( pParent->idx>pRow->idx ){
385 /* Common case: Child occurs after parent and is above the
386 ** parent in the timeline */
387 pRow->iRail = findFreeRail(p, 0, pParent->idx, inUse, pParent->iRail);
 
388 pParent->aiRiser[pRow->iRail] = pRow->idx;
389 }else{
390 /* Timewarp case: Child occurs earlier in time than parent and
391 ** appears below the parent in the timeline. */
392 int iDownRail = ++p->mxRail;
393 if( iDownRail<1 ) iDownRail = ++p->mxRail;
394 pRow->iRail = ++p->mxRail;
 
395 pRow->railInUse = 1<<pRow->iRail;
396 pParent->aiRiser[iDownRail] = pRow->idx;
397 mask = 1<<iDownRail;
 
398 for(pLoop=p->pFirst; pLoop; pLoop=pLoop->pNext){
399 pLoop->railInUse |= mask;
400 }
401 }
402 }
@@ -423,29 +496,21 @@
423 int parentRid = pRow->aParent[i];
424 pDesc = hashFind(p, parentRid);
425 if( pDesc==0 ){
426 /* Merge from a node that is off-screen */
427 int iMrail = findFreeRail(p, pRow->idx, p->nRow, 0, 0);
 
428 mask = 1<<iMrail;
429 pRow->mergeIn |= mask;
430 pRow->mergeDown |= mask;
431 for(pLoop=pRow->pNext; pLoop; pLoop=pLoop->pNext){
432 pLoop->railInUse |= mask;
433 }
434 }else{
435 /* Merge from an on-screen node */
436 if( pDesc->mergeOut<0 ){
437 int iTarget = (pRow->iRail + pDesc->iRail)/2;
438 pDesc->mergeOut = findFreeRail(p, pRow->idx, pDesc->idx-1,0,iTarget);
439 pDesc->mergeUpto = pRow->idx;
440 mask = 1<<pDesc->mergeOut;
441 for(pLoop=pRow->pNext; pLoop && pLoop->rid!=parentRid;
442 pLoop=pLoop->pNext){
443 pLoop->railInUse |= mask;
444 }
445 }
446 pRow->mergeIn |= 1<<pDesc->mergeOut;
447 }
448 }
449 }
450
451 /*
@@ -454,30 +519,23 @@
454 if( hasDup ){
455 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
456 if( !pRow->isDup ) continue;
457 pDesc = hashFind(p, pRow->rid);
458 assert( pDesc!=0 && pDesc!=pRow );
459 if( pDesc->mergeOut<0 ){
460 int iTarget = (pRow->iRail + pDesc->iRail)/2;
461 pDesc->mergeOut = findFreeRail(p, pRow->idx, pDesc->idx-1, 0, iTarget);
462 pDesc->mergeUpto = pRow->idx;
463 mask = 1<<pDesc->mergeOut;
464 for(pLoop=pRow->pNext; pLoop && pLoop!=pDesc; pLoop=pLoop->pNext){
465 pLoop->railInUse |= mask;
466 }
467 }
468 pRow->mergeIn |= 1<<pDesc->mergeOut;
469 }
470 }
471
472 /*
473 ** Find the maximum rail number.
474 */
475 p->mxRail = 0;
476 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
477 if( pRow->iRail>p->mxRail ) p->mxRail = pRow->iRail;
478 if( pRow->mergeOut>p->mxRail ) p->mxRail = pRow->mergeOut;
479 while( p->mxRail<GR_MAX_RAIL && pRow->mergeDown>((1<<(p->mxRail+1))-1) ){
480 p->mxRail++;
481 }
482 }
 
483 }
484
--- src/graph.c
+++ src/graph.c
@@ -42,15 +42,17 @@
42
43 int idx; /* Row index. First is 1. 0 used for "none" */
44 int idxTop; /* Direct descendent highest up on the graph */
45 GraphRow *pChild; /* Child immediately above this node */
46 u8 isDup; /* True if this is duplicate of a prior entry */
47 u8 isLeaf; /* True if this is a leaf node */
48 u8 timeWarp; /* Child is earlier in time */
49 u8 bDescender; /* True if riser from bottom of graph to here. */
50 i8 iRail; /* Which rail this check-in appears on. 0-based.*/
51 i8 mergeOut; /* Merge out to this rail. -1 if no merge-out */
52 u8 mergeIn[GR_MAX_RAIL]; /* Merge in from non-zero rails */
53 int aiRiser[GR_MAX_RAIL]; /* Risers from this node to a higher row. */
 
54 int mergeUpto; /* Draw the mergeOut rail up to this level */
55 u32 mergeDown; /* Draw merge lines up from bottom of graph */
56
57 u32 railInUse; /* Mask of occupied rails at this row */
58 };
@@ -87,13 +89,13 @@
89 GraphContext *graph_init(void){
90 return (GraphContext*)safeMalloc( sizeof(GraphContext) );
91 }
92
93 /*
94 ** Clear all content from a graph
95 */
96 static void graph_clear(GraphContext *p){
97 int i;
98 GraphRow *pRow;
99 while( p->pFirst ){
100 pRow = p->pFirst;
101 p->pFirst = pRow->pNext;
@@ -100,10 +102,19 @@
102 free(pRow);
103 }
104 for(i=0; i<p->nBranch; i++) free(p->azBranch[i]);
105 free(p->azBranch);
106 free(p->apHash);
107 memset(p, 0, sizeof(*p));
108 p->nErr = 1;
109 }
110
111 /*
112 ** Destroy a GraphContext;
113 */
114 void graph_free(GraphContext *p){
115 graph_clear(p);
116 free(p);
117 }
118
119 /*
120 ** Insert a row into the hash table. pRow->rid is the key. Keys must
@@ -163,11 +174,12 @@
174 GraphContext *p, /* The context to which the row is added */
175 int rid, /* RID for the check-in */
176 int nParent, /* Number of parents */
177 int *aParent, /* Array of parents */
178 const char *zBranch, /* Branch for this check-in */
179 const char *zBgClr, /* Background color. NULL or "" for white. */
180 int isLeaf /* True if this row is a leaf */
181 ){
182 GraphRow *pRow;
183 int nByte;
184
185 if( p->nErr ) return 0;
@@ -176,10 +188,12 @@
188 pRow = (GraphRow*)safeMalloc( nByte );
189 pRow->aParent = (int*)&pRow[1];
190 pRow->rid = rid;
191 pRow->nParent = nParent;
192 pRow->zBranch = persistBranchName(p, zBranch);
193 pRow->isLeaf = isLeaf;
194 memset(pRow->aiRiser, -1, sizeof(pRow->aiRiser));
195 if( zBgClr==0 || zBgClr[0]==0 ) zBgClr = "white";
196 pRow->zBgClr = persistBranchName(p, zBgClr);
197 memcpy(pRow->aParent, aParent, sizeof(aParent[0])*nParent);
198 if( p->pFirst==0 ){
199 p->pFirst = pRow;
@@ -224,10 +238,11 @@
238 iBest = i;
239 }
240 }
241 }
242 if( iBestDist>1000 ) p->nErr++;
243 if( iBest>p->mxRail ) p->mxRail = iBest;
244 return iBest;
245 }
246
247 /*
248 ** Assign all children of node pBottom to the same rail as pBottom.
@@ -253,10 +268,48 @@
268 assert( pPrior!=0 );
269 }
270 }
271 }
272
273 /*
274 ** Create a merge-arrow riser going from pParent up to pChild.
275 */
276 static void createMergeRiser(
277 GraphContext *p,
278 GraphRow *pParent,
279 GraphRow *pChild
280 ){
281 int u;
282 u32 mask;
283 GraphRow *pLoop;
284
285 if( pParent->mergeOut<0 ){
286 u = pParent->aiRiser[pParent->iRail];
287 if( u>=0 && u<pChild->idx ){
288 /* The thick arrow up to the next primary child of pDesc goes
289 ** further up than the thin merge arrow riser, so draw them both
290 ** on the same rail. */
291 pParent->mergeOut = pParent->iRail*4;
292 if( pParent->iRail<pChild->iRail ) pParent->mergeOut += 2;
293 pParent->mergeUpto = pChild->idx;
294 }else{
295 /* The thin merge arrow riser is taller than the thick primary
296 ** child riser, so use separate rails. */
297 int iTarget = pParent->iRail;
298 pParent->mergeOut = findFreeRail(p, pChild->idx, pParent->idx-1,
299 0, iTarget)*4 + 1;
300 pParent->mergeUpto = pChild->idx;
301 mask = 1<<(pParent->mergeOut/4);
302 for(pLoop=pChild->pNext; pLoop && pLoop->rid!=pParent->rid;
303 pLoop=pLoop->pNext){
304 pLoop->railInUse |= mask;
305 }
306 }
307 }
308 pChild->mergeIn[pParent->mergeOut/4] = (pParent->mergeOut&3)+1;
309 }
310
311
312 /*
313 ** Compute the complete graph
314 */
315 void graph_finish(GraphContext *p, int omitDescenders){
@@ -266,10 +319,11 @@
319 u32 inUse;
320 int hasDup = 0; /* True if one or more isDup entries */
321 const char *zTrunk;
322
323 if( p==0 || p->pFirst==0 || p->nErr ) return;
324 p->nErr = 1; /* Assume an error until proven otherwise */
325
326 /* Initialize all rows */
327 p->nHash = p->nRow*2 + 1;
328 p->apHash = safeMalloc( sizeof(p->apHash[0])*p->nHash );
329 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
@@ -318,11 +372,14 @@
372 if( pRow->isDup ) continue;
373 if( pRow->nParent==0 ) continue; /* Root node */
374 pParent = hashFind(p, pRow->aParent[0]);
375 if( pParent==0 ) continue; /* Parent off-screen */
376 if( pParent->zBranch!=pRow->zBranch ) continue; /* Different branch */
377 if( pParent->idx <= pRow->idx ){
378 pParent->timeWarp = 1;
379 continue; /* Time-warp */
380 }
381 if( pRow->idxTop < pParent->idxTop ){
382 pParent->pChild = pRow;
383 pParent->idxTop = pRow->idxTop;
384 }
385 }
@@ -344,10 +401,11 @@
401 if( omitDescenders ){
402 pRow->iRail = findFreeRail(p, pRow->idxTop, pRow->idx, 0, 0);
403 }else{
404 pRow->iRail = ++p->mxRail;
405 }
406 if( p->mxRail>=GR_MAX_RAIL ) return;
407 mask = 1<<(pRow->iRail);
408 if( !omitDescenders ){
409 pRow->bDescender = pRow->nParent>0;
410 for(pLoop=pRow; pLoop; pLoop=pLoop->pNext){
411 pLoop->railInUse |= mask;
@@ -363,40 +421,55 @@
421 inUse = (1<<(p->mxRail+1))-1;
422 for(pRow=p->pLast; pRow; pRow=pRow->pPrev){
423 int parentRid;
424
425 if( pRow->iRail>=0 ){
426 if( pRow->pChild==0 && !pRow->timeWarp ){
427 if( pRow->isLeaf || omitDescenders ){
428 inUse &= ~(1<<pRow->iRail);
429 }else{
430 pRow->aiRiser[pRow->iRail] = 0;
431 mask = 1<<pRow->iRail;
432 for(pLoop=pRow; pLoop; pLoop=pLoop->pPrev){
433 pLoop->railInUse |= mask;
434 }
435 }
436 }
437 continue;
438 }
439 if( pRow->isDup ){
440 pRow->iRail = findFreeRail(p, pRow->idx, pRow->idx, inUse, 0);
441 if( p->mxRail>=GR_MAX_RAIL ) return;
442 pDesc = pRow;
443 pParent = 0;
444 }else{
445 assert( pRow->nParent>0 );
446 parentRid = pRow->aParent[0];
447 pParent = hashFind(p, parentRid);
448 if( pParent==0 ){
449 pRow->iRail = ++p->mxRail;
450 if( p->mxRail>=GR_MAX_RAIL ) return;
451 pRow->railInUse = 1<<pRow->iRail;
452 continue;
453 }
454 if( pParent->idx>pRow->idx ){
455 /* Common case: Child occurs after parent and is above the
456 ** parent in the timeline */
457 pRow->iRail = findFreeRail(p, 0, pParent->idx, inUse, pParent->iRail);
458 if( p->mxRail>=GR_MAX_RAIL ) return;
459 pParent->aiRiser[pRow->iRail] = pRow->idx;
460 }else{
461 /* Timewarp case: Child occurs earlier in time than parent and
462 ** appears below the parent in the timeline. */
463 int iDownRail = ++p->mxRail;
464 if( iDownRail<1 ) iDownRail = ++p->mxRail;
465 pRow->iRail = ++p->mxRail;
466 if( p->mxRail>=GR_MAX_RAIL ) return;
467 pRow->railInUse = 1<<pRow->iRail;
468 pParent->aiRiser[iDownRail] = pRow->idx;
469 mask = 1<<iDownRail;
470 inUse |= mask;
471 for(pLoop=p->pFirst; pLoop; pLoop=pLoop->pNext){
472 pLoop->railInUse |= mask;
473 }
474 }
475 }
@@ -423,29 +496,21 @@
496 int parentRid = pRow->aParent[i];
497 pDesc = hashFind(p, parentRid);
498 if( pDesc==0 ){
499 /* Merge from a node that is off-screen */
500 int iMrail = findFreeRail(p, pRow->idx, p->nRow, 0, 0);
501 if( p->mxRail>=GR_MAX_RAIL ) return;
502 mask = 1<<iMrail;
503 pRow->mergeIn[iMrail] = 2;
504 pRow->mergeDown |= mask;
505 for(pLoop=pRow->pNext; pLoop; pLoop=pLoop->pNext){
506 pLoop->railInUse |= mask;
507 }
508 }else{
509 /* Merge from an on-screen node */
510 createMergeRiser(p, pDesc, pRow);
511 if( p->mxRail>=GR_MAX_RAIL ) return;
 
 
 
 
 
 
 
 
 
512 }
513 }
514 }
515
516 /*
@@ -454,30 +519,23 @@
519 if( hasDup ){
520 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
521 if( !pRow->isDup ) continue;
522 pDesc = hashFind(p, pRow->rid);
523 assert( pDesc!=0 && pDesc!=pRow );
524 createMergeRiser(p, pDesc, pRow);
525 }
526 if( p->mxRail>=GR_MAX_RAIL ) return;
 
 
 
 
 
 
 
 
527 }
528
529 /*
530 ** Find the maximum rail number.
531 */
532 p->mxRail = 0;
533 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
534 if( pRow->iRail>p->mxRail ) p->mxRail = pRow->iRail;
535 if( pRow->mergeOut/4>p->mxRail ) p->mxRail = pRow->mergeOut/4;
536 while( p->mxRail<GR_MAX_RAIL && pRow->mergeDown>((1<<(p->mxRail+1))-1) ){
537 p->mxRail++;
538 }
539 }
540 p->nErr = 0;
541 }
542
+1 -1
--- src/gzip.c
+++ src/gzip.c
@@ -74,11 +74,11 @@
7474
void gzip_step(const char *pIn, int nIn){
7575
char *zOutBuf;
7676
int nOut;
7777
7878
nOut = nIn + nIn/10 + 100;
79
- if( nOut<25000 ) nOut = 25000;
79
+ if( nOut<100000 ) nOut = 100000;
8080
zOutBuf = fossil_malloc(nOut);
8181
gzip.stream.avail_in = nIn;
8282
gzip.stream.next_in = (unsigned char*)pIn;
8383
gzip.stream.avail_out = nOut;
8484
gzip.stream.next_out = (unsigned char*)zOutBuf;
8585
--- src/gzip.c
+++ src/gzip.c
@@ -74,11 +74,11 @@
74 void gzip_step(const char *pIn, int nIn){
75 char *zOutBuf;
76 int nOut;
77
78 nOut = nIn + nIn/10 + 100;
79 if( nOut<25000 ) nOut = 25000;
80 zOutBuf = fossil_malloc(nOut);
81 gzip.stream.avail_in = nIn;
82 gzip.stream.next_in = (unsigned char*)pIn;
83 gzip.stream.avail_out = nOut;
84 gzip.stream.next_out = (unsigned char*)zOutBuf;
85
--- src/gzip.c
+++ src/gzip.c
@@ -74,11 +74,11 @@
74 void gzip_step(const char *pIn, int nIn){
75 char *zOutBuf;
76 int nOut;
77
78 nOut = nIn + nIn/10 + 100;
79 if( nOut<100000 ) nOut = 100000;
80 zOutBuf = fossil_malloc(nOut);
81 gzip.stream.avail_in = nIn;
82 gzip.stream.next_in = (unsigned char*)pIn;
83 gzip.stream.avail_out = nOut;
84 gzip.stream.next_out = (unsigned char*)zOutBuf;
85
+11 -2
--- src/info.c
+++ src/info.c
@@ -1362,10 +1362,11 @@
13621362
*/
13631363
void info_page(void){
13641364
const char *zName;
13651365
Blob uuid;
13661366
int rid;
1367
+ int rc;
13671368
13681369
zName = P("name");
13691370
if( zName==0 ) fossil_redirect_home();
13701371
if( validate16(zName, strlen(zName)) ){
13711372
if( db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%q*'", zName) ){
@@ -1376,12 +1377,20 @@
13761377
event_page();
13771378
return;
13781379
}
13791380
}
13801381
blob_set(&uuid, zName);
1381
- if( name_to_uuid(&uuid, 1) ){
1382
- fossil_redirect_home();
1382
+ rc = name_to_uuid(&uuid, -1);
1383
+ if( rc==1 ){
1384
+ style_header("No Such Object");
1385
+ @ <p>No such object: %h(zName)</p>
1386
+ style_footer();
1387
+ return;
1388
+ }else if( rc==2 ){
1389
+ cgi_set_parameter("src","info");
1390
+ ambiguous_page();
1391
+ return;
13831392
}
13841393
zName = blob_str(&uuid);
13851394
rid = db_int(0, "SELECT rid FROM blob WHERE uuid='%s'", zName);
13861395
if( rid==0 ){
13871396
style_header("Broken Link");
13881397
--- src/info.c
+++ src/info.c
@@ -1362,10 +1362,11 @@
1362 */
1363 void info_page(void){
1364 const char *zName;
1365 Blob uuid;
1366 int rid;
 
1367
1368 zName = P("name");
1369 if( zName==0 ) fossil_redirect_home();
1370 if( validate16(zName, strlen(zName)) ){
1371 if( db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%q*'", zName) ){
@@ -1376,12 +1377,20 @@
1376 event_page();
1377 return;
1378 }
1379 }
1380 blob_set(&uuid, zName);
1381 if( name_to_uuid(&uuid, 1) ){
1382 fossil_redirect_home();
 
 
 
 
 
 
 
 
1383 }
1384 zName = blob_str(&uuid);
1385 rid = db_int(0, "SELECT rid FROM blob WHERE uuid='%s'", zName);
1386 if( rid==0 ){
1387 style_header("Broken Link");
1388
--- src/info.c
+++ src/info.c
@@ -1362,10 +1362,11 @@
1362 */
1363 void info_page(void){
1364 const char *zName;
1365 Blob uuid;
1366 int rid;
1367 int rc;
1368
1369 zName = P("name");
1370 if( zName==0 ) fossil_redirect_home();
1371 if( validate16(zName, strlen(zName)) ){
1372 if( db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%q*'", zName) ){
@@ -1376,12 +1377,20 @@
1377 event_page();
1378 return;
1379 }
1380 }
1381 blob_set(&uuid, zName);
1382 rc = name_to_uuid(&uuid, -1);
1383 if( rc==1 ){
1384 style_header("No Such Object");
1385 @ <p>No such object: %h(zName)</p>
1386 style_footer();
1387 return;
1388 }else if( rc==2 ){
1389 cgi_set_parameter("src","info");
1390 ambiguous_page();
1391 return;
1392 }
1393 zName = blob_str(&uuid);
1394 rid = db_int(0, "SELECT rid FROM blob WHERE uuid='%s'", zName);
1395 if( rid==0 ){
1396 style_header("Broken Link");
1397
+6 -3
--- src/leaf.c
+++ src/leaf.c
@@ -40,11 +40,12 @@
4040
" EXCEPT"
4141
" SELECT pid FROM plink"
4242
" WHERE coalesce((SELECT value FROM tagxref"
4343
" WHERE tagid=%d AND rid=plink.pid),'trunk')"
4444
" == coalesce((SELECT value FROM tagxref"
45
- " WHERE tagid=%d AND rid=plink.cid),'trunk');",
45
+ " WHERE tagid=%d AND rid=plink.cid),'trunk')"
46
+ " AND isprim",
4647
TAG_BRANCH, TAG_BRANCH
4748
);
4849
}
4950
5051
/*
@@ -62,11 +63,11 @@
6263
static Stmt removeLeaf;
6364
int rc;
6465
6566
db_static_prepare(&checkIfLeaf,
6667
"SELECT 1 FROM plink"
67
- " WHERE pid=:rid"
68
+ " WHERE pid=:rid AND isprim"
6869
" AND coalesce((SELECT value FROM tagxref"
6970
" WHERE tagid=%d AND rid=:rid),'trunk')"
7071
" == coalesce((SELECT value FROM tagxref"
7172
" WHERE tagid=%d AND rid=plink.cid),'trunk');",
7273
TAG_BRANCH, TAG_BRANCH
@@ -109,11 +110,13 @@
109110
** Schedule a leaf check for "rid" and its parents.
110111
*/
111112
void leaf_eventually_check(int rid){
112113
static Stmt parentsOf;
113114
114
- db_static_prepare(&parentsOf, "SELECT pid FROM plink WHERE cid=:rid");
115
+ db_static_prepare(&parentsOf,
116
+ "SELECT pid FROM plink WHERE cid=:rid AND pid>0"
117
+ );
115118
db_bind_int(&parentsOf, ":rid", rid);
116119
bag_insert(&needToCheck, rid);
117120
while( db_step(&parentsOf)==SQLITE_ROW ){
118121
bag_insert(&needToCheck, db_column_int(&parentsOf, 0));
119122
}
120123
--- src/leaf.c
+++ src/leaf.c
@@ -40,11 +40,12 @@
40 " EXCEPT"
41 " SELECT pid FROM plink"
42 " WHERE coalesce((SELECT value FROM tagxref"
43 " WHERE tagid=%d AND rid=plink.pid),'trunk')"
44 " == coalesce((SELECT value FROM tagxref"
45 " WHERE tagid=%d AND rid=plink.cid),'trunk');",
 
46 TAG_BRANCH, TAG_BRANCH
47 );
48 }
49
50 /*
@@ -62,11 +63,11 @@
62 static Stmt removeLeaf;
63 int rc;
64
65 db_static_prepare(&checkIfLeaf,
66 "SELECT 1 FROM plink"
67 " WHERE pid=:rid"
68 " AND coalesce((SELECT value FROM tagxref"
69 " WHERE tagid=%d AND rid=:rid),'trunk')"
70 " == coalesce((SELECT value FROM tagxref"
71 " WHERE tagid=%d AND rid=plink.cid),'trunk');",
72 TAG_BRANCH, TAG_BRANCH
@@ -109,11 +110,13 @@
109 ** Schedule a leaf check for "rid" and its parents.
110 */
111 void leaf_eventually_check(int rid){
112 static Stmt parentsOf;
113
114 db_static_prepare(&parentsOf, "SELECT pid FROM plink WHERE cid=:rid");
 
 
115 db_bind_int(&parentsOf, ":rid", rid);
116 bag_insert(&needToCheck, rid);
117 while( db_step(&parentsOf)==SQLITE_ROW ){
118 bag_insert(&needToCheck, db_column_int(&parentsOf, 0));
119 }
120
--- src/leaf.c
+++ src/leaf.c
@@ -40,11 +40,12 @@
40 " EXCEPT"
41 " SELECT pid FROM plink"
42 " WHERE coalesce((SELECT value FROM tagxref"
43 " WHERE tagid=%d AND rid=plink.pid),'trunk')"
44 " == coalesce((SELECT value FROM tagxref"
45 " WHERE tagid=%d AND rid=plink.cid),'trunk')"
46 " AND isprim",
47 TAG_BRANCH, TAG_BRANCH
48 );
49 }
50
51 /*
@@ -62,11 +63,11 @@
63 static Stmt removeLeaf;
64 int rc;
65
66 db_static_prepare(&checkIfLeaf,
67 "SELECT 1 FROM plink"
68 " WHERE pid=:rid AND isprim"
69 " AND coalesce((SELECT value FROM tagxref"
70 " WHERE tagid=%d AND rid=:rid),'trunk')"
71 " == coalesce((SELECT value FROM tagxref"
72 " WHERE tagid=%d AND rid=plink.cid),'trunk');",
73 TAG_BRANCH, TAG_BRANCH
@@ -109,11 +110,13 @@
110 ** Schedule a leaf check for "rid" and its parents.
111 */
112 void leaf_eventually_check(int rid){
113 static Stmt parentsOf;
114
115 db_static_prepare(&parentsOf,
116 "SELECT pid FROM plink WHERE cid=:rid AND pid>0"
117 );
118 db_bind_int(&parentsOf, ":rid", rid);
119 bag_insert(&needToCheck, rid);
120 while( db_step(&parentsOf)==SQLITE_ROW ){
121 bag_insert(&needToCheck, db_column_int(&parentsOf, 0));
122 }
123
+93 -16
--- src/login.c
+++ src/login.c
@@ -114,10 +114,24 @@
114114
if( fossil_stricmp(zPw, zPassword)!=0 ) return 0;
115115
uid = db_int(0, "SELECT uid FROM user WHERE login='anonymous'"
116116
" AND length(pw)>0 AND length(cap)>0");
117117
return uid;
118118
}
119
+
120
+/*
121
+** Make sure the accesslog table exists. Create it if it does not
122
+*/
123
+void create_accesslog_table(void){
124
+ db_multi_exec(
125
+ "CREATE TABLE IF NOT EXISTS %s.accesslog("
126
+ " uname TEXT,"
127
+ " ipaddr TEXT,"
128
+ " success BOOLEAN,"
129
+ " mtime TIMESTAMP"
130
+ ");", db_name("repository")
131
+ );
132
+}
119133
120134
/*
121135
** Make a record of a login attempt, if login record keeping is enabled.
122136
*/
123137
static void record_login_attempt(
@@ -124,20 +138,15 @@
124138
const char *zUsername, /* Name of user logging in */
125139
const char *zIpAddr, /* IP address from which they logged in */
126140
int bSuccess /* True if the attempt was a success */
127141
){
128142
if( !db_get_boolean("access-log", 0) ) return;
143
+ create_accesslog_table();
129144
db_multi_exec(
130
- "CREATE TABLE IF NOT EXISTS %s.accesslog("
131
- " uname TEXT,"
132
- " ipaddr TEXT,"
133
- " success BOOLEAN,"
134
- " mtime TIMESTAMP"
135
- ");"
136145
"INSERT INTO accesslog(uname,ipaddr,success,mtime)"
137146
"VALUES(%Q,%Q,%d,julianday('now'));",
138
- db_name("repository"), zUsername, zIpAddr, bSuccess
147
+ zUsername, zIpAddr, bSuccess
139148
);
140149
}
141150
142151
/*
143152
** WEBPAGE: login
@@ -246,11 +255,11 @@
246255
cgi_set_cookie(zCookieName, zCookie, 0, expires);
247256
record_login_attempt(zUsername, zIpAddr, 1);
248257
db_multi_exec(
249258
"UPDATE user SET cookie=%Q, ipaddr=%Q, "
250259
" cexpire=julianday('now')+%d/86400.0 WHERE uid=%d",
251
- zCookie, zIpAddr, expires, uid
260
+ zCookie, ipPrefix(zIpAddr), expires, uid
252261
);
253262
redirect_to_g();
254263
}
255264
}
256265
style_header("Login/Logout");
@@ -277,14 +286,28 @@
277286
" WHERE login='anonymous'"
278287
" AND cap!=''");
279288
}
280289
@ <tr>
281290
@ <td></td>
282
- @ <td><input type="submit" name="in" value="Login" /></td>
291
+ @ <td><input type="submit" name="in" value="Login"
292
+ @ onClick="chngAction(this.form)" /></td>
283293
@ </tr>
284294
@ </table>
285
- @ <script type="text/JavaScript">document.getElementById('u').focus()</script>
295
+ @ <script type="text/JavaScript">
296
+ @ document.getElementById('u').focus()
297
+ @ function chngAction(form){
298
+ if( g.sslNotAvailable==0
299
+ && memcmp(g.zBaseURL,"https:",6)!=0
300
+ && db_get_boolean("https-login",0)
301
+ ){
302
+ char *zSSL = mprintf("https:%s", &g.zBaseURL[5]);
303
+ @ if( form.u.value!="anonymous" ){
304
+ @ form.action = "%h(zSSL)/login";
305
+ @ }
306
+ }
307
+ @ }
308
+ @ </script>
286309
if( g.zLogin==0 ){
287310
@ <p>Enter
288311
}else{
289312
@ <p>You are currently logged in as <b>%h(g.zLogin)</b></p>
290313
@ <p>To change your login to a different user, enter
@@ -391,11 +414,11 @@
391414
"SELECT uid FROM user"
392415
" WHERE uid=%d"
393416
" AND cookie=%Q"
394417
" AND ipaddr=%Q"
395418
" AND cexpire>julianday('now')",
396
- atoi(zCookie), zCookie, zRemoteAddr
419
+ atoi(zCookie), zCookie, ipPrefix(zRemoteAddr)
397420
);
398421
}else if( memcmp(zCookie,"anon/",5)==0 ){
399422
/* Cookies of the form "anon/TIME/HASH". The TIME must not be
400423
** too old and the sha1 hash of TIME+IPADDR+SECRET must match HASH.
401424
** SECRET is the "captcha-secret" value in the repository.
@@ -477,27 +500,31 @@
477500
/* Set the capabilities */
478501
login_set_capabilities(zCap);
479502
login_set_anon_nobody_capabilities();
480503
}
481504
505
+/*
506
+** Memory of settings
507
+*/
508
+static int login_anon_once = 1;
509
+
482510
/*
483511
** Add the default privileges of users "nobody" and "anonymous" as appropriate
484512
** for the user g.zLogin.
485513
*/
486514
void login_set_anon_nobody_capabilities(void){
487
- static int once = 1;
488
- if( g.zLogin && once ){
515
+ if( g.zLogin && login_anon_once ){
489516
const char *zCap;
490517
/* All logged-in users inherit privileges from "nobody" */
491518
zCap = db_text("", "SELECT cap FROM user WHERE login = 'nobody'");
492519
login_set_capabilities(zCap);
493520
if( fossil_strcmp(g.zLogin, "nobody")!=0 ){
494521
/* All logged-in users inherit privileges from "anonymous" */
495522
zCap = db_text("", "SELECT cap FROM user WHERE login = 'anonymous'");
496523
login_set_capabilities(zCap);
497524
}
498
- once = 0;
525
+ login_anon_once = 0;
499526
}
500527
}
501528
502529
/*
503530
** Set the global capability flags based on a capability string.
@@ -594,18 +621,68 @@
594621
case 's': rc = g.okSetup; break;
595622
case 't': rc = g.okTktFmt; break;
596623
/* case 'u': READER */
597624
/* case 'v': DEVELOPER */
598625
case 'w': rc = g.okWrTkt; break;
599
- /* case 'x': */
626
+ case 'x': rc = g.okPrivate; break;
600627
/* case 'y': */
601628
case 'z': rc = g.okZip; break;
602629
default: rc = 0; break;
603630
}
604631
}
605632
return rc;
606633
}
634
+
635
+/*
636
+** Change the login to zUser.
637
+*/
638
+void login_as_user(const char *zUser){
639
+ char *zCap = ""; /* New capabilities */
640
+
641
+ /* Turn off all capabilities from prior logins */
642
+ g.okSetup = 0;
643
+ g.okAdmin = 0;
644
+ g.okDelete = 0;
645
+ g.okPassword = 0;
646
+ g.okQuery = 0;
647
+ g.okWrite = 0;
648
+ g.okRead = 0;
649
+ g.okHistory = 0;
650
+ g.okClone = 0;
651
+ g.okRdWiki = 0;
652
+ g.okNewWiki = 0;
653
+ g.okApndWiki = 0;
654
+ g.okWrWiki = 0;
655
+ g.okRdTkt = 0;
656
+ g.okNewTkt = 0;
657
+ g.okApndTkt = 0;
658
+ g.okWrTkt = 0;
659
+ g.okAttach = 0;
660
+ g.okTktFmt = 0;
661
+ g.okRdAddr = 0;
662
+ g.okZip = 0;
663
+ g.okPrivate = 0;
664
+
665
+ /* Set the global variables recording the userid and login. The
666
+ ** "nobody" user is a special case in that g.zLogin==0.
667
+ */
668
+ g.userUid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zUser);
669
+ if( g.userUid==0 ){
670
+ zUser = 0;
671
+ g.userUid = db_int(0, "SELECT uid FROM user WHERE login='nobody'");
672
+ }
673
+ if( g.userUid ){
674
+ zCap = db_text("", "SELECT cap FROM user WHERE uid=%d", g.userUid);
675
+ }
676
+ if( fossil_strcmp(zUser,"nobody")==0 ) zUser = 0;
677
+ g.zLogin = fossil_strdup(zUser);
678
+
679
+ /* Set the capabilities */
680
+ login_set_capabilities(zCap);
681
+ login_anon_once = 1;
682
+ login_set_anon_nobody_capabilities();
683
+}
607684
608685
/*
609686
** Call this routine when the credential check fails. It causes
610687
** a redirect to the "login" page.
611688
*/
@@ -745,11 +822,11 @@
745822
cgi_set_cookie(zCookieName, zCookie, 0, expires);
746823
record_login_attempt(zUsername, zIpAddr, 1);
747824
db_multi_exec(
748825
"UPDATE user SET cookie=%Q, ipaddr=%Q, "
749826
" cexpire=julianday('now')+%d/86400.0 WHERE uid=%d",
750
- zCookie, zIpAddr, expires, uid
827
+ zCookie, ipPrefix(zIpAddr), expires, uid
751828
);
752829
redirect_to_g();
753830
754831
}
755832
}
756833
--- src/login.c
+++ src/login.c
@@ -114,10 +114,24 @@
114 if( fossil_stricmp(zPw, zPassword)!=0 ) return 0;
115 uid = db_int(0, "SELECT uid FROM user WHERE login='anonymous'"
116 " AND length(pw)>0 AND length(cap)>0");
117 return uid;
118 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
120 /*
121 ** Make a record of a login attempt, if login record keeping is enabled.
122 */
123 static void record_login_attempt(
@@ -124,20 +138,15 @@
124 const char *zUsername, /* Name of user logging in */
125 const char *zIpAddr, /* IP address from which they logged in */
126 int bSuccess /* True if the attempt was a success */
127 ){
128 if( !db_get_boolean("access-log", 0) ) return;
 
129 db_multi_exec(
130 "CREATE TABLE IF NOT EXISTS %s.accesslog("
131 " uname TEXT,"
132 " ipaddr TEXT,"
133 " success BOOLEAN,"
134 " mtime TIMESTAMP"
135 ");"
136 "INSERT INTO accesslog(uname,ipaddr,success,mtime)"
137 "VALUES(%Q,%Q,%d,julianday('now'));",
138 db_name("repository"), zUsername, zIpAddr, bSuccess
139 );
140 }
141
142 /*
143 ** WEBPAGE: login
@@ -246,11 +255,11 @@
246 cgi_set_cookie(zCookieName, zCookie, 0, expires);
247 record_login_attempt(zUsername, zIpAddr, 1);
248 db_multi_exec(
249 "UPDATE user SET cookie=%Q, ipaddr=%Q, "
250 " cexpire=julianday('now')+%d/86400.0 WHERE uid=%d",
251 zCookie, zIpAddr, expires, uid
252 );
253 redirect_to_g();
254 }
255 }
256 style_header("Login/Logout");
@@ -277,14 +286,28 @@
277 " WHERE login='anonymous'"
278 " AND cap!=''");
279 }
280 @ <tr>
281 @ <td></td>
282 @ <td><input type="submit" name="in" value="Login" /></td>
 
283 @ </tr>
284 @ </table>
285 @ <script type="text/JavaScript">document.getElementById('u').focus()</script>
 
 
 
 
 
 
 
 
 
 
 
 
 
286 if( g.zLogin==0 ){
287 @ <p>Enter
288 }else{
289 @ <p>You are currently logged in as <b>%h(g.zLogin)</b></p>
290 @ <p>To change your login to a different user, enter
@@ -391,11 +414,11 @@
391 "SELECT uid FROM user"
392 " WHERE uid=%d"
393 " AND cookie=%Q"
394 " AND ipaddr=%Q"
395 " AND cexpire>julianday('now')",
396 atoi(zCookie), zCookie, zRemoteAddr
397 );
398 }else if( memcmp(zCookie,"anon/",5)==0 ){
399 /* Cookies of the form "anon/TIME/HASH". The TIME must not be
400 ** too old and the sha1 hash of TIME+IPADDR+SECRET must match HASH.
401 ** SECRET is the "captcha-secret" value in the repository.
@@ -477,27 +500,31 @@
477 /* Set the capabilities */
478 login_set_capabilities(zCap);
479 login_set_anon_nobody_capabilities();
480 }
481
 
 
 
 
 
482 /*
483 ** Add the default privileges of users "nobody" and "anonymous" as appropriate
484 ** for the user g.zLogin.
485 */
486 void login_set_anon_nobody_capabilities(void){
487 static int once = 1;
488 if( g.zLogin && once ){
489 const char *zCap;
490 /* All logged-in users inherit privileges from "nobody" */
491 zCap = db_text("", "SELECT cap FROM user WHERE login = 'nobody'");
492 login_set_capabilities(zCap);
493 if( fossil_strcmp(g.zLogin, "nobody")!=0 ){
494 /* All logged-in users inherit privileges from "anonymous" */
495 zCap = db_text("", "SELECT cap FROM user WHERE login = 'anonymous'");
496 login_set_capabilities(zCap);
497 }
498 once = 0;
499 }
500 }
501
502 /*
503 ** Set the global capability flags based on a capability string.
@@ -594,18 +621,68 @@
594 case 's': rc = g.okSetup; break;
595 case 't': rc = g.okTktFmt; break;
596 /* case 'u': READER */
597 /* case 'v': DEVELOPER */
598 case 'w': rc = g.okWrTkt; break;
599 /* case 'x': */
600 /* case 'y': */
601 case 'z': rc = g.okZip; break;
602 default: rc = 0; break;
603 }
604 }
605 return rc;
606 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
607
608 /*
609 ** Call this routine when the credential check fails. It causes
610 ** a redirect to the "login" page.
611 */
@@ -745,11 +822,11 @@
745 cgi_set_cookie(zCookieName, zCookie, 0, expires);
746 record_login_attempt(zUsername, zIpAddr, 1);
747 db_multi_exec(
748 "UPDATE user SET cookie=%Q, ipaddr=%Q, "
749 " cexpire=julianday('now')+%d/86400.0 WHERE uid=%d",
750 zCookie, zIpAddr, expires, uid
751 );
752 redirect_to_g();
753
754 }
755 }
756
--- src/login.c
+++ src/login.c
@@ -114,10 +114,24 @@
114 if( fossil_stricmp(zPw, zPassword)!=0 ) return 0;
115 uid = db_int(0, "SELECT uid FROM user WHERE login='anonymous'"
116 " AND length(pw)>0 AND length(cap)>0");
117 return uid;
118 }
119
120 /*
121 ** Make sure the accesslog table exists. Create it if it does not
122 */
123 void create_accesslog_table(void){
124 db_multi_exec(
125 "CREATE TABLE IF NOT EXISTS %s.accesslog("
126 " uname TEXT,"
127 " ipaddr TEXT,"
128 " success BOOLEAN,"
129 " mtime TIMESTAMP"
130 ");", db_name("repository")
131 );
132 }
133
134 /*
135 ** Make a record of a login attempt, if login record keeping is enabled.
136 */
137 static void record_login_attempt(
@@ -124,20 +138,15 @@
138 const char *zUsername, /* Name of user logging in */
139 const char *zIpAddr, /* IP address from which they logged in */
140 int bSuccess /* True if the attempt was a success */
141 ){
142 if( !db_get_boolean("access-log", 0) ) return;
143 create_accesslog_table();
144 db_multi_exec(
 
 
 
 
 
 
145 "INSERT INTO accesslog(uname,ipaddr,success,mtime)"
146 "VALUES(%Q,%Q,%d,julianday('now'));",
147 zUsername, zIpAddr, bSuccess
148 );
149 }
150
151 /*
152 ** WEBPAGE: login
@@ -246,11 +255,11 @@
255 cgi_set_cookie(zCookieName, zCookie, 0, expires);
256 record_login_attempt(zUsername, zIpAddr, 1);
257 db_multi_exec(
258 "UPDATE user SET cookie=%Q, ipaddr=%Q, "
259 " cexpire=julianday('now')+%d/86400.0 WHERE uid=%d",
260 zCookie, ipPrefix(zIpAddr), expires, uid
261 );
262 redirect_to_g();
263 }
264 }
265 style_header("Login/Logout");
@@ -277,14 +286,28 @@
286 " WHERE login='anonymous'"
287 " AND cap!=''");
288 }
289 @ <tr>
290 @ <td></td>
291 @ <td><input type="submit" name="in" value="Login"
292 @ onClick="chngAction(this.form)" /></td>
293 @ </tr>
294 @ </table>
295 @ <script type="text/JavaScript">
296 @ document.getElementById('u').focus()
297 @ function chngAction(form){
298 if( g.sslNotAvailable==0
299 && memcmp(g.zBaseURL,"https:",6)!=0
300 && db_get_boolean("https-login",0)
301 ){
302 char *zSSL = mprintf("https:%s", &g.zBaseURL[5]);
303 @ if( form.u.value!="anonymous" ){
304 @ form.action = "%h(zSSL)/login";
305 @ }
306 }
307 @ }
308 @ </script>
309 if( g.zLogin==0 ){
310 @ <p>Enter
311 }else{
312 @ <p>You are currently logged in as <b>%h(g.zLogin)</b></p>
313 @ <p>To change your login to a different user, enter
@@ -391,11 +414,11 @@
414 "SELECT uid FROM user"
415 " WHERE uid=%d"
416 " AND cookie=%Q"
417 " AND ipaddr=%Q"
418 " AND cexpire>julianday('now')",
419 atoi(zCookie), zCookie, ipPrefix(zRemoteAddr)
420 );
421 }else if( memcmp(zCookie,"anon/",5)==0 ){
422 /* Cookies of the form "anon/TIME/HASH". The TIME must not be
423 ** too old and the sha1 hash of TIME+IPADDR+SECRET must match HASH.
424 ** SECRET is the "captcha-secret" value in the repository.
@@ -477,27 +500,31 @@
500 /* Set the capabilities */
501 login_set_capabilities(zCap);
502 login_set_anon_nobody_capabilities();
503 }
504
505 /*
506 ** Memory of settings
507 */
508 static int login_anon_once = 1;
509
510 /*
511 ** Add the default privileges of users "nobody" and "anonymous" as appropriate
512 ** for the user g.zLogin.
513 */
514 void login_set_anon_nobody_capabilities(void){
515 if( g.zLogin && login_anon_once ){
 
516 const char *zCap;
517 /* All logged-in users inherit privileges from "nobody" */
518 zCap = db_text("", "SELECT cap FROM user WHERE login = 'nobody'");
519 login_set_capabilities(zCap);
520 if( fossil_strcmp(g.zLogin, "nobody")!=0 ){
521 /* All logged-in users inherit privileges from "anonymous" */
522 zCap = db_text("", "SELECT cap FROM user WHERE login = 'anonymous'");
523 login_set_capabilities(zCap);
524 }
525 login_anon_once = 0;
526 }
527 }
528
529 /*
530 ** Set the global capability flags based on a capability string.
@@ -594,18 +621,68 @@
621 case 's': rc = g.okSetup; break;
622 case 't': rc = g.okTktFmt; break;
623 /* case 'u': READER */
624 /* case 'v': DEVELOPER */
625 case 'w': rc = g.okWrTkt; break;
626 case 'x': rc = g.okPrivate; break;
627 /* case 'y': */
628 case 'z': rc = g.okZip; break;
629 default: rc = 0; break;
630 }
631 }
632 return rc;
633 }
634
635 /*
636 ** Change the login to zUser.
637 */
638 void login_as_user(const char *zUser){
639 char *zCap = ""; /* New capabilities */
640
641 /* Turn off all capabilities from prior logins */
642 g.okSetup = 0;
643 g.okAdmin = 0;
644 g.okDelete = 0;
645 g.okPassword = 0;
646 g.okQuery = 0;
647 g.okWrite = 0;
648 g.okRead = 0;
649 g.okHistory = 0;
650 g.okClone = 0;
651 g.okRdWiki = 0;
652 g.okNewWiki = 0;
653 g.okApndWiki = 0;
654 g.okWrWiki = 0;
655 g.okRdTkt = 0;
656 g.okNewTkt = 0;
657 g.okApndTkt = 0;
658 g.okWrTkt = 0;
659 g.okAttach = 0;
660 g.okTktFmt = 0;
661 g.okRdAddr = 0;
662 g.okZip = 0;
663 g.okPrivate = 0;
664
665 /* Set the global variables recording the userid and login. The
666 ** "nobody" user is a special case in that g.zLogin==0.
667 */
668 g.userUid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zUser);
669 if( g.userUid==0 ){
670 zUser = 0;
671 g.userUid = db_int(0, "SELECT uid FROM user WHERE login='nobody'");
672 }
673 if( g.userUid ){
674 zCap = db_text("", "SELECT cap FROM user WHERE uid=%d", g.userUid);
675 }
676 if( fossil_strcmp(zUser,"nobody")==0 ) zUser = 0;
677 g.zLogin = fossil_strdup(zUser);
678
679 /* Set the capabilities */
680 login_set_capabilities(zCap);
681 login_anon_once = 1;
682 login_set_anon_nobody_capabilities();
683 }
684
685 /*
686 ** Call this routine when the credential check fails. It causes
687 ** a redirect to the "login" page.
688 */
@@ -745,11 +822,11 @@
822 cgi_set_cookie(zCookieName, zCookie, 0, expires);
823 record_login_attempt(zUsername, zIpAddr, 1);
824 db_multi_exec(
825 "UPDATE user SET cookie=%Q, ipaddr=%Q, "
826 " cexpire=julianday('now')+%d/86400.0 WHERE uid=%d",
827 zCookie, ipPrefix(zIpAddr), expires, uid
828 );
829 redirect_to_g();
830
831 }
832 }
833
+172 -35
--- src/main.c
+++ src/main.c
@@ -73,10 +73,11 @@
7373
char *zBaseURL; /* Full text of the URL being served */
7474
char *zTop; /* Parent directory of zPath */
7575
const char *zContentType; /* The content type of the input HTTP request */
7676
int iErrPriority; /* Priority of current error message */
7777
char *zErrMsg; /* Text of an error message */
78
+ int sslNotAvailable; /* SSL is not available. Do not redirect to https: */
7879
Blob cgiIn; /* Input to an xfer www method */
7980
int cgiOutput; /* Write error and status messages to CGI */
8081
int xferPanic; /* Write error messages in XFER protocol */
8182
int fullHttpReply; /* True for full HTTP reply. False for CGI reply */
8283
Th_Interp *interp; /* The TH1 interpreter */
@@ -795,14 +796,18 @@
795796
** the fossil tree. Set g.zTop to g.zBaseURL without the
796797
** leading "http://" and the host and port.
797798
*/
798799
void set_base_url(void){
799800
int i;
800
- const char *zHost = PD("HTTP_HOST","");
801
- const char *zMode = PD("HTTPS","off");
802
- const char *zCur = PD("SCRIPT_NAME","/");
801
+ const char *zHost;
802
+ const char *zMode;
803
+ const char *zCur;
803804
805
+ if( g.zBaseURL!=0 ) return;
806
+ zHost = PD("HTTP_HOST","");
807
+ zMode = PD("HTTPS","off");
808
+ zCur = PD("SCRIPT_NAME","/");
804809
i = strlen(zCur);
805810
while( i>0 && zCur[i-1]=='/' ) i--;
806811
if( strcmp(zMode,"on")==0 ){
807812
g.zBaseURL = mprintf("https://%s%.*s", zHost, i, zCur);
808813
g.zTop = &g.zBaseURL[8+strlen(zHost)];
@@ -890,36 +895,54 @@
890895
/* If the repository has not been opened already, then find the
891896
** repository based on the first element of PATH_INFO and open it.
892897
*/
893898
zPathInfo = PD("PATH_INFO","");
894899
if( !g.repositoryOpen ){
895
- char *zRepo;
900
+ char *zRepo, *zToFree;
896901
const char *zOldScript = PD("SCRIPT_NAME", "");
897902
char *zNewScript;
898903
int j, k;
904
+ i64 szFile;
899905
900906
i = 1;
901
- while( zPathInfo[i] && zPathInfo[i]!='/' ){ i++; }
902
- zRepo = mprintf("%s%.*s.fossil",g.zRepositoryName,i,zPathInfo);
903
-
904
- /* To avoid mischief, make sure the repository basename contains no
905
- ** characters other than alphanumerics, "-", and "_".
906
- */
907
- for(j=strlen(g.zRepositoryName)+1, k=0; k<i-1; j++, k++){
908
- if( !fossil_isalnum(zRepo[j]) && zRepo[j]!='-' ) zRepo[j] = '_';
909
- }
910
- if( zRepo[0]=='/' && zRepo[1]=='/' ) zRepo++;
911
-
912
- if( file_size(zRepo)<1024 ){
913
- if( zNotFound ){
914
- cgi_redirect(zNotFound);
915
- }else{
916
- @ <h1>Not Found</h1>
917
- cgi_set_status(404, "not found");
918
- cgi_reply();
919
- }
920
- return;
907
+ while( 1 ){
908
+ while( zPathInfo[i] && zPathInfo[i]!='/' ){ i++; }
909
+ zRepo = zToFree = mprintf("%s%.*s.fossil",g.zRepositoryName,i,zPathInfo);
910
+
911
+ /* To avoid mischief, make sure the repository basename contains no
912
+ ** characters other than alphanumerics, "-", "/", and "_".
913
+ */
914
+ for(j=strlen(g.zRepositoryName)+1, k=0; k<i-1; j++, k++){
915
+ if( !fossil_isalnum(zRepo[j]) && zRepo[j]!='-' && zRepo[j]!='/' ){
916
+ zRepo[j] = '_';
917
+ }
918
+ }
919
+ if( zRepo[0]=='/' && zRepo[1]=='/' ){ zRepo++; j--; }
920
+
921
+ szFile = file_size(zRepo);
922
+ if( zPathInfo[i]=='/' && szFile<0 ){
923
+ assert( strcmp(&zRepo[j], ".fossil")==0 );
924
+ zRepo[j] = 0;
925
+ if( file_isdir(zRepo)==1 ){
926
+ fossil_free(zToFree);
927
+ i++;
928
+ continue;
929
+ }
930
+ zRepo[j] = '.';
931
+ }
932
+
933
+ if( szFile<1024 ){
934
+ if( zNotFound ){
935
+ cgi_redirect(zNotFound);
936
+ }else{
937
+ @ <h1>Not Found</h1>
938
+ cgi_set_status(404, "not found");
939
+ cgi_reply();
940
+ }
941
+ return;
942
+ }
943
+ break;
921944
}
922945
zNewScript = mprintf("%s%.*s", zOldScript, i, zPathInfo);
923946
cgi_replace_parameter("PATH_INFO", &zPathInfo[i+1]);
924947
zPathInfo += i;
925948
cgi_replace_parameter("SCRIPT_NAME", zNewScript);
@@ -945,19 +968,61 @@
945968
fossil_redirect_home();
946969
}else{
947970
zPath = mprintf("%s", zPathInfo);
948971
}
949972
950
- /* Remove the leading "/" at the beginning of the path.
973
+ /* Make g.zPath point to the first element of the path. Make
974
+ ** g.zExtra point to everything past that point.
951975
*/
952
- g.zPath = &zPath[1];
953
- for(i=1; zPath[i] && zPath[i]!='/'; i++){}
954
- if( zPath[i]=='/' ){
955
- zPath[i] = 0;
956
- g.zExtra = &zPath[i+1];
957
- }else{
958
- g.zExtra = 0;
976
+ while(1){
977
+ char *zAltRepo = 0;
978
+ g.zPath = &zPath[1];
979
+ for(i=1; zPath[i] && zPath[i]!='/'; i++){}
980
+ if( zPath[i]=='/' ){
981
+ zPath[i] = 0;
982
+ g.zExtra = &zPath[i+1];
983
+
984
+ /* Look for sub-repositories. A sub-repository is another repository
985
+ ** that accepts the login credentials of the current repository. A
986
+ ** subrepository is identified by a CONFIG table entry "subrepo:NAME"
987
+ ** where NAME is the first component of the path. The value of the
988
+ ** the CONFIG entries is the string "USER:FILENAME" where USER is the
989
+ ** USER name to log in as in the subrepository and FILENAME is the
990
+ ** repository filename.
991
+ */
992
+ zAltRepo = db_text(0, "SELECT value FROM config WHERE name='subrepo:%q'",
993
+ g.zPath);
994
+ if( zAltRepo ){
995
+ int nHost;
996
+ int jj;
997
+ char *zUser = zAltRepo;
998
+ login_check_credentials();
999
+ for(jj=0; zAltRepo[jj] && zAltRepo[jj]!=':'; jj++){}
1000
+ if( zAltRepo[jj]==':' ){
1001
+ zAltRepo[jj] = 0;
1002
+ zAltRepo += jj+1;
1003
+ }else{
1004
+ zUser = "nobody";
1005
+ }
1006
+ if( zAltRepo[0]!='/' ){
1007
+ zAltRepo = mprintf("%s/../%s", g.zRepositoryName, zAltRepo);
1008
+ file_simplify_name(zAltRepo, -1);
1009
+ }
1010
+ db_close(1);
1011
+ db_open_repository(zAltRepo);
1012
+ login_as_user(zUser);
1013
+ g.okPassword = 0;
1014
+ zPath += i;
1015
+ nHost = g.zTop - g.zBaseURL;
1016
+ g.zBaseURL = mprintf("%z/%s", g.zBaseURL, g.zPath);
1017
+ g.zTop = g.zBaseURL + nHost;
1018
+ continue;
1019
+ }
1020
+ }else{
1021
+ g.zExtra = 0;
1022
+ }
1023
+ break;
9591024
}
9601025
if( g.zExtra ){
9611026
/* CGI parameters get this treatment elsewhere, but places like getfile
9621027
** will use g.zExtra directly.
9631028
*/
@@ -1005,11 +1070,13 @@
10051070
** the values of standard CGI environment variables.
10061071
*/
10071072
void cmd_cgi(void){
10081073
const char *zFile;
10091074
const char *zNotFound = 0;
1010
- Blob config, line, key, value;
1075
+ char **azRedirect = 0; /* List of repositories to redirect to */
1076
+ int nRedirect = 0; /* Number of entries in azRedirect */
1077
+ Blob config, line, key, value, value2;
10111078
if( g.argc==3 && fossil_strcmp(g.argv[1],"cgi")==0 ){
10121079
zFile = g.argv[2];
10131080
}else{
10141081
zFile = g.argv[1];
10151082
}
@@ -1059,17 +1126,82 @@
10591126
}
10601127
if( blob_eq(&key, "localauth") ){
10611128
g.useLocalauth = 1;
10621129
continue;
10631130
}
1131
+ if( blob_eq(&key, "redirect:") && blob_token(&line, &value)
1132
+ && blob_token(&line, &value2) ){
1133
+ nRedirect++;
1134
+ azRedirect = fossil_realloc(azRedirect, 2*nRedirect*sizeof(char*));
1135
+ azRedirect[nRedirect*2-2] = mprintf("%s", blob_str(&value));
1136
+ azRedirect[nRedirect*2-1] = mprintf("%s", blob_str(&value2));
1137
+ blob_reset(&value);
1138
+ blob_reset(&value2);
1139
+ continue;
1140
+ }
10641141
}
10651142
blob_reset(&config);
1066
- if( g.db==0 && g.zRepositoryName==0 ){
1143
+ if( g.db==0 && g.zRepositoryName==0 && nRedirect==0 ){
10671144
cgi_panic("Unable to find or open the project repository");
10681145
}
10691146
cgi_init();
1070
- process_one_web_page(zNotFound);
1147
+ if( nRedirect ){
1148
+ redirect_web_page(nRedirect, azRedirect);
1149
+ }else{
1150
+ process_one_web_page(zNotFound);
1151
+ }
1152
+}
1153
+
1154
+/* If the CGI program contains one or more lines of the form
1155
+**
1156
+** redirect: repository-filename http://hostname/path/%s
1157
+**
1158
+** then control jumps here. Search each repository for an artifact ID
1159
+** that matches the "name" CGI parameter and for the first match,
1160
+** redirect to the corresponding URL with the "name" CGI parameter
1161
+** inserted. Paint an error page if no match is found.
1162
+**
1163
+** If there is a line of the form:
1164
+**
1165
+** redirect: * URL
1166
+**
1167
+** Then a redirect is made to URL if no match is found. Otherwise a
1168
+** very primative error message is returned.
1169
+*/
1170
+void redirect_web_page(int nRedirect, char **azRedirect){
1171
+ int i; /* Loop counter */
1172
+ const char *zNotFound = 0; /* Not found URL */
1173
+ const char *zName = P("name");
1174
+ set_base_url();
1175
+ if( zName==0 ){
1176
+ zName = P("SCRIPT_NAME");
1177
+ if( zName && zName[0]=='/' ) zName++;
1178
+ }
1179
+ if( zName && validate16(zName, strlen(zName)) ){
1180
+ for(i=0; i<nRedirect; i++){
1181
+ if( strcmp(azRedirect[i*2],"*")==0 ){
1182
+ zNotFound = azRedirect[i*2+1];
1183
+ continue;
1184
+ }
1185
+ db_open_repository(azRedirect[i*2]);
1186
+ if( db_exists("SELECT 1 FROM blob WHERE uuid GLOB '%s*'", zName) ){
1187
+ cgi_redirectf(azRedirect[i*2+1], zName);
1188
+ return;
1189
+ }
1190
+ db_close(1);
1191
+ }
1192
+ }
1193
+ if( zNotFound ){
1194
+ cgi_redirectf(zNotFound, zName);
1195
+ }else{
1196
+ @ <html>
1197
+ @ <head><title>No Such Object</title></head>
1198
+ @ <body>
1199
+ @ <p>No such object: <b>%h(zName)</b></p>
1200
+ @ </body>
1201
+ cgi_reply();
1202
+ }
10711203
}
10721204
10731205
/*
10741206
** If g.argv[2] exists then it is either the name of a repository
10751207
** that will be used by a server, or else it is a directory that
@@ -1128,17 +1260,21 @@
11281260
** Other options:
11291261
**
11301262
** --localauth Password signin is not required if this is true and
11311263
** the input comes from 127.0.0.1 and the "localauth"
11321264
** setting is not disabled.
1265
+**
1266
+** --nossl SSL connections are not available so do not
1267
+** redirect from http: to https:.
11331268
*/
11341269
void cmd_http(void){
11351270
const char *zIpAddr;
11361271
const char *zNotFound;
11371272
const char *zHost;
11381273
zNotFound = find_option("notfound", 0, 1);
11391274
g.useLocalauth = find_option("localauth", 0, 0)!=0;
1275
+ g.sslNotAvailable = find_option("nossl", 0, 0)!=0;
11401276
if( find_option("https",0,0)!=0 ) cgi_replace_parameter("HTTPS","on");
11411277
zHost = find_option("host", 0, 1);
11421278
if( zHost ) cgi_replace_parameter("HTTP_HOST",zHost);
11431279
g.cgiOutput = 1;
11441280
if( g.argc!=2 && g.argc!=3 && g.argc!=6 ){
@@ -1287,10 +1423,11 @@
12871423
}
12881424
db_close(1);
12891425
if( cgi_http_server(iPort, mxPort, zBrowserCmd, flags) ){
12901426
fossil_fatal("unable to listen on TCP socket %d", iPort);
12911427
}
1428
+ g.sslNotAvailable = 1;
12921429
g.httpIn = stdin;
12931430
g.httpOut = stdout;
12941431
if( g.fHttpTrace || g.fSqlTrace ){
12951432
fprintf(stderr, "====== SERVER pid %d =======\n", getpid());
12961433
}
12971434
--- src/main.c
+++ src/main.c
@@ -73,10 +73,11 @@
73 char *zBaseURL; /* Full text of the URL being served */
74 char *zTop; /* Parent directory of zPath */
75 const char *zContentType; /* The content type of the input HTTP request */
76 int iErrPriority; /* Priority of current error message */
77 char *zErrMsg; /* Text of an error message */
 
78 Blob cgiIn; /* Input to an xfer www method */
79 int cgiOutput; /* Write error and status messages to CGI */
80 int xferPanic; /* Write error messages in XFER protocol */
81 int fullHttpReply; /* True for full HTTP reply. False for CGI reply */
82 Th_Interp *interp; /* The TH1 interpreter */
@@ -795,14 +796,18 @@
795 ** the fossil tree. Set g.zTop to g.zBaseURL without the
796 ** leading "http://" and the host and port.
797 */
798 void set_base_url(void){
799 int i;
800 const char *zHost = PD("HTTP_HOST","");
801 const char *zMode = PD("HTTPS","off");
802 const char *zCur = PD("SCRIPT_NAME","/");
803
 
 
 
 
804 i = strlen(zCur);
805 while( i>0 && zCur[i-1]=='/' ) i--;
806 if( strcmp(zMode,"on")==0 ){
807 g.zBaseURL = mprintf("https://%s%.*s", zHost, i, zCur);
808 g.zTop = &g.zBaseURL[8+strlen(zHost)];
@@ -890,36 +895,54 @@
890 /* If the repository has not been opened already, then find the
891 ** repository based on the first element of PATH_INFO and open it.
892 */
893 zPathInfo = PD("PATH_INFO","");
894 if( !g.repositoryOpen ){
895 char *zRepo;
896 const char *zOldScript = PD("SCRIPT_NAME", "");
897 char *zNewScript;
898 int j, k;
 
899
900 i = 1;
901 while( zPathInfo[i] && zPathInfo[i]!='/' ){ i++; }
902 zRepo = mprintf("%s%.*s.fossil",g.zRepositoryName,i,zPathInfo);
903
904 /* To avoid mischief, make sure the repository basename contains no
905 ** characters other than alphanumerics, "-", and "_".
906 */
907 for(j=strlen(g.zRepositoryName)+1, k=0; k<i-1; j++, k++){
908 if( !fossil_isalnum(zRepo[j]) && zRepo[j]!='-' ) zRepo[j] = '_';
909 }
910 if( zRepo[0]=='/' && zRepo[1]=='/' ) zRepo++;
911
912 if( file_size(zRepo)<1024 ){
913 if( zNotFound ){
914 cgi_redirect(zNotFound);
915 }else{
916 @ <h1>Not Found</h1>
917 cgi_set_status(404, "not found");
918 cgi_reply();
919 }
920 return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
921 }
922 zNewScript = mprintf("%s%.*s", zOldScript, i, zPathInfo);
923 cgi_replace_parameter("PATH_INFO", &zPathInfo[i+1]);
924 zPathInfo += i;
925 cgi_replace_parameter("SCRIPT_NAME", zNewScript);
@@ -945,19 +968,61 @@
945 fossil_redirect_home();
946 }else{
947 zPath = mprintf("%s", zPathInfo);
948 }
949
950 /* Remove the leading "/" at the beginning of the path.
 
951 */
952 g.zPath = &zPath[1];
953 for(i=1; zPath[i] && zPath[i]!='/'; i++){}
954 if( zPath[i]=='/' ){
955 zPath[i] = 0;
956 g.zExtra = &zPath[i+1];
957 }else{
958 g.zExtra = 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
959 }
960 if( g.zExtra ){
961 /* CGI parameters get this treatment elsewhere, but places like getfile
962 ** will use g.zExtra directly.
963 */
@@ -1005,11 +1070,13 @@
1005 ** the values of standard CGI environment variables.
1006 */
1007 void cmd_cgi(void){
1008 const char *zFile;
1009 const char *zNotFound = 0;
1010 Blob config, line, key, value;
 
 
1011 if( g.argc==3 && fossil_strcmp(g.argv[1],"cgi")==0 ){
1012 zFile = g.argv[2];
1013 }else{
1014 zFile = g.argv[1];
1015 }
@@ -1059,17 +1126,82 @@
1059 }
1060 if( blob_eq(&key, "localauth") ){
1061 g.useLocalauth = 1;
1062 continue;
1063 }
 
 
 
 
 
 
 
 
 
 
1064 }
1065 blob_reset(&config);
1066 if( g.db==0 && g.zRepositoryName==0 ){
1067 cgi_panic("Unable to find or open the project repository");
1068 }
1069 cgi_init();
1070 process_one_web_page(zNotFound);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1071 }
1072
1073 /*
1074 ** If g.argv[2] exists then it is either the name of a repository
1075 ** that will be used by a server, or else it is a directory that
@@ -1128,17 +1260,21 @@
1128 ** Other options:
1129 **
1130 ** --localauth Password signin is not required if this is true and
1131 ** the input comes from 127.0.0.1 and the "localauth"
1132 ** setting is not disabled.
 
 
 
1133 */
1134 void cmd_http(void){
1135 const char *zIpAddr;
1136 const char *zNotFound;
1137 const char *zHost;
1138 zNotFound = find_option("notfound", 0, 1);
1139 g.useLocalauth = find_option("localauth", 0, 0)!=0;
 
1140 if( find_option("https",0,0)!=0 ) cgi_replace_parameter("HTTPS","on");
1141 zHost = find_option("host", 0, 1);
1142 if( zHost ) cgi_replace_parameter("HTTP_HOST",zHost);
1143 g.cgiOutput = 1;
1144 if( g.argc!=2 && g.argc!=3 && g.argc!=6 ){
@@ -1287,10 +1423,11 @@
1287 }
1288 db_close(1);
1289 if( cgi_http_server(iPort, mxPort, zBrowserCmd, flags) ){
1290 fossil_fatal("unable to listen on TCP socket %d", iPort);
1291 }
 
1292 g.httpIn = stdin;
1293 g.httpOut = stdout;
1294 if( g.fHttpTrace || g.fSqlTrace ){
1295 fprintf(stderr, "====== SERVER pid %d =======\n", getpid());
1296 }
1297
--- src/main.c
+++ src/main.c
@@ -73,10 +73,11 @@
73 char *zBaseURL; /* Full text of the URL being served */
74 char *zTop; /* Parent directory of zPath */
75 const char *zContentType; /* The content type of the input HTTP request */
76 int iErrPriority; /* Priority of current error message */
77 char *zErrMsg; /* Text of an error message */
78 int sslNotAvailable; /* SSL is not available. Do not redirect to https: */
79 Blob cgiIn; /* Input to an xfer www method */
80 int cgiOutput; /* Write error and status messages to CGI */
81 int xferPanic; /* Write error messages in XFER protocol */
82 int fullHttpReply; /* True for full HTTP reply. False for CGI reply */
83 Th_Interp *interp; /* The TH1 interpreter */
@@ -795,14 +796,18 @@
796 ** the fossil tree. Set g.zTop to g.zBaseURL without the
797 ** leading "http://" and the host and port.
798 */
799 void set_base_url(void){
800 int i;
801 const char *zHost;
802 const char *zMode;
803 const char *zCur;
804
805 if( g.zBaseURL!=0 ) return;
806 zHost = PD("HTTP_HOST","");
807 zMode = PD("HTTPS","off");
808 zCur = PD("SCRIPT_NAME","/");
809 i = strlen(zCur);
810 while( i>0 && zCur[i-1]=='/' ) i--;
811 if( strcmp(zMode,"on")==0 ){
812 g.zBaseURL = mprintf("https://%s%.*s", zHost, i, zCur);
813 g.zTop = &g.zBaseURL[8+strlen(zHost)];
@@ -890,36 +895,54 @@
895 /* If the repository has not been opened already, then find the
896 ** repository based on the first element of PATH_INFO and open it.
897 */
898 zPathInfo = PD("PATH_INFO","");
899 if( !g.repositoryOpen ){
900 char *zRepo, *zToFree;
901 const char *zOldScript = PD("SCRIPT_NAME", "");
902 char *zNewScript;
903 int j, k;
904 i64 szFile;
905
906 i = 1;
907 while( 1 ){
908 while( zPathInfo[i] && zPathInfo[i]!='/' ){ i++; }
909 zRepo = zToFree = mprintf("%s%.*s.fossil",g.zRepositoryName,i,zPathInfo);
910
911 /* To avoid mischief, make sure the repository basename contains no
912 ** characters other than alphanumerics, "-", "/", and "_".
913 */
914 for(j=strlen(g.zRepositoryName)+1, k=0; k<i-1; j++, k++){
915 if( !fossil_isalnum(zRepo[j]) && zRepo[j]!='-' && zRepo[j]!='/' ){
916 zRepo[j] = '_';
917 }
918 }
919 if( zRepo[0]=='/' && zRepo[1]=='/' ){ zRepo++; j--; }
920
921 szFile = file_size(zRepo);
922 if( zPathInfo[i]=='/' && szFile<0 ){
923 assert( strcmp(&zRepo[j], ".fossil")==0 );
924 zRepo[j] = 0;
925 if( file_isdir(zRepo)==1 ){
926 fossil_free(zToFree);
927 i++;
928 continue;
929 }
930 zRepo[j] = '.';
931 }
932
933 if( szFile<1024 ){
934 if( zNotFound ){
935 cgi_redirect(zNotFound);
936 }else{
937 @ <h1>Not Found</h1>
938 cgi_set_status(404, "not found");
939 cgi_reply();
940 }
941 return;
942 }
943 break;
944 }
945 zNewScript = mprintf("%s%.*s", zOldScript, i, zPathInfo);
946 cgi_replace_parameter("PATH_INFO", &zPathInfo[i+1]);
947 zPathInfo += i;
948 cgi_replace_parameter("SCRIPT_NAME", zNewScript);
@@ -945,19 +968,61 @@
968 fossil_redirect_home();
969 }else{
970 zPath = mprintf("%s", zPathInfo);
971 }
972
973 /* Make g.zPath point to the first element of the path. Make
974 ** g.zExtra point to everything past that point.
975 */
976 while(1){
977 char *zAltRepo = 0;
978 g.zPath = &zPath[1];
979 for(i=1; zPath[i] && zPath[i]!='/'; i++){}
980 if( zPath[i]=='/' ){
981 zPath[i] = 0;
982 g.zExtra = &zPath[i+1];
983
984 /* Look for sub-repositories. A sub-repository is another repository
985 ** that accepts the login credentials of the current repository. A
986 ** subrepository is identified by a CONFIG table entry "subrepo:NAME"
987 ** where NAME is the first component of the path. The value of the
988 ** the CONFIG entries is the string "USER:FILENAME" where USER is the
989 ** USER name to log in as in the subrepository and FILENAME is the
990 ** repository filename.
991 */
992 zAltRepo = db_text(0, "SELECT value FROM config WHERE name='subrepo:%q'",
993 g.zPath);
994 if( zAltRepo ){
995 int nHost;
996 int jj;
997 char *zUser = zAltRepo;
998 login_check_credentials();
999 for(jj=0; zAltRepo[jj] && zAltRepo[jj]!=':'; jj++){}
1000 if( zAltRepo[jj]==':' ){
1001 zAltRepo[jj] = 0;
1002 zAltRepo += jj+1;
1003 }else{
1004 zUser = "nobody";
1005 }
1006 if( zAltRepo[0]!='/' ){
1007 zAltRepo = mprintf("%s/../%s", g.zRepositoryName, zAltRepo);
1008 file_simplify_name(zAltRepo, -1);
1009 }
1010 db_close(1);
1011 db_open_repository(zAltRepo);
1012 login_as_user(zUser);
1013 g.okPassword = 0;
1014 zPath += i;
1015 nHost = g.zTop - g.zBaseURL;
1016 g.zBaseURL = mprintf("%z/%s", g.zBaseURL, g.zPath);
1017 g.zTop = g.zBaseURL + nHost;
1018 continue;
1019 }
1020 }else{
1021 g.zExtra = 0;
1022 }
1023 break;
1024 }
1025 if( g.zExtra ){
1026 /* CGI parameters get this treatment elsewhere, but places like getfile
1027 ** will use g.zExtra directly.
1028 */
@@ -1005,11 +1070,13 @@
1070 ** the values of standard CGI environment variables.
1071 */
1072 void cmd_cgi(void){
1073 const char *zFile;
1074 const char *zNotFound = 0;
1075 char **azRedirect = 0; /* List of repositories to redirect to */
1076 int nRedirect = 0; /* Number of entries in azRedirect */
1077 Blob config, line, key, value, value2;
1078 if( g.argc==3 && fossil_strcmp(g.argv[1],"cgi")==0 ){
1079 zFile = g.argv[2];
1080 }else{
1081 zFile = g.argv[1];
1082 }
@@ -1059,17 +1126,82 @@
1126 }
1127 if( blob_eq(&key, "localauth") ){
1128 g.useLocalauth = 1;
1129 continue;
1130 }
1131 if( blob_eq(&key, "redirect:") && blob_token(&line, &value)
1132 && blob_token(&line, &value2) ){
1133 nRedirect++;
1134 azRedirect = fossil_realloc(azRedirect, 2*nRedirect*sizeof(char*));
1135 azRedirect[nRedirect*2-2] = mprintf("%s", blob_str(&value));
1136 azRedirect[nRedirect*2-1] = mprintf("%s", blob_str(&value2));
1137 blob_reset(&value);
1138 blob_reset(&value2);
1139 continue;
1140 }
1141 }
1142 blob_reset(&config);
1143 if( g.db==0 && g.zRepositoryName==0 && nRedirect==0 ){
1144 cgi_panic("Unable to find or open the project repository");
1145 }
1146 cgi_init();
1147 if( nRedirect ){
1148 redirect_web_page(nRedirect, azRedirect);
1149 }else{
1150 process_one_web_page(zNotFound);
1151 }
1152 }
1153
1154 /* If the CGI program contains one or more lines of the form
1155 **
1156 ** redirect: repository-filename http://hostname/path/%s
1157 **
1158 ** then control jumps here. Search each repository for an artifact ID
1159 ** that matches the "name" CGI parameter and for the first match,
1160 ** redirect to the corresponding URL with the "name" CGI parameter
1161 ** inserted. Paint an error page if no match is found.
1162 **
1163 ** If there is a line of the form:
1164 **
1165 ** redirect: * URL
1166 **
1167 ** Then a redirect is made to URL if no match is found. Otherwise a
1168 ** very primative error message is returned.
1169 */
1170 void redirect_web_page(int nRedirect, char **azRedirect){
1171 int i; /* Loop counter */
1172 const char *zNotFound = 0; /* Not found URL */
1173 const char *zName = P("name");
1174 set_base_url();
1175 if( zName==0 ){
1176 zName = P("SCRIPT_NAME");
1177 if( zName && zName[0]=='/' ) zName++;
1178 }
1179 if( zName && validate16(zName, strlen(zName)) ){
1180 for(i=0; i<nRedirect; i++){
1181 if( strcmp(azRedirect[i*2],"*")==0 ){
1182 zNotFound = azRedirect[i*2+1];
1183 continue;
1184 }
1185 db_open_repository(azRedirect[i*2]);
1186 if( db_exists("SELECT 1 FROM blob WHERE uuid GLOB '%s*'", zName) ){
1187 cgi_redirectf(azRedirect[i*2+1], zName);
1188 return;
1189 }
1190 db_close(1);
1191 }
1192 }
1193 if( zNotFound ){
1194 cgi_redirectf(zNotFound, zName);
1195 }else{
1196 @ <html>
1197 @ <head><title>No Such Object</title></head>
1198 @ <body>
1199 @ <p>No such object: <b>%h(zName)</b></p>
1200 @ </body>
1201 cgi_reply();
1202 }
1203 }
1204
1205 /*
1206 ** If g.argv[2] exists then it is either the name of a repository
1207 ** that will be used by a server, or else it is a directory that
@@ -1128,17 +1260,21 @@
1260 ** Other options:
1261 **
1262 ** --localauth Password signin is not required if this is true and
1263 ** the input comes from 127.0.0.1 and the "localauth"
1264 ** setting is not disabled.
1265 **
1266 ** --nossl SSL connections are not available so do not
1267 ** redirect from http: to https:.
1268 */
1269 void cmd_http(void){
1270 const char *zIpAddr;
1271 const char *zNotFound;
1272 const char *zHost;
1273 zNotFound = find_option("notfound", 0, 1);
1274 g.useLocalauth = find_option("localauth", 0, 0)!=0;
1275 g.sslNotAvailable = find_option("nossl", 0, 0)!=0;
1276 if( find_option("https",0,0)!=0 ) cgi_replace_parameter("HTTPS","on");
1277 zHost = find_option("host", 0, 1);
1278 if( zHost ) cgi_replace_parameter("HTTP_HOST",zHost);
1279 g.cgiOutput = 1;
1280 if( g.argc!=2 && g.argc!=3 && g.argc!=6 ){
@@ -1287,10 +1423,11 @@
1423 }
1424 db_close(1);
1425 if( cgi_http_server(iPort, mxPort, zBrowserCmd, flags) ){
1426 fossil_fatal("unable to listen on TCP socket %d", iPort);
1427 }
1428 g.sslNotAvailable = 1;
1429 g.httpIn = stdin;
1430 g.httpOut = stdout;
1431 if( g.fHttpTrace || g.fSqlTrace ){
1432 fprintf(stderr, "====== SERVER pid %d =======\n", getpid());
1433 }
1434
+11 -1
--- src/main.mk
+++ src/main.mk
@@ -54,10 +54,11 @@
5454
$(SRCDIR)/manifest.c \
5555
$(SRCDIR)/md5.c \
5656
$(SRCDIR)/merge.c \
5757
$(SRCDIR)/merge3.c \
5858
$(SRCDIR)/name.c \
59
+ $(SRCDIR)/path.c \
5960
$(SRCDIR)/pivot.c \
6061
$(SRCDIR)/popen.c \
6162
$(SRCDIR)/pqueue.c \
6263
$(SRCDIR)/printf.c \
6364
$(SRCDIR)/rebuild.c \
@@ -136,10 +137,11 @@
136137
$(OBJDIR)/manifest_.c \
137138
$(OBJDIR)/md5_.c \
138139
$(OBJDIR)/merge_.c \
139140
$(OBJDIR)/merge3_.c \
140141
$(OBJDIR)/name_.c \
142
+ $(OBJDIR)/path_.c \
141143
$(OBJDIR)/pivot_.c \
142144
$(OBJDIR)/popen_.c \
143145
$(OBJDIR)/pqueue_.c \
144146
$(OBJDIR)/printf_.c \
145147
$(OBJDIR)/rebuild_.c \
@@ -218,10 +220,11 @@
218220
$(OBJDIR)/manifest.o \
219221
$(OBJDIR)/md5.o \
220222
$(OBJDIR)/merge.o \
221223
$(OBJDIR)/merge3.o \
222224
$(OBJDIR)/name.o \
225
+ $(OBJDIR)/path.o \
223226
$(OBJDIR)/pivot.o \
224227
$(OBJDIR)/popen.o \
225228
$(OBJDIR)/pqueue.o \
226229
$(OBJDIR)/printf.o \
227230
$(OBJDIR)/rebuild.o \
@@ -304,11 +307,11 @@
304307
305308
306309
$(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex
307310
$(OBJDIR)/mkindex $(TRANS_SRC) >$@
308311
$(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h
309
- $(OBJDIR)/makeheaders $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h
312
+ $(OBJDIR)/makeheaders $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h
310313
touch $(OBJDIR)/headers
311314
$(OBJDIR)/headers: Makefile
312315
Makefile:
313316
$(OBJDIR)/add_.c: $(SRCDIR)/add.c $(OBJDIR)/translate
314317
$(OBJDIR)/translate $(SRCDIR)/add.c >$(OBJDIR)/add_.c
@@ -623,10 +626,17 @@
623626
624627
$(OBJDIR)/name.o: $(OBJDIR)/name_.c $(OBJDIR)/name.h $(SRCDIR)/config.h
625628
$(XTCC) -o $(OBJDIR)/name.o -c $(OBJDIR)/name_.c
626629
627630
$(OBJDIR)/name.h: $(OBJDIR)/headers
631
+$(OBJDIR)/path_.c: $(SRCDIR)/path.c $(OBJDIR)/translate
632
+ $(OBJDIR)/translate $(SRCDIR)/path.c >$(OBJDIR)/path_.c
633
+
634
+$(OBJDIR)/path.o: $(OBJDIR)/path_.c $(OBJDIR)/path.h $(SRCDIR)/config.h
635
+ $(XTCC) -o $(OBJDIR)/path.o -c $(OBJDIR)/path_.c
636
+
637
+$(OBJDIR)/path.h: $(OBJDIR)/headers
628638
$(OBJDIR)/pivot_.c: $(SRCDIR)/pivot.c $(OBJDIR)/translate
629639
$(OBJDIR)/translate $(SRCDIR)/pivot.c >$(OBJDIR)/pivot_.c
630640
631641
$(OBJDIR)/pivot.o: $(OBJDIR)/pivot_.c $(OBJDIR)/pivot.h $(SRCDIR)/config.h
632642
$(XTCC) -o $(OBJDIR)/pivot.o -c $(OBJDIR)/pivot_.c
633643
--- src/main.mk
+++ src/main.mk
@@ -54,10 +54,11 @@
54 $(SRCDIR)/manifest.c \
55 $(SRCDIR)/md5.c \
56 $(SRCDIR)/merge.c \
57 $(SRCDIR)/merge3.c \
58 $(SRCDIR)/name.c \
 
59 $(SRCDIR)/pivot.c \
60 $(SRCDIR)/popen.c \
61 $(SRCDIR)/pqueue.c \
62 $(SRCDIR)/printf.c \
63 $(SRCDIR)/rebuild.c \
@@ -136,10 +137,11 @@
136 $(OBJDIR)/manifest_.c \
137 $(OBJDIR)/md5_.c \
138 $(OBJDIR)/merge_.c \
139 $(OBJDIR)/merge3_.c \
140 $(OBJDIR)/name_.c \
 
141 $(OBJDIR)/pivot_.c \
142 $(OBJDIR)/popen_.c \
143 $(OBJDIR)/pqueue_.c \
144 $(OBJDIR)/printf_.c \
145 $(OBJDIR)/rebuild_.c \
@@ -218,10 +220,11 @@
218 $(OBJDIR)/manifest.o \
219 $(OBJDIR)/md5.o \
220 $(OBJDIR)/merge.o \
221 $(OBJDIR)/merge3.o \
222 $(OBJDIR)/name.o \
 
223 $(OBJDIR)/pivot.o \
224 $(OBJDIR)/popen.o \
225 $(OBJDIR)/pqueue.o \
226 $(OBJDIR)/printf.o \
227 $(OBJDIR)/rebuild.o \
@@ -304,11 +307,11 @@
304
305
306 $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex
307 $(OBJDIR)/mkindex $(TRANS_SRC) >$@
308 $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h
309 $(OBJDIR)/makeheaders $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h
310 touch $(OBJDIR)/headers
311 $(OBJDIR)/headers: Makefile
312 Makefile:
313 $(OBJDIR)/add_.c: $(SRCDIR)/add.c $(OBJDIR)/translate
314 $(OBJDIR)/translate $(SRCDIR)/add.c >$(OBJDIR)/add_.c
@@ -623,10 +626,17 @@
623
624 $(OBJDIR)/name.o: $(OBJDIR)/name_.c $(OBJDIR)/name.h $(SRCDIR)/config.h
625 $(XTCC) -o $(OBJDIR)/name.o -c $(OBJDIR)/name_.c
626
627 $(OBJDIR)/name.h: $(OBJDIR)/headers
 
 
 
 
 
 
 
628 $(OBJDIR)/pivot_.c: $(SRCDIR)/pivot.c $(OBJDIR)/translate
629 $(OBJDIR)/translate $(SRCDIR)/pivot.c >$(OBJDIR)/pivot_.c
630
631 $(OBJDIR)/pivot.o: $(OBJDIR)/pivot_.c $(OBJDIR)/pivot.h $(SRCDIR)/config.h
632 $(XTCC) -o $(OBJDIR)/pivot.o -c $(OBJDIR)/pivot_.c
633
--- src/main.mk
+++ src/main.mk
@@ -54,10 +54,11 @@
54 $(SRCDIR)/manifest.c \
55 $(SRCDIR)/md5.c \
56 $(SRCDIR)/merge.c \
57 $(SRCDIR)/merge3.c \
58 $(SRCDIR)/name.c \
59 $(SRCDIR)/path.c \
60 $(SRCDIR)/pivot.c \
61 $(SRCDIR)/popen.c \
62 $(SRCDIR)/pqueue.c \
63 $(SRCDIR)/printf.c \
64 $(SRCDIR)/rebuild.c \
@@ -136,10 +137,11 @@
137 $(OBJDIR)/manifest_.c \
138 $(OBJDIR)/md5_.c \
139 $(OBJDIR)/merge_.c \
140 $(OBJDIR)/merge3_.c \
141 $(OBJDIR)/name_.c \
142 $(OBJDIR)/path_.c \
143 $(OBJDIR)/pivot_.c \
144 $(OBJDIR)/popen_.c \
145 $(OBJDIR)/pqueue_.c \
146 $(OBJDIR)/printf_.c \
147 $(OBJDIR)/rebuild_.c \
@@ -218,10 +220,11 @@
220 $(OBJDIR)/manifest.o \
221 $(OBJDIR)/md5.o \
222 $(OBJDIR)/merge.o \
223 $(OBJDIR)/merge3.o \
224 $(OBJDIR)/name.o \
225 $(OBJDIR)/path.o \
226 $(OBJDIR)/pivot.o \
227 $(OBJDIR)/popen.o \
228 $(OBJDIR)/pqueue.o \
229 $(OBJDIR)/printf.o \
230 $(OBJDIR)/rebuild.o \
@@ -304,11 +307,11 @@
307
308
309 $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex
310 $(OBJDIR)/mkindex $(TRANS_SRC) >$@
311 $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h
312 $(OBJDIR)/makeheaders $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h
313 touch $(OBJDIR)/headers
314 $(OBJDIR)/headers: Makefile
315 Makefile:
316 $(OBJDIR)/add_.c: $(SRCDIR)/add.c $(OBJDIR)/translate
317 $(OBJDIR)/translate $(SRCDIR)/add.c >$(OBJDIR)/add_.c
@@ -623,10 +626,17 @@
626
627 $(OBJDIR)/name.o: $(OBJDIR)/name_.c $(OBJDIR)/name.h $(SRCDIR)/config.h
628 $(XTCC) -o $(OBJDIR)/name.o -c $(OBJDIR)/name_.c
629
630 $(OBJDIR)/name.h: $(OBJDIR)/headers
631 $(OBJDIR)/path_.c: $(SRCDIR)/path.c $(OBJDIR)/translate
632 $(OBJDIR)/translate $(SRCDIR)/path.c >$(OBJDIR)/path_.c
633
634 $(OBJDIR)/path.o: $(OBJDIR)/path_.c $(OBJDIR)/path.h $(SRCDIR)/config.h
635 $(XTCC) -o $(OBJDIR)/path.o -c $(OBJDIR)/path_.c
636
637 $(OBJDIR)/path.h: $(OBJDIR)/headers
638 $(OBJDIR)/pivot_.c: $(SRCDIR)/pivot.c $(OBJDIR)/translate
639 $(OBJDIR)/translate $(SRCDIR)/pivot.c >$(OBJDIR)/pivot_.c
640
641 $(OBJDIR)/pivot.o: $(OBJDIR)/pivot_.c $(OBJDIR)/pivot.h $(SRCDIR)/config.h
642 $(XTCC) -o $(OBJDIR)/pivot.o -c $(OBJDIR)/pivot_.c
643
--- src/makeheaders.c
+++ src/makeheaders.c
@@ -2344,11 +2344,13 @@
23442344
pStart = pList;
23452345
}
23462346
break;
23472347
23482348
case 'i':
2349
- if( pList->nText==6 && strncmp(pList->zText,"inline",6)==0 ){
2349
+ if( pList->nText==6 && strncmp(pList->zText,"inline",6)==0
2350
+ && (flags & PS_Static)==0
2351
+ ){
23502352
nErr += ProcessInlineProc(pList,flags,&resetFlag);
23512353
}
23522354
break;
23532355
23542356
case 'L':
23552357
--- src/makeheaders.c
+++ src/makeheaders.c
@@ -2344,11 +2344,13 @@
2344 pStart = pList;
2345 }
2346 break;
2347
2348 case 'i':
2349 if( pList->nText==6 && strncmp(pList->zText,"inline",6)==0 ){
 
 
2350 nErr += ProcessInlineProc(pList,flags,&resetFlag);
2351 }
2352 break;
2353
2354 case 'L':
2355
--- src/makeheaders.c
+++ src/makeheaders.c
@@ -2344,11 +2344,13 @@
2344 pStart = pList;
2345 }
2346 break;
2347
2348 case 'i':
2349 if( pList->nText==6 && strncmp(pList->zText,"inline",6)==0
2350 && (flags & PS_Static)==0
2351 ){
2352 nErr += ProcessInlineProc(pList,flags,&resetFlag);
2353 }
2354 break;
2355
2356 case 'L':
2357
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -60,10 +60,11 @@
6060
manifest
6161
md5
6262
merge
6363
merge3
6464
name
65
+ path
6566
pivot
6667
popen
6768
pqueue
6869
printf
6970
rebuild
7071
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -60,10 +60,11 @@
60 manifest
61 md5
62 merge
63 merge3
64 name
 
65 pivot
66 popen
67 pqueue
68 printf
69 rebuild
70
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -60,10 +60,11 @@
60 manifest
61 md5
62 merge
63 merge3
64 name
65 path
66 pivot
67 popen
68 pqueue
69 printf
70 rebuild
71
+1 -1
--- src/manifest.c
+++ src/manifest.c
@@ -1330,11 +1330,11 @@
13301330
** present in pParent but which are missing from pChild and mark them
13311331
** has having been deleted. */
13321332
manifest_file_rewind(pParent);
13331333
while( (pParentFile = manifest_file_next(pParent,0))!=0 ){
13341334
pChildFile = manifest_file_seek(pChild, pParentFile->zName);
1335
- if( pChildFile==0 ){
1335
+ if( pChildFile==0 && pParentFile->zUuid!=0 ){
13361336
add_one_mlink(cid, pParentFile->zUuid, 0, pParentFile->zName, 0,
13371337
isPublic, 0);
13381338
}
13391339
}
13401340
}
13411341
--- src/manifest.c
+++ src/manifest.c
@@ -1330,11 +1330,11 @@
1330 ** present in pParent but which are missing from pChild and mark them
1331 ** has having been deleted. */
1332 manifest_file_rewind(pParent);
1333 while( (pParentFile = manifest_file_next(pParent,0))!=0 ){
1334 pChildFile = manifest_file_seek(pChild, pParentFile->zName);
1335 if( pChildFile==0 ){
1336 add_one_mlink(cid, pParentFile->zUuid, 0, pParentFile->zName, 0,
1337 isPublic, 0);
1338 }
1339 }
1340 }
1341
--- src/manifest.c
+++ src/manifest.c
@@ -1330,11 +1330,11 @@
1330 ** present in pParent but which are missing from pChild and mark them
1331 ** has having been deleted. */
1332 manifest_file_rewind(pParent);
1333 while( (pParentFile = manifest_file_next(pParent,0))!=0 ){
1334 pChildFile = manifest_file_seek(pChild, pParentFile->zName);
1335 if( pChildFile==0 && pParentFile->zUuid!=0 ){
1336 add_one_mlink(cid, pParentFile->zUuid, 0, pParentFile->zName, 0,
1337 isPublic, 0);
1338 }
1339 }
1340 }
1341
+2 -2
--- src/name.c
+++ src/name.c
@@ -147,11 +147,11 @@
147147
int vid;
148148
char *zUuid =
149149
db_text(0,
150150
"SELECT blob.uuid"
151151
" FROM tag, tagxref, event, blob"
152
- " WHERE tag.tagname='sym-'||%Q "
152
+ " WHERE tag.tagname='sym-%q' "
153153
" AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 "
154154
" AND event.objid=tagxref.rid "
155155
" AND blob.rid=event.objid "
156156
" ORDER BY event.mtime DESC ",
157157
zTag
@@ -171,11 +171,11 @@
171171
useUtc = 1;
172172
}
173173
zUuid = db_text(0,
174174
"SELECT blob.uuid"
175175
" FROM tag, tagxref, event, blob"
176
- " WHERE tag.tagname='sym-'||%Q "
176
+ " WHERE tag.tagname='sym-%q' "
177177
" AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 "
178178
" AND event.objid=tagxref.rid "
179179
" AND blob.rid=event.objid "
180180
" AND event.mtime<=julianday(%Q %s)"
181181
" ORDER BY event.mtime DESC ",
182182
183183
ADDED src/path.c
--- src/name.c
+++ src/name.c
@@ -147,11 +147,11 @@
147 int vid;
148 char *zUuid =
149 db_text(0,
150 "SELECT blob.uuid"
151 " FROM tag, tagxref, event, blob"
152 " WHERE tag.tagname='sym-'||%Q "
153 " AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 "
154 " AND event.objid=tagxref.rid "
155 " AND blob.rid=event.objid "
156 " ORDER BY event.mtime DESC ",
157 zTag
@@ -171,11 +171,11 @@
171 useUtc = 1;
172 }
173 zUuid = db_text(0,
174 "SELECT blob.uuid"
175 " FROM tag, tagxref, event, blob"
176 " WHERE tag.tagname='sym-'||%Q "
177 " AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 "
178 " AND event.objid=tagxref.rid "
179 " AND blob.rid=event.objid "
180 " AND event.mtime<=julianday(%Q %s)"
181 " ORDER BY event.mtime DESC ",
182
183 DDED src/path.c
--- src/name.c
+++ src/name.c
@@ -147,11 +147,11 @@
147 int vid;
148 char *zUuid =
149 db_text(0,
150 "SELECT blob.uuid"
151 " FROM tag, tagxref, event, blob"
152 " WHERE tag.tagname='sym-%q' "
153 " AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 "
154 " AND event.objid=tagxref.rid "
155 " AND blob.rid=event.objid "
156 " ORDER BY event.mtime DESC ",
157 zTag
@@ -171,11 +171,11 @@
171 useUtc = 1;
172 }
173 zUuid = db_text(0,
174 "SELECT blob.uuid"
175 " FROM tag, tagxref, event, blob"
176 " WHERE tag.tagname='sym-%q' "
177 " AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 "
178 " AND event.objid=tagxref.rid "
179 " AND blob.rid=event.objid "
180 " AND event.mtime<=julianday(%Q %s)"
181 " ORDER BY event.mtime DESC ",
182
183 DDED src/path.c
+6
--- a/src/path.c
+++ b/src/path.c
@@ -0,0 +1,6 @@
1
+ re©(c)&444c re©(c)&444int iFrom, int iTo, int directOnly*pnpfnid>0if( 1);
2
+ }else{
3
+ 1)*pnChng = nChng;, i+=2){}&nChng, &aChng, 0);
4
+0printfu.pTo ){
5
+ printfprintfprintfprintf(" VERSION1To ) printfprintf(" PIVOT");
6
+ printfprintf
--- a/src/path.c
+++ b/src/path.c
@@ -0,0 +1,6 @@
 
 
 
 
 
 
--- a/src/path.c
+++ b/src/path.c
@@ -0,0 +1,6 @@
1 re©(c)&444c re©(c)&444int iFrom, int iTo, int directOnly*pnpfnid>0if( 1);
2 }else{
3 1)*pnChng = nChng;, i+=2){}&nChng, &aChng, 0);
4 0printfu.pTo ){
5 printfprintfprintfprintf(" VERSION1To ) printfprintf(" PIVOT");
6 printfprintf
+6 -2
--- src/pqueue.c
+++ src/pqueue.c
@@ -38,10 +38,11 @@
3838
struct PQueue {
3939
int cnt; /* Number of entries in the queue */
4040
int sz; /* Number of slots in a[] */
4141
struct QueueElement {
4242
int id; /* ID of the element */
43
+ void *p; /* Content pointer */
4344
double value; /* Value of element. Kept in ascending order */
4445
} *a;
4546
};
4647
#endif
4748
@@ -69,11 +70,11 @@
6970
}
7071
7172
/*
7273
** Insert element e into the queue.
7374
*/
74
-void pqueue_insert(PQueue *p, int e, double v){
75
+void pqueue_insert(PQueue *p, int e, double v, void *pData){
7576
int i, j;
7677
if( p->cnt+1>p->sz ){
7778
pqueue_resize(p, p->cnt+5);
7879
}
7980
for(i=0; i<p->cnt; i++){
@@ -83,26 +84,29 @@
8384
}
8485
break;
8586
}
8687
}
8788
p->a[i].id = e;
89
+ p->a[i].p = pData;
8890
p->a[i].value = v;
8991
p->cnt++;
9092
}
9193
9294
/*
9395
** Extract the first element from the queue (the element with
9496
** the smallest value) and return its ID. Return 0 if the queue
9597
** is empty.
9698
*/
97
-int pqueue_extract(PQueue *p){
99
+int pqueue_extract(PQueue *p, void **pp){
98100
int e, i;
99101
if( p->cnt==0 ){
102
+ if( pp ) *pp = 0;
100103
return 0;
101104
}
102105
e = p->a[0].id;
106
+ if( pp ) *pp = p->a[0].p;
103107
for(i=0; i<p->cnt-1; i++){
104108
p->a[i] = p->a[i+1];
105109
}
106110
p->cnt--;
107111
return e;
108112
}
109113
--- src/pqueue.c
+++ src/pqueue.c
@@ -38,10 +38,11 @@
38 struct PQueue {
39 int cnt; /* Number of entries in the queue */
40 int sz; /* Number of slots in a[] */
41 struct QueueElement {
42 int id; /* ID of the element */
 
43 double value; /* Value of element. Kept in ascending order */
44 } *a;
45 };
46 #endif
47
@@ -69,11 +70,11 @@
69 }
70
71 /*
72 ** Insert element e into the queue.
73 */
74 void pqueue_insert(PQueue *p, int e, double v){
75 int i, j;
76 if( p->cnt+1>p->sz ){
77 pqueue_resize(p, p->cnt+5);
78 }
79 for(i=0; i<p->cnt; i++){
@@ -83,26 +84,29 @@
83 }
84 break;
85 }
86 }
87 p->a[i].id = e;
 
88 p->a[i].value = v;
89 p->cnt++;
90 }
91
92 /*
93 ** Extract the first element from the queue (the element with
94 ** the smallest value) and return its ID. Return 0 if the queue
95 ** is empty.
96 */
97 int pqueue_extract(PQueue *p){
98 int e, i;
99 if( p->cnt==0 ){
 
100 return 0;
101 }
102 e = p->a[0].id;
 
103 for(i=0; i<p->cnt-1; i++){
104 p->a[i] = p->a[i+1];
105 }
106 p->cnt--;
107 return e;
108 }
109
--- src/pqueue.c
+++ src/pqueue.c
@@ -38,10 +38,11 @@
38 struct PQueue {
39 int cnt; /* Number of entries in the queue */
40 int sz; /* Number of slots in a[] */
41 struct QueueElement {
42 int id; /* ID of the element */
43 void *p; /* Content pointer */
44 double value; /* Value of element. Kept in ascending order */
45 } *a;
46 };
47 #endif
48
@@ -69,11 +70,11 @@
70 }
71
72 /*
73 ** Insert element e into the queue.
74 */
75 void pqueue_insert(PQueue *p, int e, double v, void *pData){
76 int i, j;
77 if( p->cnt+1>p->sz ){
78 pqueue_resize(p, p->cnt+5);
79 }
80 for(i=0; i<p->cnt; i++){
@@ -83,26 +84,29 @@
84 }
85 break;
86 }
87 }
88 p->a[i].id = e;
89 p->a[i].p = pData;
90 p->a[i].value = v;
91 p->cnt++;
92 }
93
94 /*
95 ** Extract the first element from the queue (the element with
96 ** the smallest value) and return its ID. Return 0 if the queue
97 ** is empty.
98 */
99 int pqueue_extract(PQueue *p, void **pp){
100 int e, i;
101 if( p->cnt==0 ){
102 if( pp ) *pp = 0;
103 return 0;
104 }
105 e = p->a[0].id;
106 if( pp ) *pp = p->a[0].p;
107 for(i=0; i<p->cnt-1; i++){
108 p->a[i] = p->a[i+1];
109 }
110 p->cnt--;
111 return e;
112 }
113
+1 -1
--- src/report.c
+++ src/report.c
@@ -1117,11 +1117,11 @@
11171117
"SELECT title, sqlcode, owner, cols FROM reportfmt WHERE title='%s'", zRep);
11181118
}
11191119
if( db_step(&q)!=SQLITE_ROW ){
11201120
db_finalize(&q);
11211121
rpt_list_reports();
1122
- fossil_fatal("unkown report format(%s)!",zRep);
1122
+ fossil_fatal("unknown report format(%s)!",zRep);
11231123
}
11241124
zTitle = db_column_malloc(&q, 0);
11251125
zSql = db_column_malloc(&q, 1);
11261126
zOwner = db_column_malloc(&q, 2);
11271127
zClrKey = db_column_malloc(&q, 3);
11281128
--- src/report.c
+++ src/report.c
@@ -1117,11 +1117,11 @@
1117 "SELECT title, sqlcode, owner, cols FROM reportfmt WHERE title='%s'", zRep);
1118 }
1119 if( db_step(&q)!=SQLITE_ROW ){
1120 db_finalize(&q);
1121 rpt_list_reports();
1122 fossil_fatal("unkown report format(%s)!",zRep);
1123 }
1124 zTitle = db_column_malloc(&q, 0);
1125 zSql = db_column_malloc(&q, 1);
1126 zOwner = db_column_malloc(&q, 2);
1127 zClrKey = db_column_malloc(&q, 3);
1128
--- src/report.c
+++ src/report.c
@@ -1117,11 +1117,11 @@
1117 "SELECT title, sqlcode, owner, cols FROM reportfmt WHERE title='%s'", zRep);
1118 }
1119 if( db_step(&q)!=SQLITE_ROW ){
1120 db_finalize(&q);
1121 rpt_list_reports();
1122 fossil_fatal("unknown report format(%s)!",zRep);
1123 }
1124 zTitle = db_column_malloc(&q, 0);
1125 zSql = db_column_malloc(&q, 1);
1126 zOwner = db_column_malloc(&q, 2);
1127 zClrKey = db_column_malloc(&q, 3);
1128
+80 -27
--- src/shell.c
+++ src/shell.c
@@ -417,10 +417,11 @@
417417
struct previous_mode_data explainPrev;
418418
/* Holds the mode information just before
419419
** .explain ON */
420420
char outfile[FILENAME_MAX]; /* Filename for *out */
421421
const char *zDbFilename; /* name of the database file */
422
+ const char *zVfs; /* Name of VFS to use */
422423
sqlite3_stmt *pStmt; /* Current statement if any. */
423424
FILE *pLog; /* Write log output here */
424425
};
425426
426427
/*
@@ -1848,11 +1849,11 @@
18481849
rc = 1;
18491850
}
18501851
}else
18511852
#endif
18521853
1853
- if( c=='l' && strncmp(azArg[0], "log", n)==0 && nArg>=1 ){
1854
+ if( c=='l' && strncmp(azArg[0], "log", n)==0 && nArg>=2 ){
18541855
const char *zFile = azArg[1];
18551856
if( p->pLog && p->pLog!=stdout && p->pLog!=stderr ){
18561857
fclose(p->pLog);
18571858
p->pLog = 0;
18581859
}
@@ -2170,33 +2171,49 @@
21702171
}
21712172
sqlite3_free_table(azResult);
21722173
}else
21732174
21742175
if( c=='t' && n>=8 && strncmp(azArg[0], "testctrl", n)==0 && nArg>=2 ){
2176
+ static const struct {
2177
+ const char *zCtrlName; /* Name of a test-control option */
2178
+ int ctrlCode; /* Integer code for that option */
2179
+ } aCtrl[] = {
2180
+ { "prng_save", SQLITE_TESTCTRL_PRNG_SAVE },
2181
+ { "prng_restore", SQLITE_TESTCTRL_PRNG_RESTORE },
2182
+ { "prng_reset", SQLITE_TESTCTRL_PRNG_RESET },
2183
+ { "bitvec_test", SQLITE_TESTCTRL_BITVEC_TEST },
2184
+ { "fault_install", SQLITE_TESTCTRL_FAULT_INSTALL },
2185
+ { "benign_malloc_hooks", SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS },
2186
+ { "pending_byte", SQLITE_TESTCTRL_PENDING_BYTE },
2187
+ { "assert", SQLITE_TESTCTRL_ASSERT },
2188
+ { "always", SQLITE_TESTCTRL_ALWAYS },
2189
+ { "reserve", SQLITE_TESTCTRL_RESERVE },
2190
+ { "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS },
2191
+ { "iskeyword", SQLITE_TESTCTRL_ISKEYWORD },
2192
+ { "pghdrsz", SQLITE_TESTCTRL_PGHDRSZ },
2193
+ { "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC },
2194
+ };
21752195
int testctrl = -1;
21762196
int rc = 0;
2197
+ int i, n;
21772198
open_db(p);
21782199
2179
- /* convert testctrl text option to value. allow only the first
2180
- ** three characters of the option to be used or the numerical
2181
- ** value. */
2182
- if( strncmp( azArg[1], "prng_save", 6 )==0 ) testctrl = SQLITE_TESTCTRL_PRNG_SAVE;
2183
- else if( strncmp( azArg[1], "prng_restore", 10 )==0 ) testctrl = SQLITE_TESTCTRL_PRNG_RESTORE;
2184
- else if( strncmp( azArg[1], "prng_reset", 10 )==0 ) testctrl = SQLITE_TESTCTRL_PRNG_RESET;
2185
- else if( strncmp( azArg[1], "bitvec_test", 6 )==3 ) testctrl = SQLITE_TESTCTRL_BITVEC_TEST;
2186
- else if( strncmp( azArg[1], "fault_install", 6 )==3 ) testctrl = SQLITE_TESTCTRL_FAULT_INSTALL;
2187
- else if( strncmp( azArg[1], "benign_malloc_hooks", 3 )==0 ) testctrl = SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS;
2188
- else if( strncmp( azArg[1], "pending_byte", 3 )==0 ) testctrl = SQLITE_TESTCTRL_PENDING_BYTE;
2189
- else if( strncmp( azArg[1], "assert", 3 )==0 ) testctrl = SQLITE_TESTCTRL_ASSERT;
2190
- else if( strncmp( azArg[1], "always", 3 )==0 ) testctrl = SQLITE_TESTCTRL_ALWAYS;
2191
- else if( strncmp( azArg[1], "reserve", 3 )==0 ) testctrl = SQLITE_TESTCTRL_RESERVE;
2192
- else if( strncmp( azArg[1], "optimizations", 3 )==0 ) testctrl = SQLITE_TESTCTRL_OPTIMIZATIONS;
2193
- else if( strncmp( azArg[1], "iskeyword", 3 )==0 ) testctrl = SQLITE_TESTCTRL_ISKEYWORD;
2194
- else if( strncmp( azArg[1], "pghdrsz", 3 )==0 ) testctrl = SQLITE_TESTCTRL_PGHDRSZ;
2195
- else if( strncmp( azArg[1], "scratchmalloc", 3 )==0 ) testctrl = SQLITE_TESTCTRL_SCRATCHMALLOC;
2196
- else testctrl = atoi(azArg[1]);
2197
-
2200
+ /* convert testctrl text option to value. allow any unique prefix
2201
+ ** of the option name, or a numerical value. */
2202
+ n = strlen(azArg[1]);
2203
+ for(i=0; i<sizeof(aCtrl)/sizeof(aCtrl[0]); i++){
2204
+ if( strncmp(azArg[1], aCtrl[i].zCtrlName, n)==0 ){
2205
+ if( testctrl<0 ){
2206
+ testctrl = aCtrl[i].ctrlCode;
2207
+ }else{
2208
+ fprintf(stderr, "ambiguous option name: \"%s\"\n", azArg[i]);
2209
+ testctrl = -1;
2210
+ break;
2211
+ }
2212
+ }
2213
+ }
2214
+ if( testctrl<0 ) testctrl = atoi(azArg[1]);
21982215
if( (testctrl<SQLITE_TESTCTRL_FIRST) || (testctrl>SQLITE_TESTCTRL_LAST) ){
21992216
fprintf(stderr,"Error: invalid testctrl option: %s\n", azArg[1]);
22002217
}else{
22012218
switch(testctrl){
22022219
@@ -2206,11 +2223,12 @@
22062223
if( nArg==3 ){
22072224
int opt = (int)strtol(azArg[2], 0, 0);
22082225
rc = sqlite3_test_control(testctrl, p->db, opt);
22092226
printf("%d (0x%08x)\n", rc, rc);
22102227
} else {
2211
- fprintf(stderr,"Error: testctrl %s takes a single int option\n", azArg[1]);
2228
+ fprintf(stderr,"Error: testctrl %s takes a single int option\n",
2229
+ azArg[1]);
22122230
}
22132231
break;
22142232
22152233
/* sqlite3_test_control(int) */
22162234
case SQLITE_TESTCTRL_PRNG_SAVE:
@@ -2230,11 +2248,12 @@
22302248
if( nArg==3 ){
22312249
unsigned int opt = (unsigned int)atoi(azArg[2]);
22322250
rc = sqlite3_test_control(testctrl, opt);
22332251
printf("%d (0x%08x)\n", rc, rc);
22342252
} else {
2235
- fprintf(stderr,"Error: testctrl %s takes a single unsigned int option\n", azArg[1]);
2253
+ fprintf(stderr,"Error: testctrl %s takes a single unsigned"
2254
+ " int option\n", azArg[1]);
22362255
}
22372256
break;
22382257
22392258
/* sqlite3_test_control(int, int) */
22402259
case SQLITE_TESTCTRL_ASSERT:
@@ -2242,11 +2261,12 @@
22422261
if( nArg==3 ){
22432262
int opt = atoi(azArg[2]);
22442263
rc = sqlite3_test_control(testctrl, opt);
22452264
printf("%d (0x%08x)\n", rc, rc);
22462265
} else {
2247
- fprintf(stderr,"Error: testctrl %s takes a single int option\n", azArg[1]);
2266
+ fprintf(stderr,"Error: testctrl %s takes a single int option\n",
2267
+ azArg[1]);
22482268
}
22492269
break;
22502270
22512271
/* sqlite3_test_control(int, char *) */
22522272
#ifdef SQLITE_N_KEYWORD
@@ -2254,21 +2274,23 @@
22542274
if( nArg==3 ){
22552275
const char *opt = azArg[2];
22562276
rc = sqlite3_test_control(testctrl, opt);
22572277
printf("%d (0x%08x)\n", rc, rc);
22582278
} else {
2259
- fprintf(stderr,"Error: testctrl %s takes a single char * option\n", azArg[1]);
2279
+ fprintf(stderr,"Error: testctrl %s takes a single char * option\n",
2280
+ azArg[1]);
22602281
}
22612282
break;
22622283
#endif
22632284
22642285
case SQLITE_TESTCTRL_BITVEC_TEST:
22652286
case SQLITE_TESTCTRL_FAULT_INSTALL:
22662287
case SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS:
22672288
case SQLITE_TESTCTRL_SCRATCHMALLOC:
22682289
default:
2269
- fprintf(stderr,"Error: CLI support for testctrl %s not implemented\n", azArg[1]);
2290
+ fprintf(stderr,"Error: CLI support for testctrl %s not implemented\n",
2291
+ azArg[1]);
22702292
break;
22712293
}
22722294
}
22732295
}else
22742296
@@ -2275,11 +2297,13 @@
22752297
if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 && nArg==2 ){
22762298
open_db(p);
22772299
sqlite3_busy_timeout(p->db, atoi(azArg[1]));
22782300
}else
22792301
2280
- if( HAS_TIMER && c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0 && nArg==2 ){
2302
+ if( HAS_TIMER && c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0
2303
+ && nArg==2
2304
+ ){
22812305
enableTimer = booleanValue(azArg[1]);
22822306
}else
22832307
22842308
if( c=='w' && strncmp(azArg[0], "width", n)==0 && nArg>1 ){
22852309
int j;
@@ -2462,11 +2486,13 @@
24622486
zSql = 0;
24632487
nSql = 0;
24642488
}
24652489
}
24662490
if( zSql ){
2467
- if( !_all_whitespace(zSql) ) fprintf(stderr, "Error: incomplete SQL: %s\n", zSql);
2491
+ if( !_all_whitespace(zSql) ){
2492
+ fprintf(stderr, "Error: incomplete SQL: %s\n", zSql);
2493
+ }
24682494
free(zSql);
24692495
}
24702496
free(zLine);
24712497
return errCnt;
24722498
}
@@ -2598,10 +2624,14 @@
25982624
" -list set output mode to 'list'\n"
25992625
" -separator 'x' set output field separator (|)\n"
26002626
" -stats print memory stats before each finalize\n"
26012627
" -nullvalue 'text' set text string for NULL values\n"
26022628
" -version show SQLite version\n"
2629
+ " -vfs NAME use NAME as the default VFS\n"
2630
+#ifdef SQLITE_ENABLE_VFSTRACE
2631
+ " -vfstrace enable tracing of all VFS calls\n"
2632
+#endif
26032633
;
26042634
static void usage(int showDetail){
26052635
fprintf(stderr,
26062636
"Usage: %s [OPTIONS] FILENAME [SQL]\n"
26072637
"FILENAME is the name of an SQLite database. A new database is created\n"
@@ -2682,10 +2712,29 @@
26822712
}
26832713
if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000;
26842714
#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
26852715
sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64);
26862716
#endif
2717
+#ifdef SQLITE_ENABLE_VFSTRACE
2718
+ }else if( strcmp(argv[i],"-vfstrace")==0 ){
2719
+ extern int vfstrace_register(
2720
+ const char *zTraceName,
2721
+ const char *zOldVfsName,
2722
+ int (*xOut)(const char*,void*),
2723
+ void *pOutArg,
2724
+ int makeDefault
2725
+ );
2726
+ vfstrace_register("trace",0,(int(*)(const char*,void*))fputs,stderr,1);
2727
+#endif
2728
+ }else if( strcmp(argv[i],"-vfs")==0 ){
2729
+ sqlite3_vfs *pVfs = sqlite3_vfs_find(argv[++i]);
2730
+ if( pVfs ){
2731
+ sqlite3_vfs_register(pVfs, 1);
2732
+ }else{
2733
+ fprintf(stderr, "no such VFS: \"%s\"\n", argv[i]);
2734
+ exit(1);
2735
+ }
26872736
}
26882737
}
26892738
if( i<argc ){
26902739
#if defined(SQLITE_OS_OS2) && SQLITE_OS_OS2
26912740
data.zDbFilename = (const char *)convertCpPathToUtf8( argv[i++] );
@@ -2796,10 +2845,14 @@
27962845
stdin_is_interactive = 1;
27972846
}else if( strcmp(z,"-batch")==0 ){
27982847
stdin_is_interactive = 0;
27992848
}else if( strcmp(z,"-heap")==0 ){
28002849
i++;
2850
+ }else if( strcmp(z,"-vfs")==0 ){
2851
+ i++;
2852
+ }else if( strcmp(z,"-vfstrace")==0 ){
2853
+ i++;
28012854
}else if( strcmp(z,"-help")==0 || strcmp(z, "--help")==0 ){
28022855
usage(1);
28032856
}else{
28042857
fprintf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
28052858
fprintf(stderr,"Use -help for a list of options.\n");
28062859
--- src/shell.c
+++ src/shell.c
@@ -417,10 +417,11 @@
417 struct previous_mode_data explainPrev;
418 /* Holds the mode information just before
419 ** .explain ON */
420 char outfile[FILENAME_MAX]; /* Filename for *out */
421 const char *zDbFilename; /* name of the database file */
 
422 sqlite3_stmt *pStmt; /* Current statement if any. */
423 FILE *pLog; /* Write log output here */
424 };
425
426 /*
@@ -1848,11 +1849,11 @@
1848 rc = 1;
1849 }
1850 }else
1851 #endif
1852
1853 if( c=='l' && strncmp(azArg[0], "log", n)==0 && nArg>=1 ){
1854 const char *zFile = azArg[1];
1855 if( p->pLog && p->pLog!=stdout && p->pLog!=stderr ){
1856 fclose(p->pLog);
1857 p->pLog = 0;
1858 }
@@ -2170,33 +2171,49 @@
2170 }
2171 sqlite3_free_table(azResult);
2172 }else
2173
2174 if( c=='t' && n>=8 && strncmp(azArg[0], "testctrl", n)==0 && nArg>=2 ){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2175 int testctrl = -1;
2176 int rc = 0;
 
2177 open_db(p);
2178
2179 /* convert testctrl text option to value. allow only the first
2180 ** three characters of the option to be used or the numerical
2181 ** value. */
2182 if( strncmp( azArg[1], "prng_save", 6 )==0 ) testctrl = SQLITE_TESTCTRL_PRNG_SAVE;
2183 else if( strncmp( azArg[1], "prng_restore", 10 )==0 ) testctrl = SQLITE_TESTCTRL_PRNG_RESTORE;
2184 else if( strncmp( azArg[1], "prng_reset", 10 )==0 ) testctrl = SQLITE_TESTCTRL_PRNG_RESET;
2185 else if( strncmp( azArg[1], "bitvec_test", 6 )==3 ) testctrl = SQLITE_TESTCTRL_BITVEC_TEST;
2186 else if( strncmp( azArg[1], "fault_install", 6 )==3 ) testctrl = SQLITE_TESTCTRL_FAULT_INSTALL;
2187 else if( strncmp( azArg[1], "benign_malloc_hooks", 3 )==0 ) testctrl = SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS;
2188 else if( strncmp( azArg[1], "pending_byte", 3 )==0 ) testctrl = SQLITE_TESTCTRL_PENDING_BYTE;
2189 else if( strncmp( azArg[1], "assert", 3 )==0 ) testctrl = SQLITE_TESTCTRL_ASSERT;
2190 else if( strncmp( azArg[1], "always", 3 )==0 ) testctrl = SQLITE_TESTCTRL_ALWAYS;
2191 else if( strncmp( azArg[1], "reserve", 3 )==0 ) testctrl = SQLITE_TESTCTRL_RESERVE;
2192 else if( strncmp( azArg[1], "optimizations", 3 )==0 ) testctrl = SQLITE_TESTCTRL_OPTIMIZATIONS;
2193 else if( strncmp( azArg[1], "iskeyword", 3 )==0 ) testctrl = SQLITE_TESTCTRL_ISKEYWORD;
2194 else if( strncmp( azArg[1], "pghdrsz", 3 )==0 ) testctrl = SQLITE_TESTCTRL_PGHDRSZ;
2195 else if( strncmp( azArg[1], "scratchmalloc", 3 )==0 ) testctrl = SQLITE_TESTCTRL_SCRATCHMALLOC;
2196 else testctrl = atoi(azArg[1]);
2197
2198 if( (testctrl<SQLITE_TESTCTRL_FIRST) || (testctrl>SQLITE_TESTCTRL_LAST) ){
2199 fprintf(stderr,"Error: invalid testctrl option: %s\n", azArg[1]);
2200 }else{
2201 switch(testctrl){
2202
@@ -2206,11 +2223,12 @@
2206 if( nArg==3 ){
2207 int opt = (int)strtol(azArg[2], 0, 0);
2208 rc = sqlite3_test_control(testctrl, p->db, opt);
2209 printf("%d (0x%08x)\n", rc, rc);
2210 } else {
2211 fprintf(stderr,"Error: testctrl %s takes a single int option\n", azArg[1]);
 
2212 }
2213 break;
2214
2215 /* sqlite3_test_control(int) */
2216 case SQLITE_TESTCTRL_PRNG_SAVE:
@@ -2230,11 +2248,12 @@
2230 if( nArg==3 ){
2231 unsigned int opt = (unsigned int)atoi(azArg[2]);
2232 rc = sqlite3_test_control(testctrl, opt);
2233 printf("%d (0x%08x)\n", rc, rc);
2234 } else {
2235 fprintf(stderr,"Error: testctrl %s takes a single unsigned int option\n", azArg[1]);
 
2236 }
2237 break;
2238
2239 /* sqlite3_test_control(int, int) */
2240 case SQLITE_TESTCTRL_ASSERT:
@@ -2242,11 +2261,12 @@
2242 if( nArg==3 ){
2243 int opt = atoi(azArg[2]);
2244 rc = sqlite3_test_control(testctrl, opt);
2245 printf("%d (0x%08x)\n", rc, rc);
2246 } else {
2247 fprintf(stderr,"Error: testctrl %s takes a single int option\n", azArg[1]);
 
2248 }
2249 break;
2250
2251 /* sqlite3_test_control(int, char *) */
2252 #ifdef SQLITE_N_KEYWORD
@@ -2254,21 +2274,23 @@
2254 if( nArg==3 ){
2255 const char *opt = azArg[2];
2256 rc = sqlite3_test_control(testctrl, opt);
2257 printf("%d (0x%08x)\n", rc, rc);
2258 } else {
2259 fprintf(stderr,"Error: testctrl %s takes a single char * option\n", azArg[1]);
 
2260 }
2261 break;
2262 #endif
2263
2264 case SQLITE_TESTCTRL_BITVEC_TEST:
2265 case SQLITE_TESTCTRL_FAULT_INSTALL:
2266 case SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS:
2267 case SQLITE_TESTCTRL_SCRATCHMALLOC:
2268 default:
2269 fprintf(stderr,"Error: CLI support for testctrl %s not implemented\n", azArg[1]);
 
2270 break;
2271 }
2272 }
2273 }else
2274
@@ -2275,11 +2297,13 @@
2275 if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 && nArg==2 ){
2276 open_db(p);
2277 sqlite3_busy_timeout(p->db, atoi(azArg[1]));
2278 }else
2279
2280 if( HAS_TIMER && c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0 && nArg==2 ){
 
 
2281 enableTimer = booleanValue(azArg[1]);
2282 }else
2283
2284 if( c=='w' && strncmp(azArg[0], "width", n)==0 && nArg>1 ){
2285 int j;
@@ -2462,11 +2486,13 @@
2462 zSql = 0;
2463 nSql = 0;
2464 }
2465 }
2466 if( zSql ){
2467 if( !_all_whitespace(zSql) ) fprintf(stderr, "Error: incomplete SQL: %s\n", zSql);
 
 
2468 free(zSql);
2469 }
2470 free(zLine);
2471 return errCnt;
2472 }
@@ -2598,10 +2624,14 @@
2598 " -list set output mode to 'list'\n"
2599 " -separator 'x' set output field separator (|)\n"
2600 " -stats print memory stats before each finalize\n"
2601 " -nullvalue 'text' set text string for NULL values\n"
2602 " -version show SQLite version\n"
 
 
 
 
2603 ;
2604 static void usage(int showDetail){
2605 fprintf(stderr,
2606 "Usage: %s [OPTIONS] FILENAME [SQL]\n"
2607 "FILENAME is the name of an SQLite database. A new database is created\n"
@@ -2682,10 +2712,29 @@
2682 }
2683 if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000;
2684 #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
2685 sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64);
2686 #endif
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2687 }
2688 }
2689 if( i<argc ){
2690 #if defined(SQLITE_OS_OS2) && SQLITE_OS_OS2
2691 data.zDbFilename = (const char *)convertCpPathToUtf8( argv[i++] );
@@ -2796,10 +2845,14 @@
2796 stdin_is_interactive = 1;
2797 }else if( strcmp(z,"-batch")==0 ){
2798 stdin_is_interactive = 0;
2799 }else if( strcmp(z,"-heap")==0 ){
2800 i++;
 
 
 
 
2801 }else if( strcmp(z,"-help")==0 || strcmp(z, "--help")==0 ){
2802 usage(1);
2803 }else{
2804 fprintf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
2805 fprintf(stderr,"Use -help for a list of options.\n");
2806
--- src/shell.c
+++ src/shell.c
@@ -417,10 +417,11 @@
417 struct previous_mode_data explainPrev;
418 /* Holds the mode information just before
419 ** .explain ON */
420 char outfile[FILENAME_MAX]; /* Filename for *out */
421 const char *zDbFilename; /* name of the database file */
422 const char *zVfs; /* Name of VFS to use */
423 sqlite3_stmt *pStmt; /* Current statement if any. */
424 FILE *pLog; /* Write log output here */
425 };
426
427 /*
@@ -1848,11 +1849,11 @@
1849 rc = 1;
1850 }
1851 }else
1852 #endif
1853
1854 if( c=='l' && strncmp(azArg[0], "log", n)==0 && nArg>=2 ){
1855 const char *zFile = azArg[1];
1856 if( p->pLog && p->pLog!=stdout && p->pLog!=stderr ){
1857 fclose(p->pLog);
1858 p->pLog = 0;
1859 }
@@ -2170,33 +2171,49 @@
2171 }
2172 sqlite3_free_table(azResult);
2173 }else
2174
2175 if( c=='t' && n>=8 && strncmp(azArg[0], "testctrl", n)==0 && nArg>=2 ){
2176 static const struct {
2177 const char *zCtrlName; /* Name of a test-control option */
2178 int ctrlCode; /* Integer code for that option */
2179 } aCtrl[] = {
2180 { "prng_save", SQLITE_TESTCTRL_PRNG_SAVE },
2181 { "prng_restore", SQLITE_TESTCTRL_PRNG_RESTORE },
2182 { "prng_reset", SQLITE_TESTCTRL_PRNG_RESET },
2183 { "bitvec_test", SQLITE_TESTCTRL_BITVEC_TEST },
2184 { "fault_install", SQLITE_TESTCTRL_FAULT_INSTALL },
2185 { "benign_malloc_hooks", SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS },
2186 { "pending_byte", SQLITE_TESTCTRL_PENDING_BYTE },
2187 { "assert", SQLITE_TESTCTRL_ASSERT },
2188 { "always", SQLITE_TESTCTRL_ALWAYS },
2189 { "reserve", SQLITE_TESTCTRL_RESERVE },
2190 { "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS },
2191 { "iskeyword", SQLITE_TESTCTRL_ISKEYWORD },
2192 { "pghdrsz", SQLITE_TESTCTRL_PGHDRSZ },
2193 { "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC },
2194 };
2195 int testctrl = -1;
2196 int rc = 0;
2197 int i, n;
2198 open_db(p);
2199
2200 /* convert testctrl text option to value. allow any unique prefix
2201 ** of the option name, or a numerical value. */
2202 n = strlen(azArg[1]);
2203 for(i=0; i<sizeof(aCtrl)/sizeof(aCtrl[0]); i++){
2204 if( strncmp(azArg[1], aCtrl[i].zCtrlName, n)==0 ){
2205 if( testctrl<0 ){
2206 testctrl = aCtrl[i].ctrlCode;
2207 }else{
2208 fprintf(stderr, "ambiguous option name: \"%s\"\n", azArg[i]);
2209 testctrl = -1;
2210 break;
2211 }
2212 }
2213 }
2214 if( testctrl<0 ) testctrl = atoi(azArg[1]);
 
 
 
 
2215 if( (testctrl<SQLITE_TESTCTRL_FIRST) || (testctrl>SQLITE_TESTCTRL_LAST) ){
2216 fprintf(stderr,"Error: invalid testctrl option: %s\n", azArg[1]);
2217 }else{
2218 switch(testctrl){
2219
@@ -2206,11 +2223,12 @@
2223 if( nArg==3 ){
2224 int opt = (int)strtol(azArg[2], 0, 0);
2225 rc = sqlite3_test_control(testctrl, p->db, opt);
2226 printf("%d (0x%08x)\n", rc, rc);
2227 } else {
2228 fprintf(stderr,"Error: testctrl %s takes a single int option\n",
2229 azArg[1]);
2230 }
2231 break;
2232
2233 /* sqlite3_test_control(int) */
2234 case SQLITE_TESTCTRL_PRNG_SAVE:
@@ -2230,11 +2248,12 @@
2248 if( nArg==3 ){
2249 unsigned int opt = (unsigned int)atoi(azArg[2]);
2250 rc = sqlite3_test_control(testctrl, opt);
2251 printf("%d (0x%08x)\n", rc, rc);
2252 } else {
2253 fprintf(stderr,"Error: testctrl %s takes a single unsigned"
2254 " int option\n", azArg[1]);
2255 }
2256 break;
2257
2258 /* sqlite3_test_control(int, int) */
2259 case SQLITE_TESTCTRL_ASSERT:
@@ -2242,11 +2261,12 @@
2261 if( nArg==3 ){
2262 int opt = atoi(azArg[2]);
2263 rc = sqlite3_test_control(testctrl, opt);
2264 printf("%d (0x%08x)\n", rc, rc);
2265 } else {
2266 fprintf(stderr,"Error: testctrl %s takes a single int option\n",
2267 azArg[1]);
2268 }
2269 break;
2270
2271 /* sqlite3_test_control(int, char *) */
2272 #ifdef SQLITE_N_KEYWORD
@@ -2254,21 +2274,23 @@
2274 if( nArg==3 ){
2275 const char *opt = azArg[2];
2276 rc = sqlite3_test_control(testctrl, opt);
2277 printf("%d (0x%08x)\n", rc, rc);
2278 } else {
2279 fprintf(stderr,"Error: testctrl %s takes a single char * option\n",
2280 azArg[1]);
2281 }
2282 break;
2283 #endif
2284
2285 case SQLITE_TESTCTRL_BITVEC_TEST:
2286 case SQLITE_TESTCTRL_FAULT_INSTALL:
2287 case SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS:
2288 case SQLITE_TESTCTRL_SCRATCHMALLOC:
2289 default:
2290 fprintf(stderr,"Error: CLI support for testctrl %s not implemented\n",
2291 azArg[1]);
2292 break;
2293 }
2294 }
2295 }else
2296
@@ -2275,11 +2297,13 @@
2297 if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 && nArg==2 ){
2298 open_db(p);
2299 sqlite3_busy_timeout(p->db, atoi(azArg[1]));
2300 }else
2301
2302 if( HAS_TIMER && c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0
2303 && nArg==2
2304 ){
2305 enableTimer = booleanValue(azArg[1]);
2306 }else
2307
2308 if( c=='w' && strncmp(azArg[0], "width", n)==0 && nArg>1 ){
2309 int j;
@@ -2462,11 +2486,13 @@
2486 zSql = 0;
2487 nSql = 0;
2488 }
2489 }
2490 if( zSql ){
2491 if( !_all_whitespace(zSql) ){
2492 fprintf(stderr, "Error: incomplete SQL: %s\n", zSql);
2493 }
2494 free(zSql);
2495 }
2496 free(zLine);
2497 return errCnt;
2498 }
@@ -2598,10 +2624,14 @@
2624 " -list set output mode to 'list'\n"
2625 " -separator 'x' set output field separator (|)\n"
2626 " -stats print memory stats before each finalize\n"
2627 " -nullvalue 'text' set text string for NULL values\n"
2628 " -version show SQLite version\n"
2629 " -vfs NAME use NAME as the default VFS\n"
2630 #ifdef SQLITE_ENABLE_VFSTRACE
2631 " -vfstrace enable tracing of all VFS calls\n"
2632 #endif
2633 ;
2634 static void usage(int showDetail){
2635 fprintf(stderr,
2636 "Usage: %s [OPTIONS] FILENAME [SQL]\n"
2637 "FILENAME is the name of an SQLite database. A new database is created\n"
@@ -2682,10 +2712,29 @@
2712 }
2713 if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000;
2714 #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
2715 sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64);
2716 #endif
2717 #ifdef SQLITE_ENABLE_VFSTRACE
2718 }else if( strcmp(argv[i],"-vfstrace")==0 ){
2719 extern int vfstrace_register(
2720 const char *zTraceName,
2721 const char *zOldVfsName,
2722 int (*xOut)(const char*,void*),
2723 void *pOutArg,
2724 int makeDefault
2725 );
2726 vfstrace_register("trace",0,(int(*)(const char*,void*))fputs,stderr,1);
2727 #endif
2728 }else if( strcmp(argv[i],"-vfs")==0 ){
2729 sqlite3_vfs *pVfs = sqlite3_vfs_find(argv[++i]);
2730 if( pVfs ){
2731 sqlite3_vfs_register(pVfs, 1);
2732 }else{
2733 fprintf(stderr, "no such VFS: \"%s\"\n", argv[i]);
2734 exit(1);
2735 }
2736 }
2737 }
2738 if( i<argc ){
2739 #if defined(SQLITE_OS_OS2) && SQLITE_OS_OS2
2740 data.zDbFilename = (const char *)convertCpPathToUtf8( argv[i++] );
@@ -2796,10 +2845,14 @@
2845 stdin_is_interactive = 1;
2846 }else if( strcmp(z,"-batch")==0 ){
2847 stdin_is_interactive = 0;
2848 }else if( strcmp(z,"-heap")==0 ){
2849 i++;
2850 }else if( strcmp(z,"-vfs")==0 ){
2851 i++;
2852 }else if( strcmp(z,"-vfstrace")==0 ){
2853 i++;
2854 }else if( strcmp(z,"-help")==0 || strcmp(z, "--help")==0 ){
2855 usage(1);
2856 }else{
2857 fprintf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
2858 fprintf(stderr,"Use -help for a list of options.\n");
2859
+835 -403
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -650,11 +650,11 @@
650650
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
651651
** [sqlite_version()] and [sqlite_source_id()].
652652
*/
653653
#define SQLITE_VERSION "3.7.6"
654654
#define SQLITE_VERSION_NUMBER 3007006
655
-#define SQLITE_SOURCE_ID "2011-03-06 21:54:33 3bfbf026dd6a0eeef07f8f5f1ebf74c9cfebcd61"
655
+#define SQLITE_SOURCE_ID "2011-03-24 01:34:03 b6e268fce12829f058f1dfa223731ec8479493f8"
656656
657657
/*
658658
** CAPI3REF: Run-Time Library Version Numbers
659659
** KEYWORDS: sqlite3_version, sqlite3_sourceid
660660
**
@@ -1439,14 +1439,27 @@
14391439
** a 24-hour day).
14401440
** ^SQLite will use the xCurrentTimeInt64() method to get the current
14411441
** date and time if that method is available (if iVersion is 2 or
14421442
** greater and the function pointer is not NULL) and will fall back
14431443
** to xCurrentTime() if xCurrentTimeInt64() is unavailable.
1444
+**
1445
+** ^The xSetSystemCall(), xGetSystemCall(), and xNestSystemCall() interfaces
1446
+** are not used by the SQLite core. These optional interfaces are provided
1447
+** by some VFSes to facilitate testing of the VFS code. By overriding
1448
+** system calls with functions under its control, a test program can
1449
+** simulate faults and error conditions that would otherwise be difficult
1450
+** or impossible to induce. The set of system calls that can be overridden
1451
+** varies from one VFS to another, and from one version of the same VFS to the
1452
+** next. Applications that use these interfaces must be prepared for any
1453
+** or all of these interfaces to be NULL or for their behavior to change
1454
+** from one release to the next. Applications must not attempt to access
1455
+** any of these methods if the iVersion of the VFS is less than 3.
14441456
*/
14451457
typedef struct sqlite3_vfs sqlite3_vfs;
1458
+typedef void (*sqlite3_syscall_ptr)(void);
14461459
struct sqlite3_vfs {
1447
- int iVersion; /* Structure version number (currently 2) */
1460
+ int iVersion; /* Structure version number (currently 3) */
14481461
int szOsFile; /* Size of subclassed sqlite3_file */
14491462
int mxPathname; /* Maximum file pathname length */
14501463
sqlite3_vfs *pNext; /* Next registered VFS */
14511464
const char *zName; /* Name of this virtual file system */
14521465
void *pAppData; /* Pointer to application-specific data */
@@ -1468,10 +1481,17 @@
14681481
** definition. Those that follow are added in version 2 or later
14691482
*/
14701483
int (*xCurrentTimeInt64)(sqlite3_vfs*, sqlite3_int64*);
14711484
/*
14721485
** The methods above are in versions 1 and 2 of the sqlite_vfs object.
1486
+ ** Those below are for version 3 and greater.
1487
+ */
1488
+ int (*xSetSystemCall)(sqlite3_vfs*, const char *zName, sqlite3_syscall_ptr);
1489
+ sqlite3_syscall_ptr (*xGetSystemCall)(sqlite3_vfs*, const char *zName);
1490
+ const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName);
1491
+ /*
1492
+ ** The methods above are in versions 1 through 3 of the sqlite_vfs object.
14731493
** New fields may be appended in figure versions. The iVersion
14741494
** value will increment whenever this happens.
14751495
*/
14761496
};
14771497
@@ -1652,21 +1672,16 @@
16521672
** CAPI3REF: Configure database connections
16531673
**
16541674
** The sqlite3_db_config() interface is used to make configuration
16551675
** changes to a [database connection]. The interface is similar to
16561676
** [sqlite3_config()] except that the changes apply to a single
1657
-** [database connection] (specified in the first argument). The
1658
-** sqlite3_db_config() interface should only be used immediately after
1659
-** the database connection is created using [sqlite3_open()],
1660
-** [sqlite3_open16()], or [sqlite3_open_v2()].
1677
+** [database connection] (specified in the first argument).
16611678
**
16621679
** The second argument to sqlite3_db_config(D,V,...) is the
1663
-** configuration verb - an integer code that indicates what
1664
-** aspect of the [database connection] is being configured.
1665
-** The only choice for this value is [SQLITE_DBCONFIG_LOOKASIDE].
1666
-** New verbs are likely to be added in future releases of SQLite.
1667
-** Additional arguments depend on the verb.
1680
+** [SQLITE_DBCONIG_LOOKASIDE | configuration verb] - an integer code
1681
+** that indicates what aspect of the [database connection] is being configured.
1682
+** Subsequent arguments vary depending on the configuration verb.
16681683
**
16691684
** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if
16701685
** the call is considered successful.
16711686
*/
16721687
SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
@@ -1887,11 +1902,13 @@
18871902
** undoing any prior invocation of [SQLITE_CONFIG_MALLOC]. ^If the
18881903
** memory pointer is not NULL and either [SQLITE_ENABLE_MEMSYS3] or
18891904
** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory
18901905
** allocator is engaged to handle all of SQLites memory allocation needs.
18911906
** The first pointer (the memory pointer) must be aligned to an 8-byte
1892
-** boundary or subsequent behavior of SQLite will be undefined.</dd>
1907
+** boundary or subsequent behavior of SQLite will be undefined.
1908
+** The minimum allocation size is capped at 2^12. Reasonable values
1909
+** for the minimum allocation size are 2^5 through 2^8.</dd>
18931910
**
18941911
** <dt>SQLITE_CONFIG_MUTEX</dt>
18951912
** <dd> ^(This option takes a single argument which is a pointer to an
18961913
** instance of the [sqlite3_mutex_methods] structure. The argument specifies
18971914
** alternative low-level mutex routines to be used in place
@@ -2008,13 +2025,35 @@
20082025
** [sqlite3_db_status](D,[SQLITE_CONFIG_LOOKASIDE],...) is zero.
20092026
** Any attempt to change the lookaside memory configuration when lookaside
20102027
** memory is in use leaves the configuration unchanged and returns
20112028
** [SQLITE_BUSY].)^</dd>
20122029
**
2030
+** <dt>SQLITE_DBCONFIG_ENABLE_FKEY</dt>
2031
+** <dd> ^This option is used to enable or disable the enforcement of
2032
+** [foreign key constraints]. There should be two additional arguments.
2033
+** The first argument is an integer which is 0 to disable FK enforcement,
2034
+** positive to enable FK enforcement or negative to leave FK enforcement
2035
+** unchanged. The second parameter is a pointer to an integer into which
2036
+** is written 0 or 1 to indicate whether FK enforcement is off or on
2037
+** following this call. The second parameter may be a NULL pointer, in
2038
+** which case the FK enforcement setting is not reported back. </dd>
2039
+**
2040
+** <dt>SQLITE_DBCONFIG_ENABLE_TRIGGER</dt>
2041
+** <dd> ^This option is used to enable or disable [CREATE TRIGGER | triggers].
2042
+** There should be two additional arguments.
2043
+** The first argument is an integer which is 0 to disable triggers,
2044
+** positive to enable trigers or negative to leave the setting unchanged.
2045
+** The second parameter is a pointer to an integer into which
2046
+** is written 0 or 1 to indicate whether triggers are disabled or enabled
2047
+** following this call. The second parameter may be a NULL pointer, in
2048
+** which case the trigger setting is not reported back. </dd>
2049
+**
20132050
** </dl>
20142051
*/
2015
-#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */
2052
+#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */
2053
+#define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */
2054
+#define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */
20162055
20172056
20182057
/*
20192058
** CAPI3REF: Enable Or Disable Extended Result Codes
20202059
**
@@ -8974,10 +9013,11 @@
89749013
/*
89759014
** An instance of the following structure stores a database schema.
89769015
*/
89779016
struct Schema {
89789017
int schema_cookie; /* Database schema version number for this file */
9018
+ int iGeneration; /* Generation counter. Incremented with each change */
89799019
Hash tblHash; /* All tables indexed by name */
89809020
Hash idxHash; /* All (named) indices indexed by name */
89819021
Hash trigHash; /* All triggers indexed by name */
89829022
Hash fkeyHash; /* All foreign keys by referenced table name */
89839023
Table *pSeqTab; /* The sqlite_sequence table used by AUTOINCREMENT */
@@ -9227,10 +9267,11 @@
92279267
#define SQLITE_RecTriggers 0x02000000 /* Enable recursive triggers */
92289268
#define SQLITE_ForeignKeys 0x04000000 /* Enforce foreign key constraints */
92299269
#define SQLITE_AutoIndex 0x08000000 /* Enable automatic indexes */
92309270
#define SQLITE_PreferBuiltin 0x10000000 /* Preference to built-in funcs */
92319271
#define SQLITE_LoadExtension 0x20000000 /* Enable load_extension */
9272
+#define SQLITE_EnableTrigger 0x40000000 /* True to enable triggers */
92329273
92339274
/*
92349275
** Bits of the sqlite3.flags field that are used by the
92359276
** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface.
92369277
** These must be the low-order bits of the flags field.
@@ -9926,11 +9967,11 @@
99269967
u8 op; /* Operation performed by this node */
99279968
char affinity; /* The affinity of the column or 0 if not a column */
99289969
u16 flags; /* Various flags. EP_* See below */
99299970
union {
99309971
char *zToken; /* Token value. Zero terminated and dequoted */
9931
- int iValue; /* Integer value if EP_IntValue */
9972
+ int iValue; /* Non-negative integer value if EP_IntValue */
99329973
} u;
99339974
99349975
/* If the EP_TokenOnly flag is set in the Expr.flags mask, then no
99359976
** space is allocated for the fields below this point. An attempt to
99369977
** access them will result in a segfault or malfunction.
@@ -10426,10 +10467,17 @@
1042610467
SubProgram *pProgram; /* Program implementing pTrigger/orconf */
1042710468
u32 aColmask[2]; /* Masks of old.*, new.* columns accessed */
1042810469
TriggerPrg *pNext; /* Next entry in Parse.pTriggerPrg list */
1042910470
};
1043010471
10472
+/* Datatype for the bitmask of all attached databases */
10473
+#if SQLITE_MAX_ATTACHED>30
10474
+ typedef sqlite3_uint64 tAttachMask;
10475
+#else
10476
+ typedef unsigned int tAttachMask;
10477
+#endif
10478
+
1043110479
/*
1043210480
** An SQL parser context. A copy of this structure is passed through
1043310481
** the parser and down into all the parser action routine in order to
1043410482
** carry around information that is global to the entire parse.
1043510483
**
@@ -10474,12 +10522,12 @@
1047410522
u8 tempReg; /* iReg is a temp register that needs to be freed */
1047510523
int iLevel; /* Nesting level */
1047610524
int iReg; /* Reg with value of this column. 0 means none. */
1047710525
int lru; /* Least recently used entry has the smallest value */
1047810526
} aColCache[SQLITE_N_COLCACHE]; /* One for each column cache entry */
10479
- u32 writeMask; /* Start a write transaction on these databases */
10480
- u32 cookieMask; /* Bitmask of schema verified databases */
10527
+ tAttachMask writeMask; /* Start a write transaction on these databases */
10528
+ tAttachMask cookieMask; /* Bitmask of schema verified databases */
1048110529
u8 isMultiWrite; /* True if statement may affect/insert multiple rows */
1048210530
u8 mayAbort; /* True if statement may throw an ABORT exception */
1048310531
int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */
1048410532
int cookieValue[SQLITE_MAX_ATTACHED+2]; /* Values of cookies to verify */
1048510533
#ifndef SQLITE_OMIT_SHARED_CACHE
@@ -11209,10 +11257,11 @@
1120911257
SQLITE_PRIVATE int sqlite3CheckObjectName(Parse *, const char *);
1121011258
SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *, int);
1121111259
SQLITE_PRIVATE int sqlite3AddInt64(i64*,i64);
1121211260
SQLITE_PRIVATE int sqlite3SubInt64(i64*,i64);
1121311261
SQLITE_PRIVATE int sqlite3MulInt64(i64*,i64);
11262
+SQLITE_PRIVATE int sqlite3AbsInt32(int);
1121411263
1121511264
SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value*, u8);
1121611265
SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value*, u8);
1121711266
SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8,
1121811267
void(*)(void*));
@@ -12023,10 +12072,13 @@
1202312072
"OMIT_TRIGGER",
1202412073
#endif
1202512074
#ifdef SQLITE_OMIT_TRUNCATE_OPTIMIZATION
1202612075
"OMIT_TRUNCATE_OPTIMIZATION",
1202712076
#endif
12077
+#ifdef SQLITE_OMIT_UNIQUE_ENFORCEMENT
12078
+ "OMIT_UNIQUE_ENFORCEMENT",
12079
+#endif
1202812080
#ifdef SQLITE_OMIT_UTF16
1202912081
"OMIT_UTF16",
1203012082
#endif
1203112083
#ifdef SQLITE_OMIT_VACUUM
1203212084
"OMIT_VACUUM",
@@ -12436,11 +12488,11 @@
1243612488
u8 inVtabMethod; /* See comments above */
1243712489
u8 usesStmtJournal; /* True if uses a statement journal */
1243812490
u8 readOnly; /* True for read-only statements */
1243912491
u8 isPrepareV2; /* True if prepared with prepare_v2() */
1244012492
int nChange; /* Number of db changes made since last reset */
12441
- int btreeMask; /* Bitmask of db->aDb[] entries referenced */
12493
+ tAttachMask btreeMask; /* Bitmask of db->aDb[] entries referenced */
1244212494
int iStatement; /* Statement number (or 0 if has not opened stmt) */
1244312495
int aCounter[3]; /* Counters used by sqlite3_stmt_status() */
1244412496
BtreeMutexArray aMutex; /* An array of Btree used here and needing locks */
1244512497
#ifndef SQLITE_OMIT_TRACE
1244612498
i64 startTime; /* Time when query started - used for profiling */
@@ -16155,11 +16207,11 @@
1615516207
** memsys5Log(8) -> 3
1615616208
** memsys5Log(9) -> 4
1615716209
*/
1615816210
static int memsys5Log(int iValue){
1615916211
int iLog;
16160
- for(iLog=0; (1<<iLog)<iValue; iLog++);
16212
+ for(iLog=0; (iLog<((sizeof(int)*8)-1)) && (1<<iLog)<iValue; iLog++);
1616116213
return iLog;
1616216214
}
1616316215
1616416216
/*
1616516217
** Initialize the memory allocator.
@@ -16186,10 +16238,11 @@
1618616238
1618716239
nByte = sqlite3GlobalConfig.nHeap;
1618816240
zByte = (u8*)sqlite3GlobalConfig.pHeap;
1618916241
assert( zByte!=0 ); /* sqlite3_config() does not allow otherwise */
1619016242
16243
+ /* boundaries on sqlite3GlobalConfig.mnReq are enforced in sqlite3_config() */
1619116244
nMinLog = memsys5Log(sqlite3GlobalConfig.mnReq);
1619216245
mem5.szAtom = (1<<nMinLog);
1619316246
while( (int)sizeof(Mem5Link)>mem5.szAtom ){
1619416247
mem5.szAtom = mem5.szAtom << 1;
1619516248
}
@@ -16689,15 +16742,20 @@
1668916742
** Each recursive mutex is an instance of the following structure.
1669016743
*/
1669116744
struct sqlite3_mutex {
1669216745
HMTX mutex; /* Mutex controlling the lock */
1669316746
int id; /* Mutex type */
16694
- int nRef; /* Number of references */
16695
- TID owner; /* Thread holding this mutex */
16747
+#ifdef SQLITE_DEBUG
16748
+ int trace; /* True to trace changes */
16749
+#endif
1669616750
};
1669716751
16698
-#define OS2_MUTEX_INITIALIZER 0,0,0,0
16752
+#ifdef SQLITE_DEBUG
16753
+#define SQLITE3_MUTEX_INITIALIZER { 0, 0, 0 }
16754
+#else
16755
+#define SQLITE3_MUTEX_INITIALIZER { 0, 0 }
16756
+#endif
1669916757
1670016758
/*
1670116759
** Initialize and deinitialize the mutex subsystem.
1670216760
*/
1670316761
static int os2MutexInit(void){ return SQLITE_OK; }
@@ -16709,15 +16767,18 @@
1670916767
** that means that a mutex could not be allocated.
1671016768
** SQLite will unwind its stack and return an error. The argument
1671116769
** to sqlite3_mutex_alloc() is one of these integer constants:
1671216770
**
1671316771
** <ul>
16714
-** <li> SQLITE_MUTEX_FAST 0
16715
-** <li> SQLITE_MUTEX_RECURSIVE 1
16716
-** <li> SQLITE_MUTEX_STATIC_MASTER 2
16717
-** <li> SQLITE_MUTEX_STATIC_MEM 3
16718
-** <li> SQLITE_MUTEX_STATIC_PRNG 4
16772
+** <li> SQLITE_MUTEX_FAST
16773
+** <li> SQLITE_MUTEX_RECURSIVE
16774
+** <li> SQLITE_MUTEX_STATIC_MASTER
16775
+** <li> SQLITE_MUTEX_STATIC_MEM
16776
+** <li> SQLITE_MUTEX_STATIC_MEM2
16777
+** <li> SQLITE_MUTEX_STATIC_PRNG
16778
+** <li> SQLITE_MUTEX_STATIC_LRU
16779
+** <li> SQLITE_MUTEX_STATIC_LRU2
1671916780
** </ul>
1672016781
**
1672116782
** The first two constants cause sqlite3_mutex_alloc() to create
1672216783
** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
1672316784
** is used but not necessarily so when SQLITE_MUTEX_FAST is used.
@@ -16727,11 +16788,11 @@
1672716788
** cases where it really needs one. If a faster non-recursive mutex
1672816789
** implementation is available on the host platform, the mutex subsystem
1672916790
** might return such a mutex in response to SQLITE_MUTEX_FAST.
1673016791
**
1673116792
** The other allowed parameters to sqlite3_mutex_alloc() each return
16732
-** a pointer to a static preexisting mutex. Three static mutexes are
16793
+** a pointer to a static preexisting mutex. Six static mutexes are
1673316794
** used by the current version of SQLite. Future versions of SQLite
1673416795
** may add additional static mutexes. Static mutexes are for internal
1673516796
** use by SQLite only. Applications that use SQLite mutexes should
1673616797
** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or
1673716798
** SQLITE_MUTEX_RECURSIVE.
@@ -16757,17 +16818,17 @@
1675716818
}
1675816819
break;
1675916820
}
1676016821
default: {
1676116822
static volatile int isInit = 0;
16762
- static sqlite3_mutex staticMutexes[] = {
16763
- { OS2_MUTEX_INITIALIZER, },
16764
- { OS2_MUTEX_INITIALIZER, },
16765
- { OS2_MUTEX_INITIALIZER, },
16766
- { OS2_MUTEX_INITIALIZER, },
16767
- { OS2_MUTEX_INITIALIZER, },
16768
- { OS2_MUTEX_INITIALIZER, },
16823
+ static sqlite3_mutex staticMutexes[6] = {
16824
+ SQLITE3_MUTEX_INITIALIZER,
16825
+ SQLITE3_MUTEX_INITIALIZER,
16826
+ SQLITE3_MUTEX_INITIALIZER,
16827
+ SQLITE3_MUTEX_INITIALIZER,
16828
+ SQLITE3_MUTEX_INITIALIZER,
16829
+ SQLITE3_MUTEX_INITIALIZER,
1676916830
};
1677016831
if ( !isInit ){
1677116832
APIRET rc;
1677216833
PTIB ptib;
1677316834
PPIB ppib;
@@ -16809,13 +16870,18 @@
1680916870
/*
1681016871
** This routine deallocates a previously allocated mutex.
1681116872
** SQLite is careful to deallocate every mutex that it allocates.
1681216873
*/
1681316874
static void os2MutexFree(sqlite3_mutex *p){
16814
- if( p==0 ) return;
16815
- assert( p->nRef==0 );
16875
+#ifdef SQLITE_DEBUG
16876
+ TID tid;
16877
+ PID pid;
16878
+ ULONG ulCount;
16879
+ DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount);
16880
+ assert( ulCount==0 );
1681616881
assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
16882
+#endif
1681716883
DosCloseMutexSem( p->mutex );
1681816884
sqlite3_free( p );
1681916885
}
1682016886
1682116887
#ifdef SQLITE_DEBUG
@@ -16826,30 +16892,33 @@
1682616892
static int os2MutexHeld(sqlite3_mutex *p){
1682716893
TID tid;
1682816894
PID pid;
1682916895
ULONG ulCount;
1683016896
PTIB ptib;
16831
- if( p!=0 ) {
16832
- DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount);
16833
- } else {
16834
- DosGetInfoBlocks(&ptib, NULL);
16835
- tid = ptib->tib_ptib2->tib2_ultid;
16836
- }
16837
- return p==0 || (p->nRef!=0 && p->owner==tid);
16897
+ DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount);
16898
+ if( ulCount==0 || ( ulCount>1 && p->id!=SQLITE_MUTEX_RECURSIVE ) )
16899
+ return 0;
16900
+ DosGetInfoBlocks(&ptib, NULL);
16901
+ return tid==ptib->tib_ptib2->tib2_ultid;
1683816902
}
1683916903
static int os2MutexNotheld(sqlite3_mutex *p){
1684016904
TID tid;
1684116905
PID pid;
1684216906
ULONG ulCount;
1684316907
PTIB ptib;
16844
- if( p!= 0 ) {
16845
- DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount);
16846
- } else {
16847
- DosGetInfoBlocks(&ptib, NULL);
16848
- tid = ptib->tib_ptib2->tib2_ultid;
16849
- }
16850
- return p==0 || p->nRef==0 || p->owner!=tid;
16908
+ DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount);
16909
+ if( ulCount==0 )
16910
+ return 1;
16911
+ DosGetInfoBlocks(&ptib, NULL);
16912
+ return tid!=ptib->tib_ptib2->tib2_ultid;
16913
+}
16914
+static void os2MutexTrace(sqlite3_mutex *p, char *pAction){
16915
+ TID tid;
16916
+ PID pid;
16917
+ ULONG ulCount;
16918
+ DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount);
16919
+ printf("%s mutex %p (%d) with nRef=%ld\n", pAction, (void*)p, p->trace, ulCount);
1685116920
}
1685216921
#endif
1685316922
1685416923
/*
1685516924
** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
@@ -16861,36 +16930,25 @@
1686116930
** mutex must be exited an equal number of times before another thread
1686216931
** can enter. If the same thread tries to enter any other kind of mutex
1686316932
** more than once, the behavior is undefined.
1686416933
*/
1686516934
static void os2MutexEnter(sqlite3_mutex *p){
16866
- TID tid;
16867
- PID holder1;
16868
- ULONG holder2;
16869
- if( p==0 ) return;
1687016935
assert( p->id==SQLITE_MUTEX_RECURSIVE || os2MutexNotheld(p) );
1687116936
DosRequestMutexSem(p->mutex, SEM_INDEFINITE_WAIT);
16872
- DosQueryMutexSem(p->mutex, &holder1, &tid, &holder2);
16873
- p->owner = tid;
16874
- p->nRef++;
16937
+#ifdef SQLITE_DEBUG
16938
+ if( p->trace ) os2MutexTrace(p, "enter");
16939
+#endif
1687516940
}
1687616941
static int os2MutexTry(sqlite3_mutex *p){
16877
- int rc;
16878
- TID tid;
16879
- PID holder1;
16880
- ULONG holder2;
16881
- if( p==0 ) return SQLITE_OK;
16942
+ int rc = SQLITE_BUSY;
1688216943
assert( p->id==SQLITE_MUTEX_RECURSIVE || os2MutexNotheld(p) );
16883
- if( DosRequestMutexSem(p->mutex, SEM_IMMEDIATE_RETURN) == NO_ERROR) {
16884
- DosQueryMutexSem(p->mutex, &holder1, &tid, &holder2);
16885
- p->owner = tid;
16886
- p->nRef++;
16944
+ if( DosRequestMutexSem(p->mutex, SEM_IMMEDIATE_RETURN) == NO_ERROR ) {
1688716945
rc = SQLITE_OK;
16888
- } else {
16889
- rc = SQLITE_BUSY;
16946
+#ifdef SQLITE_DEBUG
16947
+ if( p->trace ) os2MutexTrace(p, "try");
16948
+#endif
1689016949
}
16891
-
1689216950
return rc;
1689316951
}
1689416952
1689516953
/*
1689616954
** The sqlite3_mutex_leave() routine exits a mutex that was
@@ -16897,23 +16955,18 @@
1689716955
** previously entered by the same thread. The behavior
1689816956
** is undefined if the mutex is not currently entered or
1689916957
** is not currently allocated. SQLite will never do either.
1690016958
*/
1690116959
static void os2MutexLeave(sqlite3_mutex *p){
16902
- TID tid;
16903
- PID holder1;
16904
- ULONG holder2;
16905
- if( p==0 ) return;
16906
- assert( p->nRef>0 );
16907
- DosQueryMutexSem(p->mutex, &holder1, &tid, &holder2);
16908
- assert( p->owner==tid );
16909
- p->nRef--;
16910
- assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
16960
+ assert( os2MutexHeld(p) );
1691116961
DosReleaseMutexSem(p->mutex);
16962
+#ifdef SQLITE_DEBUG
16963
+ if( p->trace ) os2MutexTrace(p, "leave");
16964
+#endif
1691216965
}
1691316966
16914
-SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
16967
+SQLITE_PRIVATE SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
1691516968
static const sqlite3_mutex_methods sMutex = {
1691616969
os2MutexInit,
1691716970
os2MutexEnd,
1691816971
os2MutexAlloc,
1691916972
os2MutexFree,
@@ -16921,10 +16974,13 @@
1692116974
os2MutexTry,
1692216975
os2MutexLeave,
1692316976
#ifdef SQLITE_DEBUG
1692416977
os2MutexHeld,
1692516978
os2MutexNotheld
16979
+#else
16980
+ 0,
16981
+ 0
1692616982
#endif
1692716983
};
1692816984
1692916985
return &sMutex;
1693016986
}
@@ -17564,11 +17620,11 @@
1756417620
#else
1756517621
UNUSED_PARAMETER(p);
1756617622
#endif
1756717623
#ifdef SQLITE_DEBUG
1756817624
if( rc==SQLITE_OK && p->trace ){
17569
- printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
17625
+ printf("try mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
1757017626
}
1757117627
#endif
1757217628
return rc;
1757317629
}
1757417630
@@ -21270,10 +21326,20 @@
2127021326
r *= TWOPOWER32;
2127121327
if( sqlite3AddInt64(&r, iA0*iB0) ) return 1;
2127221328
*pA = r;
2127321329
return 0;
2127421330
}
21331
+
21332
+/*
21333
+** Compute the absolute value of a 32-bit signed integer, of possible. Or
21334
+** if the integer has a value of -2147483648, return +2147483647
21335
+*/
21336
+SQLITE_PRIVATE int sqlite3AbsInt32(int x){
21337
+ if( x>=0 ) return x;
21338
+ if( x==(int)0x80000000 ) return 0x7fffffff;
21339
+ return -x;
21340
+}
2127521341
2127621342
/************** End of util.c ************************************************/
2127721343
/************** Begin file hash.c ********************************************/
2127821344
/*
2127921345
** 2001 September 22
@@ -22560,23 +22626,27 @@
2256022626
/*
2256122627
** This vector defines all the methods that can operate on an
2256222628
** sqlite3_file for os2.
2256322629
*/
2256422630
static const sqlite3_io_methods os2IoMethod = {
22565
- 1, /* iVersion */
22566
- os2Close,
22567
- os2Read,
22568
- os2Write,
22569
- os2Truncate,
22570
- os2Sync,
22571
- os2FileSize,
22572
- os2Lock,
22573
- os2Unlock,
22574
- os2CheckReservedLock,
22575
- os2FileControl,
22576
- os2SectorSize,
22577
- os2DeviceCharacteristics
22631
+ 1, /* iVersion */
22632
+ os2Close, /* xClose */
22633
+ os2Read, /* xRead */
22634
+ os2Write, /* xWrite */
22635
+ os2Truncate, /* xTruncate */
22636
+ os2Sync, /* xSync */
22637
+ os2FileSize, /* xFileSize */
22638
+ os2Lock, /* xLock */
22639
+ os2Unlock, /* xUnlock */
22640
+ os2CheckReservedLock, /* xCheckReservedLock */
22641
+ os2FileControl, /* xFileControl */
22642
+ os2SectorSize, /* xSectorSize */
22643
+ os2DeviceCharacteristics, /* xDeviceCharacteristics */
22644
+ 0, /* xShmMap */
22645
+ 0, /* xShmLock */
22646
+ 0, /* xShmBarrier */
22647
+ 0 /* xShmUnmap */
2257822648
};
2257922649
2258022650
/***************************************************************************
2258122651
** Here ends the I/O methods that form the sqlite3_io_methods object.
2258222652
**
@@ -22664,115 +22734,151 @@
2266422734
/*
2266522735
** Open a file.
2266622736
*/
2266722737
static int os2Open(
2266822738
sqlite3_vfs *pVfs, /* Not used */
22669
- const char *zName, /* Name of the file */
22739
+ const char *zName, /* Name of the file (UTF-8) */
2267022740
sqlite3_file *id, /* Write the SQLite file handle here */
2267122741
int flags, /* Open mode flags */
2267222742
int *pOutFlags /* Status return flags */
2267322743
){
2267422744
HFILE h;
22675
- ULONG ulFileAttribute = FILE_NORMAL;
2267622745
ULONG ulOpenFlags = 0;
2267722746
ULONG ulOpenMode = 0;
22747
+ ULONG ulAction = 0;
22748
+ ULONG rc;
2267822749
os2File *pFile = (os2File*)id;
22679
- APIRET rc = NO_ERROR;
22680
- ULONG ulAction;
22750
+ const char *zUtf8Name = zName;
2268122751
char *zNameCp;
22682
- char zTmpname[CCHMAXPATH+1]; /* Buffer to hold name of temp file */
22752
+ char zTmpname[CCHMAXPATH];
22753
+
22754
+ int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE);
22755
+ int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE);
22756
+ int isCreate = (flags & SQLITE_OPEN_CREATE);
22757
+ int isReadWrite = (flags & SQLITE_OPEN_READWRITE);
22758
+#ifndef NDEBUG
22759
+ int isReadonly = (flags & SQLITE_OPEN_READONLY);
22760
+ int eType = (flags & 0xFFFFFF00);
22761
+ int isOpenJournal = (isCreate && (
22762
+ eType==SQLITE_OPEN_MASTER_JOURNAL
22763
+ || eType==SQLITE_OPEN_MAIN_JOURNAL
22764
+ || eType==SQLITE_OPEN_WAL
22765
+ ));
22766
+#endif
22767
+
22768
+ UNUSED_PARAMETER(pVfs);
22769
+ assert( id!=0 );
22770
+
22771
+ /* Check the following statements are true:
22772
+ **
22773
+ ** (a) Exactly one of the READWRITE and READONLY flags must be set, and
22774
+ ** (b) if CREATE is set, then READWRITE must also be set, and
22775
+ ** (c) if EXCLUSIVE is set, then CREATE must also be set.
22776
+ ** (d) if DELETEONCLOSE is set, then CREATE must also be set.
22777
+ */
22778
+ assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly));
22779
+ assert(isCreate==0 || isReadWrite);
22780
+ assert(isExclusive==0 || isCreate);
22781
+ assert(isDelete==0 || isCreate);
22782
+
22783
+ /* The main DB, main journal, WAL file and master journal are never
22784
+ ** automatically deleted. Nor are they ever temporary files. */
22785
+ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB );
22786
+ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL );
22787
+ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL );
22788
+ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL );
22789
+
22790
+ /* Assert that the upper layer has set one of the "file-type" flags. */
22791
+ assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB
22792
+ || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
22793
+ || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL
22794
+ || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
22795
+ );
22796
+
22797
+ memset( pFile, 0, sizeof(*pFile) );
22798
+ pFile->pMethod = &os2IoMethod;
2268322799
2268422800
/* If the second argument to this function is NULL, generate a
2268522801
** temporary file name to use
2268622802
*/
22687
- if( !zName ){
22688
- int rc = getTempname(CCHMAXPATH+1, zTmpname);
22803
+ if( !zUtf8Name ){
22804
+ assert(isDelete && !isOpenJournal);
22805
+ rc = getTempname(CCHMAXPATH, zTmpname);
2268922806
if( rc!=SQLITE_OK ){
2269022807
return rc;
2269122808
}
22692
- zName = zTmpname;
22809
+ zUtf8Name = zTmpname;
2269322810
}
2269422811
22695
-
22696
- memset( pFile, 0, sizeof(*pFile) );
22697
-
22698
- OSTRACE(( "OPEN want %d\n", flags ));
22699
-
22700
- if( flags & SQLITE_OPEN_READWRITE ){
22812
+ if( isReadWrite ){
2270122813
ulOpenMode |= OPEN_ACCESS_READWRITE;
22702
- OSTRACE(( "OPEN read/write\n" ));
2270322814
}else{
2270422815
ulOpenMode |= OPEN_ACCESS_READONLY;
22705
- OSTRACE(( "OPEN read only\n" ));
22706
- }
22707
-
22708
- if( flags & SQLITE_OPEN_CREATE ){
22709
- ulOpenFlags |= OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW;
22710
- OSTRACE(( "OPEN open new/create\n" ));
22711
- }else{
22712
- ulOpenFlags |= OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW;
22713
- OSTRACE(( "OPEN open existing\n" ));
22714
- }
22715
-
22716
- if( flags & SQLITE_OPEN_MAIN_DB ){
22717
- ulOpenMode |= OPEN_SHARE_DENYNONE;
22718
- OSTRACE(( "OPEN share read/write\n" ));
22719
- }else{
22720
- ulOpenMode |= OPEN_SHARE_DENYWRITE;
22721
- OSTRACE(( "OPEN share read only\n" ));
22722
- }
22723
-
22724
- if( flags & SQLITE_OPEN_DELETEONCLOSE ){
22725
- char pathUtf8[CCHMAXPATH];
22726
-#ifdef NDEBUG /* when debugging we want to make sure it is deleted */
22727
- ulFileAttribute = FILE_HIDDEN;
22728
-#endif
22729
- os2FullPathname( pVfs, zName, CCHMAXPATH, pathUtf8 );
22730
- pFile->pathToDel = convertUtf8PathToCp( pathUtf8 );
22731
- OSTRACE(( "OPEN hidden/delete on close file attributes\n" ));
22732
- }else{
22733
- pFile->pathToDel = NULL;
22734
- OSTRACE(( "OPEN normal file attribute\n" ));
22735
- }
22736
-
22737
- /* always open in random access mode for possibly better speed */
22816
+ }
22817
+
22818
+ /* Open in random access mode for possibly better speed. Allow full
22819
+ ** sharing because file locks will provide exclusive access when needed.
22820
+ */
2273822821
ulOpenMode |= OPEN_FLAGS_RANDOM;
2273922822
ulOpenMode |= OPEN_FLAGS_FAIL_ON_ERROR;
2274022823
ulOpenMode |= OPEN_FLAGS_NOINHERIT;
22824
+ ulOpenMode |= OPEN_SHARE_DENYNONE;
2274122825
22742
- zNameCp = convertUtf8PathToCp( zName );
22826
+ /* SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is
22827
+ ** created. SQLite doesn't use it to indicate "exclusive access"
22828
+ ** as it is usually understood.
22829
+ */
22830
+ if( isExclusive ){
22831
+ /* Creates a new file, only if it does not already exist. */
22832
+ /* If the file exists, it fails. */
22833
+ ulOpenFlags |= OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_FAIL_IF_EXISTS;
22834
+ }else if( isCreate ){
22835
+ /* Open existing file, or create if it doesn't exist */
22836
+ ulOpenFlags |= OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
22837
+ }else{
22838
+ /* Opens a file, only if it exists. */
22839
+ ulOpenFlags |= OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
22840
+ }
22841
+
22842
+ /* For DELETEONCLOSE, save a pointer to the converted filename */
22843
+ if( isDelete ){
22844
+ char pathUtf8[CCHMAXPATH];
22845
+ os2FullPathname( pVfs, zUtf8Name, CCHMAXPATH, pathUtf8 );
22846
+ pFile->pathToDel = convertUtf8PathToCp( pathUtf8 );
22847
+ }
22848
+
22849
+ zNameCp = convertUtf8PathToCp( zUtf8Name );
2274322850
rc = DosOpen( (PSZ)zNameCp,
2274422851
&h,
2274522852
&ulAction,
2274622853
0L,
22747
- ulFileAttribute,
22854
+ FILE_NORMAL,
2274822855
ulOpenFlags,
2274922856
ulOpenMode,
2275022857
(PEAOP2)NULL );
2275122858
free( zNameCp );
22859
+
2275222860
if( rc != NO_ERROR ){
22753
- OSTRACE(( "OPEN Invalid handle rc=%d: zName=%s, ulAction=%#lx, ulAttr=%#lx, ulFlags=%#lx, ulMode=%#lx\n",
22754
- rc, zName, ulAction, ulFileAttribute, ulOpenFlags, ulOpenMode ));
22861
+ OSTRACE(( "OPEN Invalid handle rc=%d: zName=%s, ulAction=%#lx, ulFlags=%#lx, ulMode=%#lx\n",
22862
+ rc, zUtf8Name, ulAction, ulOpenFlags, ulOpenMode ));
2275522863
if( pFile->pathToDel )
2275622864
free( pFile->pathToDel );
2275722865
pFile->pathToDel = NULL;
22758
- if( flags & SQLITE_OPEN_READWRITE ){
22759
- OSTRACE(( "OPEN %d Invalid handle\n",
22760
- ((flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE) ));
22866
+
22867
+ if( isReadWrite ){
2276122868
return os2Open( pVfs, zName, id,
22762
- ((flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE),
22869
+ ((flags|SQLITE_OPEN_READONLY)&~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)),
2276322870
pOutFlags );
2276422871
}else{
2276522872
return SQLITE_CANTOPEN;
2276622873
}
2276722874
}
2276822875
2276922876
if( pOutFlags ){
22770
- *pOutFlags = flags & SQLITE_OPEN_READWRITE ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY;
22877
+ *pOutFlags = isReadWrite ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY;
2277122878
}
2277222879
22773
- pFile->pMethod = &os2IoMethod;
2277422880
pFile->h = h;
2277522881
OpenCounter(+1);
2277622882
OSTRACE(( "OPEN %d pOutFlags=%d\n", pFile->h, pOutFlags ));
2277722883
return SQLITE_OK;
2277822884
}
@@ -22783,17 +22889,20 @@
2278322889
static int os2Delete(
2278422890
sqlite3_vfs *pVfs, /* Not used on os2 */
2278522891
const char *zFilename, /* Name of file to delete */
2278622892
int syncDir /* Not used on os2 */
2278722893
){
22788
- APIRET rc = NO_ERROR;
22789
- char *zFilenameCp = convertUtf8PathToCp( zFilename );
22894
+ APIRET rc;
22895
+ char *zFilenameCp;
2279022896
SimulateIOError( return SQLITE_IOERR_DELETE );
22897
+ zFilenameCp = convertUtf8PathToCp( zFilename );
2279122898
rc = DosDelete( (PSZ)zFilenameCp );
2279222899
free( zFilenameCp );
2279322900
OSTRACE(( "DELETE \"%s\"\n", zFilename ));
22794
- return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR_DELETE;
22901
+ return (rc == NO_ERROR ||
22902
+ rc == ERROR_FILE_NOT_FOUND ||
22903
+ rc == ERROR_PATH_NOT_FOUND ) ? SQLITE_OK : SQLITE_IOERR_DELETE;
2279522904
}
2279622905
2279722906
/*
2279822907
** Check the existance and status of a file.
2279922908
*/
@@ -22854,11 +22963,11 @@
2285422963
** os2Dlopen returns zero if DosLoadModule is not successful.
2285522964
*/
2285622965
static void os2DlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
2285722966
/* no-op */
2285822967
}
22859
-static void *os2DlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){
22968
+static void (*os2DlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol))(void){
2286022969
PFN pfn;
2286122970
APIRET rc;
2286222971
rc = DosQueryProcAddr((HMODULE)pHandle, 0L, zSymbol, &pfn);
2286322972
if( rc != NO_ERROR ){
2286422973
/* if the symbol itself was not found, search again for the same
@@ -22866,11 +22975,11 @@
2286622975
* on the calling convention */
2286722976
char _zSymbol[256] = "_";
2286822977
strncat(_zSymbol, zSymbol, 255);
2286922978
rc = DosQueryProcAddr((HMODULE)pHandle, 0L, _zSymbol, &pfn);
2287022979
}
22871
- return rc != NO_ERROR ? 0 : (void*)pfn;
22980
+ return rc != NO_ERROR ? 0 : (void(*)(void))pfn;
2287222981
}
2287322982
static void os2DlClose(sqlite3_vfs *pVfs, void *pHandle){
2287422983
DosFreeModule((HMODULE)pHandle);
2287522984
}
2287622985
#else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */
@@ -22970,14 +23079,15 @@
2297023079
** return 0. Return 1 if the time and date cannot be found.
2297123080
*/
2297223081
int os2CurrentTime( sqlite3_vfs *pVfs, double *prNow ){
2297323082
double now;
2297423083
SHORT minute; /* needs to be able to cope with negative timezone offset */
22975
- USHORT second, hour,
23084
+ USHORT hundredths, second, hour,
2297623085
day, month, year;
2297723086
DATETIME dt;
2297823087
DosGetDateTime( &dt );
23088
+ hundredths = (USHORT)dt.hundredths;
2297923089
second = (USHORT)dt.seconds;
2298023090
minute = (SHORT)dt.minutes + dt.timezone;
2298123091
hour = (USHORT)dt.hours;
2298223092
day = (USHORT)dt.day;
2298323093
month = (USHORT)dt.month;
@@ -22993,18 +23103,35 @@
2299323103
2299423104
/* Add the fractional hours, mins and seconds */
2299523105
now += (hour + 12.0)/24.0;
2299623106
now += minute/1440.0;
2299723107
now += second/86400.0;
23108
+ now += hundredths/8640000.0;
2299823109
*prNow = now;
2299923110
#ifdef SQLITE_TEST
2300023111
if( sqlite3_current_time ){
2300123112
*prNow = sqlite3_current_time/86400.0 + 2440587.5;
2300223113
}
2300323114
#endif
2300423115
return 0;
2300523116
}
23117
+
23118
+/*
23119
+** Find the current time (in Universal Coordinated Time). Write into *piNow
23120
+** the current time and date as a Julian Day number times 86_400_000. In
23121
+** other words, write into *piNow the number of milliseconds since the Julian
23122
+** epoch of noon in Greenwich on November 24, 4714 B.C according to the
23123
+** proleptic Gregorian calendar.
23124
+**
23125
+** On success, return 0. Return 1 if the time and date cannot be found.
23126
+*/
23127
+static int os2CurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){
23128
+ double now;
23129
+ os2CurrentTime(pVfs, &now);
23130
+ *piNow = now * 86400000;
23131
+ return 0;
23132
+}
2300623133
2300723134
static int os2GetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
2300823135
return 0;
2300923136
}
2301023137
@@ -23011,11 +23138,11 @@
2301123138
/*
2301223139
** Initialize and deinitialize the operating system interface.
2301323140
*/
2301423141
SQLITE_API int sqlite3_os_init(void){
2301523142
static sqlite3_vfs os2Vfs = {
23016
- 1, /* iVersion */
23143
+ 3, /* iVersion */
2301723144
sizeof(os2File), /* szOsFile */
2301823145
CCHMAXPATH, /* mxPathname */
2301923146
0, /* pNext */
2302023147
"os2", /* zName */
2302123148
0, /* pAppData */
@@ -23030,10 +23157,14 @@
2303023157
os2DlClose, /* xDlClose */
2303123158
os2Randomness, /* xRandomness */
2303223159
os2Sleep, /* xSleep */
2303323160
os2CurrentTime, /* xCurrentTime */
2303423161
os2GetLastError, /* xGetLastError */
23162
+ os2CurrentTimeInt64 /* xCurrentTimeInt64 */
23163
+ 0, /* xSetSystemCall */
23164
+ 0, /* xGetSystemCall */
23165
+ 0, /* xNextSystemCall */
2303523166
};
2303623167
sqlite3_vfs_register(&os2Vfs, 1);
2303723168
initUconvObjects();
2303823169
return SQLITE_OK;
2303923170
}
@@ -23249,14 +23380,14 @@
2324923380
sqlite3_io_methods const *pMethod; /* Always the first entry */
2325023381
unixInodeInfo *pInode; /* Info about locks on this inode */
2325123382
int h; /* The file descriptor */
2325223383
int dirfd; /* File descriptor for the directory */
2325323384
unsigned char eFileLock; /* The type of lock held on this fd */
23385
+ unsigned char ctrlFlags; /* Behavioral bits. UNIXFILE_* flags */
2325423386
int lastErrno; /* The unix errno from last I/O error */
2325523387
void *lockingContext; /* Locking style specific state */
2325623388
UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */
23257
- int fileFlags; /* Miscellanous flags */
2325823389
const char *zPath; /* Name of the file */
2325923390
unixShm *pShm; /* Shared memory segment information */
2326023391
int szChunk; /* Configured by FCNTL_CHUNK_SIZE */
2326123392
#if SQLITE_ENABLE_LOCKING_STYLE
2326223393
int openFlags; /* The flags specified at open() */
@@ -23287,13 +23418,14 @@
2328723418
char aPadding[32];
2328823419
#endif
2328923420
};
2329023421
2329123422
/*
23292
-** The following macros define bits in unixFile.fileFlags
23423
+** Allowed values for the unixFile.ctrlFlags bitmask:
2329323424
*/
23294
-#define SQLITE_WHOLE_FILE_LOCKING 0x0001 /* Use whole-file locking */
23425
+#define UNIXFILE_EXCL 0x01 /* Connections from one process only */
23426
+#define UNIXFILE_RDONLY 0x02 /* Connection is read only */
2329523427
2329623428
/*
2329723429
** Include code that is common to all os_*.c files
2329823430
*/
2329923431
/************** Include os_common.h in the middle of os_unix.c ***************/
@@ -23518,20 +23650,10 @@
2351823650
#endif
2351923651
#ifndef O_BINARY
2352023652
# define O_BINARY 0
2352123653
#endif
2352223654
23523
-/*
23524
-** The DJGPP compiler environment looks mostly like Unix, but it
23525
-** lacks the fcntl() system call. So redefine fcntl() to be something
23526
-** that always succeeds. This means that locking does not occur under
23527
-** DJGPP. But it is DOS - what did you expect?
23528
-*/
23529
-#ifdef __DJGPP__
23530
-# define fcntl(A,B,C) 0
23531
-#endif
23532
-
2353323655
/*
2353423656
** The threadid macro resolves to the thread-id or to 0. Used for
2353523657
** testing and debugging only.
2353623658
*/
2353723659
#if SQLITE_THREADSAFE
@@ -23538,10 +23660,197 @@
2353823660
#define threadid pthread_self()
2353923661
#else
2354023662
#define threadid 0
2354123663
#endif
2354223664
23665
+/*
23666
+** Many system calls are accessed through pointer-to-functions so that
23667
+** they may be overridden at runtime to facilitate fault injection during
23668
+** testing and sandboxing. The following array holds the names and pointers
23669
+** to all overrideable system calls.
23670
+*/
23671
+static struct unix_syscall {
23672
+ const char *zName; /* Name of the sytem call */
23673
+ sqlite3_syscall_ptr pCurrent; /* Current value of the system call */
23674
+ sqlite3_syscall_ptr pDefault; /* Default value */
23675
+} aSyscall[] = {
23676
+ { "open", (sqlite3_syscall_ptr)open, 0 },
23677
+#define osOpen ((int(*)(const char*,int,int))aSyscall[0].pCurrent)
23678
+
23679
+ { "close", (sqlite3_syscall_ptr)close, 0 },
23680
+#define osClose ((int(*)(int))aSyscall[1].pCurrent)
23681
+
23682
+ { "access", (sqlite3_syscall_ptr)access, 0 },
23683
+#define osAccess ((int(*)(const char*,int))aSyscall[2].pCurrent)
23684
+
23685
+ { "getcwd", (sqlite3_syscall_ptr)getcwd, 0 },
23686
+#define osGetcwd ((char*(*)(char*,size_t))aSyscall[3].pCurrent)
23687
+
23688
+ { "stat", (sqlite3_syscall_ptr)stat, 0 },
23689
+#define osStat ((int(*)(const char*,struct stat*))aSyscall[4].pCurrent)
23690
+
23691
+/*
23692
+** The DJGPP compiler environment looks mostly like Unix, but it
23693
+** lacks the fcntl() system call. So redefine fcntl() to be something
23694
+** that always succeeds. This means that locking does not occur under
23695
+** DJGPP. But it is DOS - what did you expect?
23696
+*/
23697
+#ifdef __DJGPP__
23698
+ { "fstat", 0, 0 },
23699
+#define osFstat(a,b,c) 0
23700
+#else
23701
+ { "fstat", (sqlite3_syscall_ptr)fstat, 0 },
23702
+#define osFstat ((int(*)(int,struct stat*))aSyscall[5].pCurrent)
23703
+#endif
23704
+
23705
+ { "ftruncate", (sqlite3_syscall_ptr)ftruncate, 0 },
23706
+#define osFtruncate ((int(*)(int,off_t))aSyscall[6].pCurrent)
23707
+
23708
+ { "fcntl", (sqlite3_syscall_ptr)fcntl, 0 },
23709
+#define osFcntl ((int(*)(int,int,...))aSyscall[7].pCurrent)
23710
+
23711
+ { "read", (sqlite3_syscall_ptr)read, 0 },
23712
+#define osRead ((ssize_t(*)(int,void*,size_t))aSyscall[8].pCurrent)
23713
+
23714
+#if defined(USE_PREAD) || defined(SQLITE_ENABLE_LOCKING_STYLE)
23715
+ { "pread", (sqlite3_syscall_ptr)pread, 0 },
23716
+#else
23717
+ { "pread", (sqlite3_syscall_ptr)0, 0 },
23718
+#endif
23719
+#define osPread ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[9].pCurrent)
23720
+
23721
+#if defined(USE_PREAD64)
23722
+ { "pread64", (sqlite3_syscall_ptr)pread64, 0 },
23723
+#else
23724
+ { "pread64", (sqlite3_syscall_ptr)0, 0 },
23725
+#endif
23726
+#define osPread64 ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].pCurrent)
23727
+
23728
+ { "write", (sqlite3_syscall_ptr)write, 0 },
23729
+#define osWrite ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent)
23730
+
23731
+#if defined(USE_PREAD) || defined(SQLITE_ENABLE_LOCKING_STYLE)
23732
+ { "pwrite", (sqlite3_syscall_ptr)pwrite, 0 },
23733
+#else
23734
+ { "pwrite", (sqlite3_syscall_ptr)0, 0 },
23735
+#endif
23736
+#define osPwrite ((ssize_t(*)(int,const void*,size_t,off_t))\
23737
+ aSyscall[12].pCurrent)
23738
+
23739
+#if defined(USE_PREAD64)
23740
+ { "pwrite64", (sqlite3_syscall_ptr)pwrite64, 0 },
23741
+#else
23742
+ { "pwrite64", (sqlite3_syscall_ptr)0, 0 },
23743
+#endif
23744
+#define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\
23745
+ aSyscall[13].pCurrent)
23746
+
23747
+ { "fchmod", (sqlite3_syscall_ptr)fchmod, 0 },
23748
+#define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent)
23749
+
23750
+#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
23751
+ { "fallocate", (sqlite3_syscall_ptr)posix_fallocate, 0 },
23752
+#else
23753
+ { "fallocate", (sqlite3_syscall_ptr)0, 0 },
23754
+#endif
23755
+#define osFallocate ((int(*)(int,off_t,off_t)aSyscall[15].pCurrent)
23756
+
23757
+}; /* End of the overrideable system calls */
23758
+
23759
+/*
23760
+** This is the xSetSystemCall() method of sqlite3_vfs for all of the
23761
+** "unix" VFSes. Return SQLITE_OK opon successfully updating the
23762
+** system call pointer, or SQLITE_NOTFOUND if there is no configurable
23763
+** system call named zName.
23764
+*/
23765
+static int unixSetSystemCall(
23766
+ sqlite3_vfs *pNotUsed, /* The VFS pointer. Not used */
23767
+ const char *zName, /* Name of system call to override */
23768
+ sqlite3_syscall_ptr pNewFunc /* Pointer to new system call value */
23769
+){
23770
+ unsigned int i;
23771
+ int rc = SQLITE_NOTFOUND;
23772
+
23773
+ UNUSED_PARAMETER(pNotUsed);
23774
+ if( zName==0 ){
23775
+ /* If no zName is given, restore all system calls to their default
23776
+ ** settings and return NULL
23777
+ */
23778
+ for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
23779
+ if( aSyscall[i].pDefault ){
23780
+ aSyscall[i].pCurrent = aSyscall[i].pDefault;
23781
+ rc = SQLITE_OK;
23782
+ }
23783
+ }
23784
+ }else{
23785
+ /* If zName is specified, operate on only the one system call
23786
+ ** specified.
23787
+ */
23788
+ for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
23789
+ if( strcmp(zName, aSyscall[i].zName)==0 ){
23790
+ if( aSyscall[i].pDefault==0 ){
23791
+ aSyscall[i].pDefault = aSyscall[i].pCurrent;
23792
+ }
23793
+ rc = SQLITE_OK;
23794
+ if( pNewFunc==0 ) pNewFunc = aSyscall[i].pDefault;
23795
+ aSyscall[i].pCurrent = pNewFunc;
23796
+ break;
23797
+ }
23798
+ }
23799
+ }
23800
+ return rc;
23801
+}
23802
+
23803
+/*
23804
+** Return the value of a system call. Return NULL if zName is not a
23805
+** recognized system call name. NULL is also returned if the system call
23806
+** is currently undefined.
23807
+*/
23808
+static sqlite3_syscall_ptr unixGetSystemCall(
23809
+ sqlite3_vfs *pNotUsed,
23810
+ const char *zName
23811
+){
23812
+ unsigned int i;
23813
+
23814
+ UNUSED_PARAMETER(pNotUsed);
23815
+ for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
23816
+ if( strcmp(zName, aSyscall[i].zName)==0 ) return aSyscall[i].pCurrent;
23817
+ }
23818
+ return 0;
23819
+}
23820
+
23821
+/*
23822
+** Return the name of the first system call after zName. If zName==NULL
23823
+** then return the name of the first system call. Return NULL if zName
23824
+** is the last system call or if zName is not the name of a valid
23825
+** system call.
23826
+*/
23827
+static const char *unixNextSystemCall(sqlite3_vfs *p, const char *zName){
23828
+ unsigned int i;
23829
+
23830
+ UNUSED_PARAMETER(p);
23831
+ if( zName==0 ){
23832
+ i = -1;
23833
+ }else{
23834
+ for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0])-1; i++){
23835
+ if( strcmp(zName, aSyscall[0].zName)==0 ) break;
23836
+ }
23837
+ }
23838
+ for(i++; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
23839
+ if( aSyscall[0].pCurrent!=0 ) return aSyscall[0].zName;
23840
+ }
23841
+ return 0;
23842
+}
23843
+
23844
+/*
23845
+** Retry open() calls that fail due to EINTR
23846
+*/
23847
+static int robust_open(const char *z, int f, int m){
23848
+ int rc;
23849
+ do{ rc = osOpen(z,f,m); }while( rc<0 && errno==EINTR );
23850
+ return rc;
23851
+}
2354323852
2354423853
/*
2354523854
** Helper functions to obtain and relinquish the global mutex. The
2354623855
** global mutex is used to protect the unixInodeInfo and
2354723856
** vxworksFileId objects used by this file, all of which may be
@@ -23602,11 +23911,11 @@
2360223911
if( op==F_GETLK ){
2360323912
zOpName = "GETLK";
2360423913
}else if( op==F_SETLK ){
2360523914
zOpName = "SETLK";
2360623915
}else{
23607
- s = fcntl(fd, op, p);
23916
+ s = osFcntl(fd, op, p);
2360823917
sqlite3DebugPrintf("fcntl unknown %d %d %d\n", fd, op, s);
2360923918
return s;
2361023919
}
2361123920
if( p->l_type==F_RDLCK ){
2361223921
zType = "RDLCK";
@@ -23616,19 +23925,19 @@
2361623925
zType = "UNLCK";
2361723926
}else{
2361823927
assert( 0 );
2361923928
}
2362023929
assert( p->l_whence==SEEK_SET );
23621
- s = fcntl(fd, op, p);
23930
+ s = osFcntl(fd, op, p);
2362223931
savedErrno = errno;
2362323932
sqlite3DebugPrintf("fcntl %d %d %s %s %d %d %d %d\n",
2362423933
threadid, fd, zOpName, zType, (int)p->l_start, (int)p->l_len,
2362523934
(int)p->l_pid, s);
2362623935
if( s==(-1) && op==F_SETLK && (p->l_type==F_RDLCK || p->l_type==F_WRLCK) ){
2362723936
struct flock l2;
2362823937
l2 = *p;
23629
- fcntl(fd, F_GETLK, &l2);
23938
+ osFcntl(fd, F_GETLK, &l2);
2363023939
if( l2.l_type==F_RDLCK ){
2363123940
zType = "RDLCK";
2363223941
}else if( l2.l_type==F_WRLCK ){
2363323942
zType = "WRLCK";
2363423943
}else if( l2.l_type==F_UNLCK ){
@@ -23640,27 +23949,22 @@
2364023949
zType, (int)l2.l_start, (int)l2.l_len, (int)l2.l_pid);
2364123950
}
2364223951
errno = savedErrno;
2364323952
return s;
2364423953
}
23645
-#define fcntl lockTrace
23954
+#undef osFcntl
23955
+#define osFcntl lockTrace
2364623956
#endif /* SQLITE_LOCK_TRACE */
23647
-
2364823957
2364923958
/*
2365023959
** Retry ftruncate() calls that fail due to EINTR
2365123960
*/
23652
-#ifdef EINTR
2365323961
static int robust_ftruncate(int h, sqlite3_int64 sz){
2365423962
int rc;
23655
- do{ rc = ftruncate(h,sz); }while( rc<0 && errno==EINTR );
23963
+ do{ rc = osFtruncate(h,sz); }while( rc<0 && errno==EINTR );
2365623964
return rc;
2365723965
}
23658
-#else
23659
-# define robust_ftruncate(a,b) ftruncate(a,b)
23660
-#endif
23661
-
2366223966
2366323967
/*
2366423968
** This routine translates a standard POSIX errno code into something
2366523969
** useful to the clients of the sqlite3 functions. Specifically, it is
2366623970
** intended to translate a variety of "try again" errors into SQLITE_BUSY
@@ -23978,11 +24282,12 @@
2397824282
** object keeps a count of the number of unixFile pointing to it.
2397924283
*/
2398024284
struct unixInodeInfo {
2398124285
struct unixFileId fileId; /* The lookup key */
2398224286
int nShared; /* Number of SHARED locks held */
23983
- int eFileLock; /* One of SHARED_LOCK, RESERVED_LOCK etc. */
24287
+ unsigned char eFileLock; /* One of SHARED_LOCK, RESERVED_LOCK etc. */
24288
+ unsigned char bProcessLock; /* An exclusive process lock is held */
2398424289
int nRef; /* Number of pointers to this structure */
2398524290
unixShmNode *pShmNode; /* Shared memory associated with this inode */
2398624291
int nLock; /* Number of outstanding file locks */
2398724292
UnixUnusedFd *pUnused; /* Unused file descriptors to close */
2398824293
unixInodeInfo *pNext; /* List of all unixInodeInfo objects */
@@ -24083,11 +24388,11 @@
2408324388
** file descriptor might have already been reused by another thread.
2408424389
** So we don't even try to recover from an EINTR. Just log the error
2408524390
** and move on.
2408624391
*/
2408724392
static void robust_close(unixFile *pFile, int h, int lineno){
24088
- if( close(h) ){
24393
+ if( osClose(h) ){
2408924394
unixLogErrorAtLine(SQLITE_IOERR_CLOSE, "close",
2409024395
pFile ? pFile->zPath : 0, lineno);
2409124396
}
2409224397
}
2409324398
@@ -24160,11 +24465,11 @@
2416024465
2416124466
/* Get low-level information about the file that we can used to
2416224467
** create a unique name for the file.
2416324468
*/
2416424469
fd = pFile->h;
24165
- rc = fstat(fd, &statbuf);
24470
+ rc = osFstat(fd, &statbuf);
2416624471
if( rc!=0 ){
2416724472
pFile->lastErrno = errno;
2416824473
#ifdef EOVERFLOW
2416924474
if( pFile->lastErrno==EOVERFLOW ) return SQLITE_NOLFS;
2417024475
#endif
@@ -24181,16 +24486,16 @@
2418124486
** in the header of every SQLite database. In this way, if there
2418224487
** is a race condition such that another thread has already populated
2418324488
** the first page of the database, no damage is done.
2418424489
*/
2418524490
if( statbuf.st_size==0 && (pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS)!=0 ){
24186
- do{ rc = write(fd, "S", 1); }while( rc<0 && errno==EINTR );
24491
+ do{ rc = osWrite(fd, "S", 1); }while( rc<0 && errno==EINTR );
2418724492
if( rc!=1 ){
2418824493
pFile->lastErrno = errno;
2418924494
return SQLITE_IOERR;
2419024495
}
24191
- rc = fstat(fd, &statbuf);
24496
+ rc = osFstat(fd, &statbuf);
2419224497
if( rc!=0 ){
2419324498
pFile->lastErrno = errno;
2419424499
return SQLITE_IOERR;
2419524500
}
2419624501
}
@@ -24249,17 +24554,17 @@
2424924554
}
2425024555
2425124556
/* Otherwise see if some other process holds it.
2425224557
*/
2425324558
#ifndef __DJGPP__
24254
- if( !reserved ){
24559
+ if( !reserved && !pFile->pInode->bProcessLock ){
2425524560
struct flock lock;
2425624561
lock.l_whence = SEEK_SET;
2425724562
lock.l_start = RESERVED_BYTE;
2425824563
lock.l_len = 1;
2425924564
lock.l_type = F_WRLCK;
24260
- if (-1 == fcntl(pFile->h, F_GETLK, &lock)) {
24565
+ if (-1 == osFcntl(pFile->h, F_GETLK, &lock)) {
2426124566
int tErrno = errno;
2426224567
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_CHECKRESERVEDLOCK);
2426324568
pFile->lastErrno = tErrno;
2426424569
} else if( lock.l_type!=F_UNLCK ){
2426524570
reserved = 1;
@@ -24271,10 +24576,54 @@
2427124576
OSTRACE(("TEST WR-LOCK %d %d %d (unix)\n", pFile->h, rc, reserved));
2427224577
2427324578
*pResOut = reserved;
2427424579
return rc;
2427524580
}
24581
+
24582
+/*
24583
+** Attempt to set a system-lock on the file pFile. The lock is
24584
+** described by pLock.
24585
+**
24586
+** If the pFile was opened read/write from unix-excl, then the only lock
24587
+** ever obtained is an exclusive lock, and it is obtained exactly once
24588
+** the first time any lock is attempted. All subsequent system locking
24589
+** operations become no-ops. Locking operations still happen internally,
24590
+** in order to coordinate access between separate database connections
24591
+** within this process, but all of that is handled in memory and the
24592
+** operating system does not participate.
24593
+**
24594
+** This function is a pass-through to fcntl(F_SETLK) if pFile is using
24595
+** any VFS other than "unix-excl" or if pFile is opened on "unix-excl"
24596
+** and is read-only.
24597
+*/
24598
+static int unixFileLock(unixFile *pFile, struct flock *pLock){
24599
+ int rc;
24600
+ unixInodeInfo *pInode = pFile->pInode;
24601
+ assert( unixMutexHeld() );
24602
+ assert( pInode!=0 );
24603
+ if( ((pFile->ctrlFlags & UNIXFILE_EXCL)!=0 || pInode->bProcessLock)
24604
+ && ((pFile->ctrlFlags & UNIXFILE_RDONLY)==0)
24605
+ ){
24606
+ if( pInode->bProcessLock==0 ){
24607
+ struct flock lock;
24608
+ assert( pInode->nLock==0 );
24609
+ lock.l_whence = SEEK_SET;
24610
+ lock.l_start = SHARED_FIRST;
24611
+ lock.l_len = SHARED_SIZE;
24612
+ lock.l_type = F_WRLCK;
24613
+ rc = osFcntl(pFile->h, F_SETLK, &lock);
24614
+ if( rc<0 ) return rc;
24615
+ pInode->bProcessLock = 1;
24616
+ pInode->nLock++;
24617
+ }else{
24618
+ rc = 0;
24619
+ }
24620
+ }else{
24621
+ rc = osFcntl(pFile->h, F_SETLK, pLock);
24622
+ }
24623
+ return rc;
24624
+}
2427624625
2427724626
/*
2427824627
** Lock the file with the lock specified by parameter eFileLock - one
2427924628
** of the following:
2428024629
**
@@ -24408,11 +24757,11 @@
2440824757
if( eFileLock==SHARED_LOCK
2440924758
|| (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock<PENDING_LOCK)
2441024759
){
2441124760
lock.l_type = (eFileLock==SHARED_LOCK?F_RDLCK:F_WRLCK);
2441224761
lock.l_start = PENDING_BYTE;
24413
- s = fcntl(pFile->h, F_SETLK, &lock);
24762
+ s = unixFileLock(pFile, &lock);
2441424763
if( s==(-1) ){
2441524764
tErrno = errno;
2441624765
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
2441724766
if( IS_LOCK_ERROR(rc) ){
2441824767
pFile->lastErrno = tErrno;
@@ -24430,18 +24779,18 @@
2443024779
assert( pInode->eFileLock==0 );
2443124780
2443224781
/* Now get the read-lock */
2443324782
lock.l_start = SHARED_FIRST;
2443424783
lock.l_len = SHARED_SIZE;
24435
- if( (s = fcntl(pFile->h, F_SETLK, &lock))==(-1) ){
24784
+ if( (s = unixFileLock(pFile, &lock))==(-1) ){
2443624785
tErrno = errno;
2443724786
}
2443824787
/* Drop the temporary PENDING lock */
2443924788
lock.l_start = PENDING_BYTE;
2444024789
lock.l_len = 1L;
2444124790
lock.l_type = F_UNLCK;
24442
- if( fcntl(pFile->h, F_SETLK, &lock)!=0 ){
24791
+ if( unixFileLock(pFile, &lock)!=0 ){
2444324792
if( s != -1 ){
2444424793
/* This could happen with a network mount */
2444524794
tErrno = errno;
2444624795
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
2444724796
if( IS_LOCK_ERROR(rc) ){
@@ -24480,11 +24829,11 @@
2448024829
lock.l_len = SHARED_SIZE;
2448124830
break;
2448224831
default:
2448324832
assert(0);
2448424833
}
24485
- s = fcntl(pFile->h, F_SETLK, &lock);
24834
+ s = unixFileLock(pFile, &lock);
2448624835
if( s==(-1) ){
2448724836
tErrno = errno;
2448824837
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
2448924838
if( IS_LOCK_ERROR(rc) ){
2449024839
pFile->lastErrno = tErrno;
@@ -24549,11 +24898,11 @@
2454924898
** the byte range is divided into 2 parts and the first part is unlocked then
2455024899
** set to a read lock, then the other part is simply unlocked. This works
2455124900
** around a bug in BSD NFS lockd (also seen on MacOSX 10.3+) that fails to
2455224901
** remove the write lock on a region when a read lock is set.
2455324902
*/
24554
-static int _posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
24903
+static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
2455524904
unixFile *pFile = (unixFile*)id;
2455624905
unixInodeInfo *pInode;
2455724906
struct flock lock;
2455824907
int rc = SQLITE_OK;
2455924908
int h;
@@ -24605,10 +24954,11 @@
2460524954
** 4: [RRRR.]
2460624955
*/
2460724956
if( eFileLock==SHARED_LOCK ){
2460824957
2460924958
#if !defined(__APPLE__) || !SQLITE_ENABLE_LOCKING_STYLE
24959
+ (void)handleNFSUnlock;
2461024960
assert( handleNFSUnlock==0 );
2461124961
#endif
2461224962
#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
2461324963
if( handleNFSUnlock ){
2461424964
off_t divSize = SHARED_SIZE - 1;
@@ -24615,11 +24965,11 @@
2461524965
2461624966
lock.l_type = F_UNLCK;
2461724967
lock.l_whence = SEEK_SET;
2461824968
lock.l_start = SHARED_FIRST;
2461924969
lock.l_len = divSize;
24620
- if( fcntl(h, F_SETLK, &lock)==(-1) ){
24970
+ if( unixFileLock(pFile,, &lock)==(-1) ){
2462124971
tErrno = errno;
2462224972
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
2462324973
if( IS_LOCK_ERROR(rc) ){
2462424974
pFile->lastErrno = tErrno;
2462524975
}
@@ -24627,11 +24977,11 @@
2462724977
}
2462824978
lock.l_type = F_RDLCK;
2462924979
lock.l_whence = SEEK_SET;
2463024980
lock.l_start = SHARED_FIRST;
2463124981
lock.l_len = divSize;
24632
- if( fcntl(h, F_SETLK, &lock)==(-1) ){
24982
+ if( unixFileLock(pFile, &lock)==(-1) ){
2463324983
tErrno = errno;
2463424984
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);
2463524985
if( IS_LOCK_ERROR(rc) ){
2463624986
pFile->lastErrno = tErrno;
2463724987
}
@@ -24639,11 +24989,11 @@
2463924989
}
2464024990
lock.l_type = F_UNLCK;
2464124991
lock.l_whence = SEEK_SET;
2464224992
lock.l_start = SHARED_FIRST+divSize;
2464324993
lock.l_len = SHARED_SIZE-divSize;
24644
- if( fcntl(h, F_SETLK, &lock)==(-1) ){
24994
+ if( unixFileLock(pFile, &lock)==(-1) ){
2464524995
tErrno = errno;
2464624996
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
2464724997
if( IS_LOCK_ERROR(rc) ){
2464824998
pFile->lastErrno = tErrno;
2464924999
}
@@ -24654,11 +25004,11 @@
2465425004
{
2465525005
lock.l_type = F_RDLCK;
2465625006
lock.l_whence = SEEK_SET;
2465725007
lock.l_start = SHARED_FIRST;
2465825008
lock.l_len = SHARED_SIZE;
24659
- if( fcntl(h, F_SETLK, &lock)==(-1) ){
25009
+ if( unixFileLock(pFile, &lock)==(-1) ){
2466025010
tErrno = errno;
2466125011
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);
2466225012
if( IS_LOCK_ERROR(rc) ){
2466325013
pFile->lastErrno = tErrno;
2466425014
}
@@ -24668,11 +25018,11 @@
2466825018
}
2466925019
lock.l_type = F_UNLCK;
2467025020
lock.l_whence = SEEK_SET;
2467125021
lock.l_start = PENDING_BYTE;
2467225022
lock.l_len = 2L; assert( PENDING_BYTE+1==RESERVED_BYTE );
24673
- if( fcntl(h, F_SETLK, &lock)!=(-1) ){
25023
+ if( unixFileLock(pFile, &lock)!=(-1) ){
2467425024
pInode->eFileLock = SHARED_LOCK;
2467525025
}else{
2467625026
tErrno = errno;
2467725027
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
2467825028
if( IS_LOCK_ERROR(rc) ){
@@ -24692,11 +25042,11 @@
2469225042
lock.l_whence = SEEK_SET;
2469325043
lock.l_start = lock.l_len = 0L;
2469425044
SimulateIOErrorBenign(1);
2469525045
SimulateIOError( h=(-1) )
2469625046
SimulateIOErrorBenign(0);
24697
- if( fcntl(h, F_SETLK, &lock)!=(-1) ){
25047
+ if( unixFileLock(pFile, &lock)!=(-1) ){
2469825048
pInode->eFileLock = NO_LOCK;
2469925049
}else{
2470025050
tErrno = errno;
2470125051
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
2470225052
if( IS_LOCK_ERROR(rc) ){
@@ -24730,11 +25080,11 @@
2473025080
**
2473125081
** If the locking level of the file descriptor is already at or below
2473225082
** the requested locking level, this routine is a no-op.
2473325083
*/
2473425084
static int unixUnlock(sqlite3_file *id, int eFileLock){
24735
- return _posixUnlock(id, eFileLock, 0);
25085
+ return posixUnlock(id, eFileLock, 0);
2473625086
}
2473725087
2473825088
/*
2473925089
** This function performs the parts of the "close file" operation
2474025090
** common to all locking schemes. It closes the directory and file
@@ -24780,10 +25130,12 @@
2478025130
int rc = SQLITE_OK;
2478125131
if( id ){
2478225132
unixFile *pFile = (unixFile *)id;
2478325133
unixUnlock(id, NO_LOCK);
2478425134
unixEnterMutex();
25135
+ assert( pFile->pInode==0 || pFile->pInode->nLock>0
25136
+ || pFile->pInode->bProcessLock==0 );
2478525137
if( pFile->pInode && pFile->pInode->nLock ){
2478625138
/* If there are outstanding locks, do not actually close the file just
2478725139
** yet because that would clear those locks. Instead, add the file
2478825140
** descriptor to pInode->pUnused list. It will be automatically closed
2478925141
** when the last lock is cleared.
@@ -24894,11 +25246,11 @@
2489425246
** holds a lock on the file. No need to check further. */
2489525247
reserved = 1;
2489625248
}else{
2489725249
/* The lock is held if and only if the lockfile exists */
2489825250
const char *zLockFile = (const char*)pFile->lockingContext;
24899
- reserved = access(zLockFile, 0)==0;
25251
+ reserved = osAccess(zLockFile, 0)==0;
2490025252
}
2490125253
OSTRACE(("TEST WR-LOCK %d %d %d (dotlock)\n", pFile->h, rc, reserved));
2490225254
*pResOut = reserved;
2490325255
return rc;
2490425256
}
@@ -24948,11 +25300,11 @@
2494825300
#endif
2494925301
return SQLITE_OK;
2495025302
}
2495125303
2495225304
/* grab an exclusive lock */
24953
- fd = open(zLockFile,O_RDONLY|O_CREAT|O_EXCL,0600);
25305
+ fd = robust_open(zLockFile,O_RDONLY|O_CREAT|O_EXCL,0600);
2495425306
if( fd<0 ){
2495525307
/* failed to open/create the file, someone else may have stolen the lock */
2495625308
int tErrno = errno;
2495725309
if( EEXIST == tErrno ){
2495825310
rc = SQLITE_BUSY;
@@ -25911,11 +26263,11 @@
2591126263
**
2591226264
** If the locking level of the file descriptor is already at or below
2591326265
** the requested locking level, this routine is a no-op.
2591426266
*/
2591526267
static int nfsUnlock(sqlite3_file *id, int eFileLock){
25916
- return _posixUnlock(id, eFileLock, 1);
26268
+ return posixUnlock(id, eFileLock, 1);
2591726269
}
2591826270
2591926271
#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
2592026272
/*
2592126273
** The code above is the NFS lock implementation. The code is specific
@@ -25953,14 +26305,14 @@
2595326305
#if (!defined(USE_PREAD) && !defined(USE_PREAD64))
2595426306
i64 newOffset;
2595526307
#endif
2595626308
TIMER_START;
2595726309
#if defined(USE_PREAD)
25958
- do{ got = pread(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR );
26310
+ do{ got = osPread(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR );
2595926311
SimulateIOError( got = -1 );
2596026312
#elif defined(USE_PREAD64)
25961
- do{ got = pread64(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR );
26313
+ do{ got = osPread64(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR);
2596226314
SimulateIOError( got = -1 );
2596326315
#else
2596426316
newOffset = lseek(id->h, offset, SEEK_SET);
2596526317
SimulateIOError( newOffset-- );
2596626318
if( newOffset!=offset ){
@@ -25969,11 +26321,11 @@
2596926321
}else{
2597026322
((unixFile*)id)->lastErrno = 0;
2597126323
}
2597226324
return -1;
2597326325
}
25974
- do{ got = read(id->h, pBuf, cnt); }while( got<0 && errno==EINTR );
26326
+ do{ got = osRead(id->h, pBuf, cnt); }while( got<0 && errno==EINTR );
2597526327
#endif
2597626328
TIMER_END;
2597726329
if( got<0 ){
2597826330
((unixFile*)id)->lastErrno = errno;
2597926331
}
@@ -26031,13 +26383,13 @@
2603126383
#if (!defined(USE_PREAD) && !defined(USE_PREAD64))
2603226384
i64 newOffset;
2603326385
#endif
2603426386
TIMER_START;
2603526387
#if defined(USE_PREAD)
26036
- do{ got = pwrite(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR );
26388
+ do{ got = osPwrite(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR );
2603726389
#elif defined(USE_PREAD64)
26038
- do{ got = pwrite64(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR );
26390
+ do{ got = osPwrite64(id->h, pBuf, cnt, offset);}while( got<0 && errno==EINTR);
2603926391
#else
2604026392
newOffset = lseek(id->h, offset, SEEK_SET);
2604126393
if( newOffset!=offset ){
2604226394
if( newOffset == -1 ){
2604326395
((unixFile*)id)->lastErrno = errno;
@@ -26044,11 +26396,11 @@
2604426396
}else{
2604526397
((unixFile*)id)->lastErrno = 0;
2604626398
}
2604726399
return -1;
2604826400
}
26049
- do{ got = write(id->h, pBuf, cnt); }while( got<0 && errno==EINTR );
26401
+ do{ got = osWrite(id->h, pBuf, cnt); }while( got<0 && errno==EINTR );
2605026402
#endif
2605126403
TIMER_END;
2605226404
if( got<0 ){
2605326405
((unixFile*)id)->lastErrno = errno;
2605426406
}
@@ -26212,11 +26564,11 @@
2621226564
*/
2621326565
#ifdef SQLITE_NO_SYNC
2621426566
rc = SQLITE_OK;
2621526567
#elif HAVE_FULLFSYNC
2621626568
if( fullSync ){
26217
- rc = fcntl(fd, F_FULLFSYNC, 0);
26569
+ rc = osFcntl(fd, F_FULLFSYNC, 0);
2621826570
}else{
2621926571
rc = 1;
2622026572
}
2622126573
/* If the FULLFSYNC failed, fall back to attempting an fsync().
2622226574
** It shouldn't be possible for fullfsync to fail on the local
@@ -26359,11 +26711,11 @@
2635926711
*/
2636026712
static int unixFileSize(sqlite3_file *id, i64 *pSize){
2636126713
int rc;
2636226714
struct stat buf;
2636326715
assert( id );
26364
- rc = fstat(((unixFile*)id)->h, &buf);
26716
+ rc = osFstat(((unixFile*)id)->h, &buf);
2636526717
SimulateIOError( rc=1 );
2636626718
if( rc!=0 ){
2636726719
((unixFile*)id)->lastErrno = errno;
2636826720
return SQLITE_IOERR_FSTAT;
2636926721
}
@@ -26400,18 +26752,18 @@
2640026752
static int fcntlSizeHint(unixFile *pFile, i64 nByte){
2640126753
if( pFile->szChunk ){
2640226754
i64 nSize; /* Required file size */
2640326755
struct stat buf; /* Used to hold return values of fstat() */
2640426756
26405
- if( fstat(pFile->h, &buf) ) return SQLITE_IOERR_FSTAT;
26757
+ if( osFstat(pFile->h, &buf) ) return SQLITE_IOERR_FSTAT;
2640626758
2640726759
nSize = ((nByte+pFile->szChunk-1) / pFile->szChunk) * pFile->szChunk;
2640826760
if( nSize>(i64)buf.st_size ){
2640926761
#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
2641026762
int rc;
2641126763
do{
26412
- rc = posix_fallocate(pFile-.h, buf.st_size, nSize-buf.st_size;
26764
+ rc = osFallocate(pFile->.h, buf.st_size, nSize-buf.st_size;
2641326765
}while( rc<0 && errno=EINTR );
2641426766
if( rc ) return SQLITE_IOERR_WRITE;
2641526767
#else
2641626768
/* If the OS does not have posix_fallocate(), fake it. First use
2641726769
** ftruncate() to set the file size, then write a single byte to
@@ -26608,19 +26960,21 @@
2660826960
assert( n==1 || lockType!=F_RDLCK );
2660926961
2661026962
/* Locks are within range */
2661126963
assert( n>=1 && n<SQLITE_SHM_NLOCK );
2661226964
26613
- /* Initialize the locking parameters */
26614
- memset(&f, 0, sizeof(f));
26615
- f.l_type = lockType;
26616
- f.l_whence = SEEK_SET;
26617
- f.l_start = ofst;
26618
- f.l_len = n;
26619
-
26620
- rc = fcntl(pShmNode->h, F_SETLK, &f);
26621
- rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY;
26965
+ if( pShmNode->h>=0 ){
26966
+ /* Initialize the locking parameters */
26967
+ memset(&f, 0, sizeof(f));
26968
+ f.l_type = lockType;
26969
+ f.l_whence = SEEK_SET;
26970
+ f.l_start = ofst;
26971
+ f.l_len = n;
26972
+
26973
+ rc = osFcntl(pShmNode->h, F_SETLK, &f);
26974
+ rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY;
26975
+ }
2662226976
2662326977
/* Update the global lock state and do debug tracing */
2662426978
#ifdef SQLITE_DEBUG
2662526979
{ u16 mask;
2662626980
OSTRACE(("SHM-LOCK "));
@@ -26671,11 +27025,15 @@
2667127025
if( p && p->nRef==0 ){
2667227026
int i;
2667327027
assert( p->pInode==pFd->pInode );
2667427028
if( p->mutex ) sqlite3_mutex_free(p->mutex);
2667527029
for(i=0; i<p->nRegion; i++){
26676
- munmap(p->apRegion[i], p->szRegion);
27030
+ if( p->h>=0 ){
27031
+ munmap(p->apRegion[i], p->szRegion);
27032
+ }else{
27033
+ sqlite3_free(p->apRegion[i]);
27034
+ }
2667727035
}
2667827036
sqlite3_free(p->apRegion);
2667927037
if( p->h>=0 ){
2668027038
robust_close(pFd, p->h, __LINE__);
2668127039
p->h = -1;
@@ -26711,10 +27069,16 @@
2671127069
** "unsupported" and may go away in a future SQLite release.
2671227070
**
2671327071
** When opening a new shared-memory file, if no other instances of that
2671427072
** file are currently open, in this process or in other processes, then
2671527073
** the file must be truncated to zero length or have its header cleared.
27074
+**
27075
+** If the original database file (pDbFd) is using the "unix-excl" VFS
27076
+** that means that an exclusive lock is held on the database file and
27077
+** that no other processes are able to read or write the database. In
27078
+** that case, we do not really need shared memory. No shared memory
27079
+** file is created. The shared memory will be simulated with heap memory.
2671627080
*/
2671727081
static int unixOpenSharedMemory(unixFile *pDbFd){
2671827082
struct unixShm *p = 0; /* The connection to be opened */
2671927083
struct unixShmNode *pShmNode; /* The underlying mmapped file */
2672027084
int rc; /* Result code */
@@ -26740,11 +27104,11 @@
2674027104
/* Call fstat() to figure out the permissions on the database file. If
2674127105
** a new *-shm file is created, an attempt will be made to create it
2674227106
** with the same permissions. The actual permissions the file is created
2674327107
** with are subject to the current umask setting.
2674427108
*/
26745
- if( fstat(pDbFd->h, &sStat) ){
27109
+ if( osFstat(pDbFd->h, &sStat) && pInode->bProcessLock==0 ){
2674627110
rc = SQLITE_IOERR_FSTAT;
2674727111
goto shm_open_err;
2674827112
}
2674927113
2675027114
#ifdef SQLITE_SHM_DIRECTORY
@@ -26773,29 +27137,32 @@
2677327137
if( pShmNode->mutex==0 ){
2677427138
rc = SQLITE_NOMEM;
2677527139
goto shm_open_err;
2677627140
}
2677727141
26778
- pShmNode->h = open(zShmFilename, O_RDWR|O_CREAT, (sStat.st_mode & 0777));
26779
- if( pShmNode->h<0 ){
26780
- rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename);
26781
- goto shm_open_err;
26782
- }
26783
-
26784
- /* Check to see if another process is holding the dead-man switch.
26785
- ** If not, truncate the file to zero length.
26786
- */
26787
- rc = SQLITE_OK;
26788
- if( unixShmSystemLock(pShmNode, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){
26789
- if( robust_ftruncate(pShmNode->h, 0) ){
26790
- rc = unixLogError(SQLITE_IOERR_SHMOPEN, "ftruncate", zShmFilename);
26791
- }
26792
- }
26793
- if( rc==SQLITE_OK ){
26794
- rc = unixShmSystemLock(pShmNode, F_RDLCK, UNIX_SHM_DMS, 1);
26795
- }
26796
- if( rc ) goto shm_open_err;
27142
+ if( pInode->bProcessLock==0 ){
27143
+ pShmNode->h = robust_open(zShmFilename, O_RDWR|O_CREAT,
27144
+ (sStat.st_mode & 0777));
27145
+ if( pShmNode->h<0 ){
27146
+ rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename);
27147
+ goto shm_open_err;
27148
+ }
27149
+
27150
+ /* Check to see if another process is holding the dead-man switch.
27151
+ ** If not, truncate the file to zero length.
27152
+ */
27153
+ rc = SQLITE_OK;
27154
+ if( unixShmSystemLock(pShmNode, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){
27155
+ if( robust_ftruncate(pShmNode->h, 0) ){
27156
+ rc = unixLogError(SQLITE_IOERR_SHMOPEN, "ftruncate", zShmFilename);
27157
+ }
27158
+ }
27159
+ if( rc==SQLITE_OK ){
27160
+ rc = unixShmSystemLock(pShmNode, F_RDLCK, UNIX_SHM_DMS, 1);
27161
+ }
27162
+ if( rc ) goto shm_open_err;
27163
+ }
2679727164
}
2679827165
2679927166
/* Make the new connection a child of the unixShmNode */
2680027167
p->pShmNode = pShmNode;
2680127168
#ifdef SQLITE_DEBUG
@@ -26865,38 +27232,44 @@
2686527232
2686627233
p = pDbFd->pShm;
2686727234
pShmNode = p->pShmNode;
2686827235
sqlite3_mutex_enter(pShmNode->mutex);
2686927236
assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
27237
+ assert( pShmNode->pInode==pDbFd->pInode );
27238
+ assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 );
27239
+ assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 );
2687027240
2687127241
if( pShmNode->nRegion<=iRegion ){
2687227242
char **apNew; /* New apRegion[] array */
2687327243
int nByte = (iRegion+1)*szRegion; /* Minimum required file size */
2687427244
struct stat sStat; /* Used by fstat() */
2687527245
2687627246
pShmNode->szRegion = szRegion;
2687727247
26878
- /* The requested region is not mapped into this processes address space.
26879
- ** Check to see if it has been allocated (i.e. if the wal-index file is
26880
- ** large enough to contain the requested region).
26881
- */
26882
- if( fstat(pShmNode->h, &sStat) ){
26883
- rc = SQLITE_IOERR_SHMSIZE;
26884
- goto shmpage_out;
26885
- }
26886
-
26887
- if( sStat.st_size<nByte ){
26888
- /* The requested memory region does not exist. If bExtend is set to
26889
- ** false, exit early. *pp will be set to NULL and SQLITE_OK returned.
26890
- **
26891
- ** Alternatively, if bExtend is true, use ftruncate() to allocate
26892
- ** the requested memory region.
26893
- */
26894
- if( !bExtend ) goto shmpage_out;
26895
- if( robust_ftruncate(pShmNode->h, nByte) ){
26896
- rc = unixLogError(SQLITE_IOERR_SHMSIZE,"ftruncate",pShmNode->zFilename);
26897
- goto shmpage_out;
27248
+ if( pShmNode->h>=0 ){
27249
+ /* The requested region is not mapped into this processes address space.
27250
+ ** Check to see if it has been allocated (i.e. if the wal-index file is
27251
+ ** large enough to contain the requested region).
27252
+ */
27253
+ if( osFstat(pShmNode->h, &sStat) ){
27254
+ rc = SQLITE_IOERR_SHMSIZE;
27255
+ goto shmpage_out;
27256
+ }
27257
+
27258
+ if( sStat.st_size<nByte ){
27259
+ /* The requested memory region does not exist. If bExtend is set to
27260
+ ** false, exit early. *pp will be set to NULL and SQLITE_OK returned.
27261
+ **
27262
+ ** Alternatively, if bExtend is true, use ftruncate() to allocate
27263
+ ** the requested memory region.
27264
+ */
27265
+ if( !bExtend ) goto shmpage_out;
27266
+ if( robust_ftruncate(pShmNode->h, nByte) ){
27267
+ rc = unixLogError(SQLITE_IOERR_SHMSIZE, "ftruncate",
27268
+ pShmNode->zFilename);
27269
+ goto shmpage_out;
27270
+ }
2689827271
}
2689927272
}
2690027273
2690127274
/* Map the requested memory region into this processes address space. */
2690227275
apNew = (char **)sqlite3_realloc(
@@ -26906,16 +27279,26 @@
2690627279
rc = SQLITE_IOERR_NOMEM;
2690727280
goto shmpage_out;
2690827281
}
2690927282
pShmNode->apRegion = apNew;
2691027283
while(pShmNode->nRegion<=iRegion){
26911
- void *pMem = mmap(0, szRegion, PROT_READ|PROT_WRITE,
26912
- MAP_SHARED, pShmNode->h, pShmNode->nRegion*szRegion
26913
- );
26914
- if( pMem==MAP_FAILED ){
26915
- rc = SQLITE_IOERR;
26916
- goto shmpage_out;
27284
+ void *pMem;
27285
+ if( pShmNode->h>=0 ){
27286
+ pMem = mmap(0, szRegion, PROT_READ|PROT_WRITE,
27287
+ MAP_SHARED, pShmNode->h, pShmNode->nRegion*szRegion
27288
+ );
27289
+ if( pMem==MAP_FAILED ){
27290
+ rc = SQLITE_IOERR;
27291
+ goto shmpage_out;
27292
+ }
27293
+ }else{
27294
+ pMem = sqlite3_malloc(szRegion);
27295
+ if( pMem==0 ){
27296
+ rc = SQLITE_NOMEM;
27297
+ goto shmpage_out;
27298
+ }
27299
+ memset(pMem, 0, szRegion);
2691727300
}
2691827301
pShmNode->apRegion[pShmNode->nRegion] = pMem;
2691927302
pShmNode->nRegion++;
2692027303
}
2692127304
}
@@ -26958,10 +27341,12 @@
2695827341
assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED)
2695927342
|| flags==(SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE)
2696027343
|| flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED)
2696127344
|| flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
2696227345
assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
27346
+ assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 );
27347
+ assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 );
2696327348
2696427349
mask = (1<<(ofst+n)) - (1<<ofst);
2696527350
assert( n>1 || mask==(1<<ofst) );
2696627351
sqlite3_mutex_enter(pShmNode->mutex);
2696727352
if( flags & SQLITE_SHM_UNLOCK ){
@@ -27095,11 +27480,11 @@
2709527480
** shared-memory file, too */
2709627481
unixEnterMutex();
2709727482
assert( pShmNode->nRef>0 );
2709827483
pShmNode->nRef--;
2709927484
if( pShmNode->nRef==0 ){
27100
- if( deleteFlag ) unlink(pShmNode->zFilename);
27485
+ if( deleteFlag && pShmNode->h>=0 ) unlink(pShmNode->zFilename);
2710127486
unixShmPurge(pDbFd);
2710227487
}
2710327488
unixLeaveMutex();
2710427489
2710527490
return SQLITE_OK;
@@ -27336,11 +27721,11 @@
2733627721
*/
2733727722
lockInfo.l_len = 1;
2733827723
lockInfo.l_start = 0;
2733927724
lockInfo.l_whence = SEEK_SET;
2734027725
lockInfo.l_type = F_RDLCK;
27341
- if( fcntl(pNew->h, F_GETLK, &lockInfo)!=-1 ) {
27726
+ if( osFcntl(pNew->h, F_GETLK, &lockInfo)!=-1 ) {
2734227727
if( strcmp(fsInfo.f_fstypename, "nfs")==0 ){
2734327728
return &nfsIoMethods;
2734427729
} else {
2734527730
return &posixIoMethods;
2734627731
}
@@ -27378,11 +27763,11 @@
2737827763
*/
2737927764
lockInfo.l_len = 1;
2738027765
lockInfo.l_start = 0;
2738127766
lockInfo.l_whence = SEEK_SET;
2738227767
lockInfo.l_type = F_RDLCK;
27383
- if( fcntl(pNew->h, F_GETLK, &lockInfo)!=-1 ) {
27768
+ if( osFcntl(pNew->h, F_GETLK, &lockInfo)!=-1 ) {
2738427769
return &posixIoMethods;
2738527770
}else{
2738627771
return &semIoMethods;
2738727772
}
2738827773
}
@@ -27412,11 +27797,12 @@
2741227797
int h, /* Open file descriptor of file being opened */
2741327798
int dirfd, /* Directory file descriptor */
2741427799
sqlite3_file *pId, /* Write to the unixFile structure here */
2741527800
const char *zFilename, /* Name of the file being opened */
2741627801
int noLock, /* Omit locking if true */
27417
- int isDelete /* Delete on close if true */
27802
+ int isDelete, /* Delete on close if true */
27803
+ int isReadOnly /* True if the file is opened read-only */
2741827804
){
2741927805
const sqlite3_io_methods *pLockingStyle;
2742027806
unixFile *pNew = (unixFile *)pId;
2742127807
int rc = SQLITE_OK;
2742227808
@@ -27439,12 +27825,19 @@
2743927825
#endif
2744027826
2744127827
OSTRACE(("OPEN %-3d %s\n", h, zFilename));
2744227828
pNew->h = h;
2744327829
pNew->dirfd = dirfd;
27444
- pNew->fileFlags = 0;
2744527830
pNew->zPath = zFilename;
27831
+ if( memcmp(pVfs->zName,"unix-excl",10)==0 ){
27832
+ pNew->ctrlFlags = UNIXFILE_EXCL;
27833
+ }else{
27834
+ pNew->ctrlFlags = 0;
27835
+ }
27836
+ if( isReadOnly ){
27837
+ pNew->ctrlFlags |= UNIXFILE_RDONLY;
27838
+ }
2744627839
2744727840
#if OS_VXWORKS
2744827841
pNew->pId = vxworksFindFileId(zFilename);
2744927842
if( pNew->pId==0 ){
2745027843
noLock = 1;
@@ -27601,14 +27994,14 @@
2760127994
2760227995
sqlite3_snprintf(MAX_PATHNAME, zDirname, "%s", zFilename);
2760327996
for(ii=(int)strlen(zDirname); ii>1 && zDirname[ii]!='/'; ii--);
2760427997
if( ii>0 ){
2760527998
zDirname[ii] = '\0';
27606
- fd = open(zDirname, O_RDONLY|O_BINARY, 0);
27999
+ fd = robust_open(zDirname, O_RDONLY|O_BINARY, 0);
2760728000
if( fd>=0 ){
2760828001
#ifdef FD_CLOEXEC
27609
- fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
28002
+ osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
2761028003
#endif
2761128004
OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname));
2761228005
}
2761328006
}
2761428007
*pFd = fd;
@@ -27634,13 +28027,13 @@
2763428027
2763528028
azDirs[0] = sqlite3_temp_directory;
2763628029
if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR");
2763728030
for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); zDir=azDirs[i++]){
2763828031
if( zDir==0 ) continue;
27639
- if( stat(zDir, &buf) ) continue;
28032
+ if( osStat(zDir, &buf) ) continue;
2764028033
if( !S_ISDIR(buf.st_mode) ) continue;
27641
- if( access(zDir, 07) ) continue;
28034
+ if( osAccess(zDir, 07) ) continue;
2764228035
break;
2764328036
}
2764428037
return zDir;
2764528038
}
2764628039
@@ -27679,11 +28072,11 @@
2767928072
sqlite3_randomness(15, &zBuf[j]);
2768028073
for(i=0; i<15; i++, j++){
2768128074
zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
2768228075
}
2768328076
zBuf[j] = 0;
27684
- }while( access(zBuf,0)==0 );
28077
+ }while( osAccess(zBuf,0)==0 );
2768528078
return SQLITE_OK;
2768628079
}
2768728080
2768828081
#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
2768928082
/*
@@ -27940,19 +28333,20 @@
2794028333
if( rc!=SQLITE_OK ){
2794128334
assert( !p->pUnused );
2794228335
assert( eType==SQLITE_OPEN_WAL || eType==SQLITE_OPEN_MAIN_JOURNAL );
2794328336
return rc;
2794428337
}
27945
- fd = open(zName, openFlags, openMode);
28338
+ fd = robust_open(zName, openFlags, openMode);
2794628339
OSTRACE(("OPENX %-3d %s 0%o\n", fd, zName, openFlags));
2794728340
if( fd<0 && errno!=EISDIR && isReadWrite && !isExclusive ){
2794828341
/* Failed to open the file for read/write access. Try read-only. */
2794928342
flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
2795028343
openFlags &= ~(O_RDWR|O_CREAT);
2795128344
flags |= SQLITE_OPEN_READONLY;
2795228345
openFlags |= O_RDONLY;
27953
- fd = open(zName, openFlags, openMode);
28346
+ isReadonly = 1;
28347
+ fd = robust_open(zName, openFlags, openMode);
2795428348
}
2795528349
if( fd<0 ){
2795628350
rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
2795728351
goto open_finished;
2795828352
}
@@ -27992,11 +28386,11 @@
2799228386
goto open_finished;
2799328387
}
2799428388
}
2799528389
2799628390
#ifdef FD_CLOEXEC
27997
- fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
28391
+ osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
2799828392
#endif
2799928393
2800028394
noLock = eType!=SQLITE_OPEN_MAIN_DB;
2800128395
2800228396
@@ -28044,11 +28438,12 @@
2804428438
goto open_finished;
2804528439
}
2804628440
useProxy = !(fsInfo.f_flags&MNT_LOCAL);
2804728441
}
2804828442
if( useProxy ){
28049
- rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock, isDelete);
28443
+ rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock,
28444
+ isDelete, isReadonly);
2805028445
if( rc==SQLITE_OK ){
2805128446
rc = proxyTransformUnixFile((unixFile*)pFile, ":auto:");
2805228447
if( rc!=SQLITE_OK ){
2805328448
/* Use unixClose to clean up the resources added in fillInUnixFile
2805428449
** and clear all the structure's references. Specifically,
@@ -28061,11 +28456,12 @@
2806128456
goto open_finished;
2806228457
}
2806328458
}
2806428459
#endif
2806528460
28066
- rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock, isDelete);
28461
+ rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock,
28462
+ isDelete, isReadonly);
2806728463
open_finished:
2806828464
if( rc!=SQLITE_OK ){
2806928465
sqlite3_free(p->pUnused);
2807028466
}
2807128467
return rc;
@@ -28138,11 +28534,11 @@
2813828534
break;
2813928535
2814028536
default:
2814128537
assert(!"Invalid flags argument");
2814228538
}
28143
- *pResOut = (access(zPath, amode)==0);
28539
+ *pResOut = (osAccess(zPath, amode)==0);
2814428540
if( flags==SQLITE_ACCESS_EXISTS && *pResOut ){
2814528541
struct stat buf;
2814628542
if( 0==stat(zPath, &buf) && buf.st_size==0 ){
2814728543
*pResOut = 0;
2814828544
}
@@ -28180,11 +28576,11 @@
2818028576
zOut[nOut-1] = '\0';
2818128577
if( zPath[0]=='/' ){
2818228578
sqlite3_snprintf(nOut, zOut, "%s", zPath);
2818328579
}else{
2818428580
int nCwd;
28185
- if( getcwd(zOut, nOut-1)==0 ){
28581
+ if( osGetcwd(zOut, nOut-1)==0 ){
2818628582
return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath);
2818728583
}
2818828584
nCwd = (int)strlen(zOut);
2818928585
sqlite3_snprintf(nOut-nCwd, &zOut[nCwd], "/%s", zPath);
2819028586
}
@@ -28275,21 +28671,21 @@
2827528671
*/
2827628672
memset(zBuf, 0, nBuf);
2827728673
#if !defined(SQLITE_TEST)
2827828674
{
2827928675
int pid, fd;
28280
- fd = open("/dev/urandom", O_RDONLY);
28676
+ fd = robust_open("/dev/urandom", O_RDONLY, 0);
2828128677
if( fd<0 ){
2828228678
time_t t;
2828328679
time(&t);
2828428680
memcpy(zBuf, &t, sizeof(t));
2828528681
pid = getpid();
2828628682
memcpy(&zBuf[sizeof(t)], &pid, sizeof(pid));
2828728683
assert( sizeof(t)+sizeof(pid)<=(size_t)nBuf );
2828828684
nBuf = sizeof(t) + sizeof(pid);
2828928685
}else{
28290
- do{ nBuf = read(fd, zBuf, nBuf); }while( nBuf<0 && errno==EINTR );
28686
+ do{ nBuf = osRead(fd, zBuf, nBuf); }while( nBuf<0 && errno==EINTR );
2829128687
robust_close(0, fd, __LINE__);
2829228688
}
2829328689
}
2829428690
#endif
2829528691
return nBuf;
@@ -28684,21 +29080,21 @@
2868429080
if( !pUnused ){
2868529081
return SQLITE_NOMEM;
2868629082
}
2868729083
}
2868829084
if( fd<0 ){
28689
- fd = open(path, openFlags, SQLITE_DEFAULT_FILE_PERMISSIONS);
29085
+ fd = robust_open(path, openFlags, SQLITE_DEFAULT_FILE_PERMISSIONS);
2869029086
terrno = errno;
2869129087
if( fd<0 && errno==ENOENT && islockfile ){
2869229088
if( proxyCreateLockPath(path) == SQLITE_OK ){
28693
- fd = open(path, openFlags, SQLITE_DEFAULT_FILE_PERMISSIONS);
29089
+ fd = robust_open(path, openFlags, SQLITE_DEFAULT_FILE_PERMISSIONS);
2869429090
}
2869529091
}
2869629092
}
2869729093
if( fd<0 ){
2869829094
openFlags = O_RDONLY;
28699
- fd = open(path, openFlags, SQLITE_DEFAULT_FILE_PERMISSIONS);
29095
+ fd = robust_open(path, openFlags, SQLITE_DEFAULT_FILE_PERMISSIONS);
2870029096
terrno = errno;
2870129097
}
2870229098
if( fd<0 ){
2870329099
if( islockfile ){
2870429100
return SQLITE_BUSY;
@@ -28723,11 +29119,11 @@
2872329119
dummyVfs.pAppData = (void*)&autolockIoFinder;
2872429120
pUnused->fd = fd;
2872529121
pUnused->flags = openFlags;
2872629122
pNew->pUnused = pUnused;
2872729123
28728
- rc = fillInUnixFile(&dummyVfs, fd, dirfd, (sqlite3_file*)pNew, path, 0, 0);
29124
+ rc = fillInUnixFile(&dummyVfs, fd, dirfd, (sqlite3_file*)pNew, path, 0, 0, 0);
2872929125
if( rc==SQLITE_OK ){
2873029126
*ppFile = pNew;
2873129127
return SQLITE_OK;
2873229128
}
2873329129
end_create_proxy:
@@ -28808,22 +29204,23 @@
2880829204
(strlcpy(&tPath[pathLen-5], "break", 6) != 5) ){
2880929205
sqlite3_snprintf(sizeof(errmsg),errmsg,"path error (len %d)",(int)pathLen);
2881029206
goto end_breaklock;
2881129207
}
2881229208
/* read the conch content */
28813
- readLen = pread(conchFile->h, buf, PROXY_MAXCONCHLEN, 0);
29209
+ readLen = osPread(conchFile->h, buf, PROXY_MAXCONCHLEN, 0);
2881429210
if( readLen<PROXY_PATHINDEX ){
2881529211
sqlite3_snprintf(sizeof(errmsg),errmsg,"read error (len %d)",(int)readLen);
2881629212
goto end_breaklock;
2881729213
}
2881829214
/* write it out to the temporary break file */
28819
- fd = open(tPath, (O_RDWR|O_CREAT|O_EXCL), SQLITE_DEFAULT_FILE_PERMISSIONS);
29215
+ fd = robust_open(tPath, (O_RDWR|O_CREAT|O_EXCL),
29216
+ SQLITE_DEFAULT_FILE_PERMISSIONS);
2882029217
if( fd<0 ){
2882129218
sqlite3_snprintf(sizeof(errmsg), errmsg, "create failed (%d)", errno);
2882229219
goto end_breaklock;
2882329220
}
28824
- if( pwrite(fd, buf, readLen, 0) != (ssize_t)readLen ){
29221
+ if( osPwrite(fd, buf, readLen, 0) != (ssize_t)readLen ){
2882529222
sqlite3_snprintf(sizeof(errmsg), errmsg, "write failed (%d)", errno);
2882629223
goto end_breaklock;
2882729224
}
2882829225
if( rename(tPath, cPath) ){
2882929226
sqlite3_snprintf(sizeof(errmsg), errmsg, "rename failed (%d)", errno);
@@ -28865,11 +29262,11 @@
2886529262
* 2nd try: fail if the mod time changed or host id is different, wait
2886629263
* 10 sec and try again
2886729264
* 3rd try: break the lock unless the mod time has changed.
2886829265
*/
2886929266
struct stat buf;
28870
- if( fstat(conchFile->h, &buf) ){
29267
+ if( osFstat(conchFile->h, &buf) ){
2887129268
pFile->lastErrno = errno;
2887229269
return SQLITE_IOERR_LOCK;
2887329270
}
2887429271
2887529272
if( nTries==1 ){
@@ -28884,11 +29281,11 @@
2888429281
return SQLITE_BUSY;
2888529282
}
2888629283
2888729284
if( nTries==2 ){
2888829285
char tBuf[PROXY_MAXCONCHLEN];
28889
- int len = pread(conchFile->h, tBuf, PROXY_MAXCONCHLEN, 0);
29286
+ int len = osPread(conchFile->h, tBuf, PROXY_MAXCONCHLEN, 0);
2889029287
if( len<0 ){
2889129288
pFile->lastErrno = errno;
2889229289
return SQLITE_IOERR_LOCK;
2889329290
}
2889429291
if( len>PROXY_PATHINDEX && tBuf[0]==(char)PROXY_CONCHVERSION){
@@ -29054,20 +29451,20 @@
2905429451
/* If we created a new conch file (not just updated the contents of a
2905529452
** valid conch file), try to match the permissions of the database
2905629453
*/
2905729454
if( rc==SQLITE_OK && createConch ){
2905829455
struct stat buf;
29059
- int err = fstat(pFile->h, &buf);
29456
+ int err = osFstat(pFile->h, &buf);
2906029457
if( err==0 ){
2906129458
mode_t cmode = buf.st_mode&(S_IRUSR|S_IWUSR | S_IRGRP|S_IWGRP |
2906229459
S_IROTH|S_IWOTH);
2906329460
/* try to match the database file R/W permissions, ignore failure */
2906429461
#ifndef SQLITE_PROXY_DEBUG
29065
- fchmod(conchFile->h, cmode);
29462
+ osFchmod(conchFile->h, cmode);
2906629463
#else
2906729464
do{
29068
- rc = fchmod(conchFile->h, cmode);
29465
+ rc = osFchmod(conchFile->h, cmode);
2906929466
}while( rc==(-1) && errno==EINTR );
2907029467
if( rc!=0 ){
2907129468
int code = errno;
2907229469
fprintf(stderr, "fchmod %o FAILED with %d %s\n",
2907329470
cmode, code, strerror(code));
@@ -29089,11 +29486,11 @@
2908929486
if( rc==SQLITE_OK && pFile->openFlags ){
2909029487
if( pFile->h>=0 ){
2909129488
robust_close(pFile, pFile->h, __LINE__);
2909229489
}
2909329490
pFile->h = -1;
29094
- int fd = open(pCtx->dbPath, pFile->openFlags,
29491
+ int fd = robust_open(pCtx->dbPath, pFile->openFlags,
2909529492
SQLITE_DEFAULT_FILE_PERMISSIONS);
2909629493
OSTRACE(("TRANSPROXY: OPEN %d\n", fd));
2909729494
if( fd>=0 ){
2909829495
pFile->h = fd;
2909929496
}else{
@@ -29315,11 +29712,11 @@
2931529712
*/
2931629713
struct statfs fsInfo;
2931729714
struct stat conchInfo;
2931829715
int goLockless = 0;
2931929716
29320
- if( stat(pCtx->conchFilePath, &conchInfo) == -1 ) {
29717
+ if( osStat(pCtx->conchFilePath, &conchInfo) == -1 ) {
2932129718
int err = errno;
2932229719
if( (err==ENOENT) && (statfs(dbPath, &fsInfo) != -1) ){
2932329720
goLockless = (fsInfo.f_flags&MNT_RDONLY) == MNT_RDONLY;
2932429721
}
2932529722
}
@@ -29600,11 +29997,11 @@
2960029997
** more than that; it looks at the filesystem type that hosts the
2960129998
** database file and tries to choose an locking method appropriate for
2960229999
** that filesystem time.
2960330000
*/
2960430001
#define UNIXVFS(VFSNAME, FINDER) { \
29605
- 2, /* iVersion */ \
30002
+ 3, /* iVersion */ \
2960630003
sizeof(unixFile), /* szOsFile */ \
2960730004
MAX_PATHNAME, /* mxPathname */ \
2960830005
0, /* pNext */ \
2960930006
VFSNAME, /* zName */ \
2961030007
(void*)&FINDER, /* pAppData */ \
@@ -29619,10 +30016,13 @@
2961930016
unixRandomness, /* xRandomness */ \
2962030017
unixSleep, /* xSleep */ \
2962130018
unixCurrentTime, /* xCurrentTime */ \
2962230019
unixGetLastError, /* xGetLastError */ \
2962330020
unixCurrentTimeInt64, /* xCurrentTimeInt64 */ \
30021
+ unixSetSystemCall, /* xSetSystemCall */ \
30022
+ unixGetSystemCall, /* xGetSystemCall */ \
30023
+ unixNextSystemCall, /* xNextSystemCall */ \
2962430024
}
2962530025
2962630026
/*
2962730027
** All default VFSes for unix are contained in the following array.
2962830028
**
@@ -29636,10 +30036,11 @@
2963630036
#else
2963730037
UNIXVFS("unix", posixIoFinder ),
2963830038
#endif
2963930039
UNIXVFS("unix-none", nolockIoFinder ),
2964030040
UNIXVFS("unix-dotfile", dotlockIoFinder ),
30041
+ UNIXVFS("unix-excl", posixIoFinder ),
2964130042
#if OS_VXWORKS
2964230043
UNIXVFS("unix-namedsem", semIoFinder ),
2964330044
#endif
2964430045
#if SQLITE_ENABLE_LOCKING_STYLE
2964530046
UNIXVFS("unix-posix", posixIoFinder ),
@@ -32626,11 +33027,11 @@
3262633027
/*
3262733028
** Initialize and deinitialize the operating system interface.
3262833029
*/
3262933030
SQLITE_API int sqlite3_os_init(void){
3263033031
static sqlite3_vfs winVfs = {
32631
- 2, /* iVersion */
33032
+ 3, /* iVersion */
3263233033
sizeof(winFile), /* szOsFile */
3263333034
MAX_PATH, /* mxPathname */
3263433035
0, /* pNext */
3263533036
"win32", /* zName */
3263633037
0, /* pAppData */
@@ -32645,10 +33046,13 @@
3264533046
winRandomness, /* xRandomness */
3264633047
winSleep, /* xSleep */
3264733048
winCurrentTime, /* xCurrentTime */
3264833049
winGetLastError, /* xGetLastError */
3264933050
winCurrentTimeInt64, /* xCurrentTimeInt64 */
33051
+ 0, /* xSetSystemCall */
33052
+ 0, /* xGetSystemCall */
33053
+ 0, /* xNextSystemCall */
3265033054
};
3265133055
3265233056
#ifndef SQLITE_OMIT_WAL
3265333057
/* get memory map allocation granularity */
3265433058
memset(&winSysInfo, 0, sizeof(SYSTEM_INFO));
@@ -50782,15 +51186,13 @@
5078251186
}
5078351187
if( nearby>0 ){
5078451188
u32 i;
5078551189
int dist;
5078651190
closest = 0;
50787
- dist = get4byte(&aData[8]) - nearby;
50788
- if( dist<0 ) dist = -dist;
51191
+ dist = sqlite3AbsInt32(get4byte(&aData[8]) - nearby);
5078951192
for(i=1; i<k; i++){
50790
- int d2 = get4byte(&aData[8+i*4]) - nearby;
50791
- if( d2<0 ) d2 = -d2;
51193
+ int d2 = sqlite3AbsInt32(get4byte(&aData[8+i*4]) - nearby);
5079251194
if( d2<dist ){
5079351195
closest = i;
5079451196
dist = d2;
5079551197
}
5079651198
}
@@ -55777,13 +56179,18 @@
5577756179
}
5577856180
}else if( op==TK_UMINUS ) {
5577956181
/* This branch happens for multiple negative signs. Ex: -(-5) */
5578056182
if( SQLITE_OK==sqlite3ValueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal) ){
5578156183
sqlite3VdbeMemNumerify(pVal);
55782
- pVal->u.i = -1 * pVal->u.i;
55783
- /* (double)-1 In case of SQLITE_OMIT_FLOATING_POINT... */
55784
- pVal->r = (double)-1 * pVal->r;
56184
+ if( pVal->u.i==SMALLEST_INT64 ){
56185
+ pVal->flags &= MEM_Int;
56186
+ pVal->flags |= MEM_Real;
56187
+ pVal->r = (double)LARGEST_INT64;
56188
+ }else{
56189
+ pVal->u.i = -pVal->u.i;
56190
+ }
56191
+ pVal->r = -pVal->r;
5578556192
sqlite3ValueApplyAffinity(pVal, affinity, enc);
5578656193
}
5578756194
}else if( op==TK_NULL ){
5578856195
pVal = sqlite3ValueNew(db);
5578956196
if( pVal==0 ) goto no_mem;
@@ -56805,12 +57212,12 @@
5680557212
** will be used so that it can acquire mutexes on them all in sorted
5680657213
** order (via sqlite3VdbeMutexArrayEnter(). Mutexes are acquired
5680757214
** in order (and released in reverse order) to avoid deadlocks.
5680857215
*/
5680957216
SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe *p, int i){
56810
- int mask;
56811
- assert( i>=0 && i<p->db->nDb && i<sizeof(u32)*8 );
57217
+ tAttachMask mask;
57218
+ assert( i>=0 && i<p->db->nDb && i<sizeof(tAttachMask)*8 );
5681257219
assert( i<(int)sizeof(p->btreeMask)*8 );
5681357220
mask = ((u32)1)<<i;
5681457221
if( (p->btreeMask & mask)==0 ){
5681557222
p->btreeMask |= mask;
5681657223
sqlite3BtreeMutexArrayInsert(&p->aMutex, p->db->aDb[i].pBt);
@@ -61309,10 +61716,11 @@
6130961716
struct OP_SetCookie_stack_vars {
6131061717
Db *pDb;
6131161718
} au;
6131261719
struct OP_VerifyCookie_stack_vars {
6131361720
int iMeta;
61721
+ int iGen;
6131461722
Btree *pBt;
6131561723
} av;
6131661724
struct OP_OpenWrite_stack_vars {
6131761725
int nField;
6131861726
KeyInfo *pKeyInfo;
@@ -63931,14 +64339,16 @@
6393164339
p->expired = 0;
6393264340
}
6393364341
break;
6393464342
}
6393564343
63936
-/* Opcode: VerifyCookie P1 P2 *
64344
+/* Opcode: VerifyCookie P1 P2 P3 * *
6393764345
**
6393864346
** Check the value of global database parameter number 0 (the
63939
-** schema version) and make sure it is equal to P2.
64347
+** schema version) and make sure it is equal to P2 and that the
64348
+** generation counter on the local schema parse equals P3.
64349
+**
6394064350
** P1 is the database number which is 0 for the main database file
6394164351
** and 1 for the file holding temporary tables and some higher number
6394264352
** for auxiliary databases.
6394364353
**
6394464354
** The cookie changes its value whenever the database schema changes.
@@ -63950,21 +64360,24 @@
6395064360
** invoked.
6395164361
*/
6395264362
case OP_VerifyCookie: {
6395364363
#if 0 /* local variables moved into u.av */
6395464364
int iMeta;
64365
+ int iGen;
6395564366
Btree *pBt;
6395664367
#endif /* local variables moved into u.av */
64368
+
6395764369
assert( pOp->p1>=0 && pOp->p1<db->nDb );
6395864370
assert( (p->btreeMask & (1<<pOp->p1))!=0 );
6395964371
u.av.pBt = db->aDb[pOp->p1].pBt;
6396064372
if( u.av.pBt ){
6396164373
sqlite3BtreeGetMeta(u.av.pBt, BTREE_SCHEMA_VERSION, (u32 *)&u.av.iMeta);
64374
+ u.av.iGen = db->aDb[pOp->p1].pSchema->iGeneration;
6396264375
}else{
6396364376
u.av.iMeta = 0;
6396464377
}
63965
- if( u.av.iMeta!=pOp->p2 ){
64378
+ if( u.av.iMeta!=pOp->p2 || u.av.iGen!=pOp->p3 ){
6396664379
sqlite3DbFree(db, p->zErrMsg);
6396764380
p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed");
6396864381
/* If the schema-cookie from the database file matches the cookie
6396964382
** stored with the in-memory representation of the schema, do
6397064383
** not reload the schema from the database file.
@@ -65694,18 +66107,14 @@
6569466107
rc = sqlite3BtreeCreateTable(u.bt.pDb->pBt, &u.bt.pgno, u.bt.flags);
6569566108
pOut->u.i = u.bt.pgno;
6569666109
break;
6569766110
}
6569866111
65699
-/* Opcode: ParseSchema P1 P2 * P4 *
66112
+/* Opcode: ParseSchema P1 * * P4 *
6570066113
**
6570166114
** Read and parse all entries from the SQLITE_MASTER table of database P1
65702
-** that match the WHERE clause P4. P2 is the "force" flag. Always do
65703
-** the parsing if P2 is true. If P2 is false, then this routine is a
65704
-** no-op if the schema is not currently loaded. In other words, if P2
65705
-** is false, the SQLITE_MASTER table is only parsed if the rest of the
65706
-** schema is already loaded into the symbol table.
66115
+** that match the WHERE clause P4.
6570766116
**
6570866117
** This opcode invokes the parser to create a new virtual machine,
6570966118
** then runs the new virtual machine. It is thus a re-entrant opcode.
6571066119
*/
6571166120
case OP_ParseSchema: {
@@ -65717,18 +66126,11 @@
6571766126
#endif /* local variables moved into u.bu */
6571866127
6571966128
u.bu.iDb = pOp->p1;
6572066129
assert( u.bu.iDb>=0 && u.bu.iDb<db->nDb );
6572166130
65722
- /* If pOp->p2 is 0, then this opcode is being executed to read a
65723
- ** single row, for example the row corresponding to a new index
65724
- ** created by this VDBE, from the sqlite_master table. It only
65725
- ** does this if the corresponding in-memory schema is currently
65726
- ** loaded. Otherwise, the new index definition can be loaded along
65727
- ** with the rest of the schema when it is required.
65728
- **
65729
- ** Although the mutex on the BtShared object that corresponds to
66131
+ /* Although the mutex on the BtShared object that corresponds to
6573066132
** database u.bu.iDb (the database containing the sqlite_master table
6573166133
** read by this instruction) is currently held, it is necessary to
6573266134
** obtain the mutexes on all attached databases before checking if
6573366135
** the schema of u.bu.iDb is loaded. This is because, at the start of
6573466136
** the sqlite3_exec() call below, SQLite will invoke
@@ -65740,11 +66142,11 @@
6574066142
** can result in a "no such table: sqlite_master" or "malformed
6574166143
** database schema" error being returned to the user.
6574266144
*/
6574366145
assert( sqlite3BtreeHoldsMutex(db->aDb[u.bu.iDb].pBt) );
6574466146
sqlite3BtreeEnterAll(db);
65745
- if( pOp->p2 || DbHasProperty(db, u.bu.iDb, DB_SchemaLoaded) ){
66147
+ if( ALWAYS(DbHasProperty(db, u.bu.iDb, DB_SchemaLoaded)) ){
6574666148
u.bu.zMaster = SCHEMA_TABLE(u.bu.iDb);
6574766149
u.bu.initData.db = db;
6574866150
u.bu.initData.iDb = pOp->p1;
6574966151
u.bu.initData.pzErrMsg = &p->zErrMsg;
6575066152
u.bu.zSql = sqlite3MPrintf(db,
@@ -67395,10 +67797,11 @@
6739567797
sqlite3VdbeChangeP2(v, 0, flags);
6739667798
6739767799
/* Configure the OP_VerifyCookie */
6739867800
sqlite3VdbeChangeP1(v, 1, iDb);
6739967801
sqlite3VdbeChangeP2(v, 1, pTab->pSchema->schema_cookie);
67802
+ sqlite3VdbeChangeP3(v, 1, pTab->pSchema->iGeneration);
6740067803
6740167804
/* Make sure a mutex is held on the table to be accessed */
6740267805
sqlite3VdbeUsesBtree(v, iDb);
6740367806
6740467807
/* Configure the OP_TableLock instruction */
@@ -69826,10 +70229,11 @@
6982670229
6982770230
if( pToken ){
6982870231
if( op!=TK_INTEGER || pToken->z==0
6982970232
|| sqlite3GetInt32(pToken->z, &iValue)==0 ){
6983070233
nExtra = pToken->n+1;
70234
+ assert( iValue>=0 );
6983170235
}
6983270236
}
6983370237
pNew = sqlite3DbMallocZero(db, sizeof(Expr)+nExtra);
6983470238
if( pNew ){
6983570239
pNew->op = (u8)op;
@@ -70051,10 +70455,12 @@
7005170455
/*
7005270456
** Recursively delete an expression tree.
7005370457
*/
7005470458
SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3 *db, Expr *p){
7005570459
if( p==0 ) return;
70460
+ /* Sanity check: Assert that the IntValue is non-negative if it exists */
70461
+ assert( !ExprHasProperty(p, EP_IntValue) || p->u.iValue>=0 );
7005670462
if( !ExprHasAnyProperty(p, EP_TokenOnly) ){
7005770463
sqlite3ExprDelete(db, p->pLeft);
7005870464
sqlite3ExprDelete(db, p->pRight);
7005970465
if( !ExprHasProperty(p, EP_Reduced) && (p->flags2 & EP2_MallocedToken)!=0 ){
7006070466
sqlite3DbFree(db, p->u.zToken);
@@ -70660,17 +71066,10 @@
7066071066
}
7066171067
break;
7066271068
}
7066371069
default: break;
7066471070
}
70665
- if( rc ){
70666
- assert( ExprHasAnyProperty(p, EP_Reduced|EP_TokenOnly)
70667
- || (p->flags2 & EP2_MallocedToken)==0 );
70668
- p->op = TK_INTEGER;
70669
- p->flags |= EP_IntValue;
70670
- p->u.iValue = *pValue;
70671
- }
7067271071
return rc;
7067371072
}
7067471073
7067571074
/*
7067671075
** Return FALSE if there is no chance that the expression can be NULL.
@@ -71391,10 +71790,11 @@
7139171790
*/
7139271791
static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
7139371792
Vdbe *v = pParse->pVdbe;
7139471793
if( pExpr->flags & EP_IntValue ){
7139571794
int i = pExpr->u.iValue;
71795
+ assert( i>=0 );
7139671796
if( negFlag ) i = -i;
7139771797
sqlite3VdbeAddOp2(v, OP_Integer, i, iMem);
7139871798
}else{
7139971799
int c;
7140071800
i64 value;
@@ -75655,19 +76055,21 @@
7565576055
** set for each database that is used. Generate code to start a
7565676056
** transaction on each used database and to verify the schema cookie
7565776057
** on each used database.
7565876058
*/
7565976059
if( pParse->cookieGoto>0 ){
75660
- u32 mask;
76060
+ tAttachMask mask;
7566176061
int iDb;
7566276062
sqlite3VdbeJumpHere(v, pParse->cookieGoto-1);
7566376063
for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){
7566476064
if( (mask & pParse->cookieMask)==0 ) continue;
7566576065
sqlite3VdbeUsesBtree(v, iDb);
7566676066
sqlite3VdbeAddOp2(v,OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
7566776067
if( db->init.busy==0 ){
75668
- sqlite3VdbeAddOp2(v,OP_VerifyCookie, iDb, pParse->cookieValue[iDb]);
76068
+ sqlite3VdbeAddOp3(v, OP_VerifyCookie,
76069
+ iDb, pParse->cookieValue[iDb],
76070
+ db->aDb[iDb].pSchema->iGeneration);
7566976071
}
7567076072
}
7567176073
#ifndef SQLITE_OMIT_VIRTUALTABLE
7567276074
{
7567376075
int i;
@@ -75873,11 +76275,11 @@
7587376275
int len;
7587476276
Hash *pHash = &db->aDb[iDb].pSchema->idxHash;
7587576277
7587676278
len = sqlite3Strlen30(zIdxName);
7587776279
pIndex = sqlite3HashInsert(pHash, zIdxName, len, 0);
75878
- if( pIndex ){
76280
+ if( ALWAYS(pIndex) ){
7587976281
if( pIndex->pTable->pIndex==pIndex ){
7588076282
pIndex->pTable->pIndex = pIndex->pNext;
7588176283
}else{
7588276284
Index *p;
7588376285
/* Justification of ALWAYS(); The index must be on the list of
@@ -78949,16 +79351,16 @@
7894979351
if( v==0 ) return; /* This only happens if there was a prior error */
7895079352
pToplevel->cookieGoto = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0)+1;
7895179353
}
7895279354
if( iDb>=0 ){
7895379355
sqlite3 *db = pToplevel->db;
78954
- int mask;
79356
+ tAttachMask mask;
7895579357
7895679358
assert( iDb<db->nDb );
7895779359
assert( db->aDb[iDb].pBt!=0 || iDb==1 );
7895879360
assert( iDb<SQLITE_MAX_ATTACHED+2 );
78959
- mask = 1<<iDb;
79361
+ mask = ((tAttachMask)1)<<iDb;
7896079362
if( (pToplevel->cookieMask & mask)==0 ){
7896179363
pToplevel->cookieMask |= mask;
7896279364
pToplevel->cookieValue[iDb] = db->aDb[iDb].pSchema->schema_cookie;
7896379365
if( !OMIT_TEMPDB && iDb==1 ){
7896479366
sqlite3OpenTempDatabase(pToplevel);
@@ -78981,11 +79383,11 @@
7898179383
** necessary to undo a write and the checkpoint should not be set.
7898279384
*/
7898379385
SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){
7898479386
Parse *pToplevel = sqlite3ParseToplevel(pParse);
7898579387
sqlite3CodeVerifySchema(pParse, iDb);
78986
- pToplevel->writeMask |= 1<<iDb;
79388
+ pToplevel->writeMask |= ((tAttachMask)1)<<iDb;
7898779389
pToplevel->isMultiWrite |= setStatement;
7898879390
}
7898979391
7899079392
/*
7899179393
** Indicate that the statement currently under construction might write
@@ -79626,11 +80028,14 @@
7962680028
sqlite3DeleteTable(0, pTab);
7962780029
}
7962880030
sqlite3HashClear(&temp1);
7962980031
sqlite3HashClear(&pSchema->fkeyHash);
7963080032
pSchema->pSeqTab = 0;
79631
- pSchema->flags &= ~DB_SchemaLoaded;
80033
+ if( pSchema->flags & DB_SchemaLoaded ){
80034
+ pSchema->iGeneration++;
80035
+ pSchema->flags &= ~DB_SchemaLoaded;
80036
+ }
7963280037
}
7963380038
7963480039
/*
7963580040
** Find and return the schema associated with a BTree. Create
7963680041
** a new one if necessary.
@@ -84381,12 +84786,13 @@
8438184786
** index and making sure that duplicate entries do not already exist.
8438284787
** Add the new records to the indices as we go.
8438384788
*/
8438484789
for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){
8438584790
int regIdx;
84791
+#ifndef SQLITE_OMIT_UNIQUE_ENFORCEMENT
8438684792
int regR;
84387
-
84793
+#endif
8438884794
if( aRegIdx[iCur]==0 ) continue; /* Skip unused indices */
8438984795
8439084796
/* Create a key for accessing the index entry */
8439184797
regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn+1);
8439284798
for(i=0; i<pIdx->nColumn; i++){
@@ -84399,10 +84805,15 @@
8439984805
}
8440084806
sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i);
8440184807
sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn+1, aRegIdx[iCur]);
8440284808
sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v, pIdx), 0);
8440384809
sqlite3ExprCacheAffinityChange(pParse, regIdx, pIdx->nColumn+1);
84810
+
84811
+#ifdef SQLITE_OMIT_UNIQUE_ENFORCEMENT
84812
+ sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn+1);
84813
+ continue; /* Treat pIdx as if it is not a UNIQUE index */
84814
+#else
8440484815
8440584816
/* Find out what action to take in case there is an indexing conflict */
8440684817
onError = pIdx->onError;
8440784818
if( onError==OE_None ){
8440884819
sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn+1);
@@ -84473,10 +84884,11 @@
8447384884
break;
8447484885
}
8447584886
}
8447684887
sqlite3VdbeJumpHere(v, j3);
8447784888
sqlite3ReleaseTempReg(pParse, regR);
84889
+#endif
8447884890
}
8447984891
8448084892
if( pbMayReplace ){
8448184893
*pbMayReplace = seenReplace;
8448284894
}
@@ -86501,12 +86913,11 @@
8650186913
addr = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
8650286914
sqlite3VdbeChangeP1(v, addr, iDb);
8650386915
sqlite3VdbeChangeP1(v, addr+1, iDb);
8650486916
sqlite3VdbeChangeP1(v, addr+6, SQLITE_DEFAULT_CACHE_SIZE);
8650586917
}else{
86506
- int size = sqlite3Atoi(zRight);
86507
- if( size<0 ) size = -size;
86918
+ int size = sqlite3AbsInt32(sqlite3Atoi(zRight));
8650886919
sqlite3BeginWriteOperation(pParse, 0, iDb);
8650986920
sqlite3VdbeAddOp2(v, OP_Integer, size, 1);
8651086921
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_DEFAULT_CACHE_SIZE, 1);
8651186922
pDb->pSchema->cache_size = size;
8651286923
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
@@ -86811,12 +87222,11 @@
8681187222
if( sqlite3StrICmp(zLeft,"cache_size")==0 ){
8681287223
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
8681387224
if( !zRight ){
8681487225
returnSingleInt(pParse, "cache_size", pDb->pSchema->cache_size);
8681587226
}else{
86816
- int size = sqlite3Atoi(zRight);
86817
- if( size<0 ) size = -size;
87227
+ int size = sqlite3AbsInt32(sqlite3Atoi(zRight));
8681887228
pDb->pSchema->cache_size = size;
8681987229
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
8682087230
}
8682187231
}else
8682287232
@@ -87920,13 +88330,12 @@
8792088330
DbSetProperty(db, iDb, DB_Empty);
8792188331
}
8792288332
pDb->pSchema->enc = ENC(db);
8792388333
8792488334
if( pDb->pSchema->cache_size==0 ){
87925
- size = meta[BTREE_DEFAULT_CACHE_SIZE-1];
88335
+ size = sqlite3AbsInt32(meta[BTREE_DEFAULT_CACHE_SIZE-1]);
8792688336
if( size==0 ){ size = SQLITE_DEFAULT_CACHE_SIZE; }
87927
- if( size<0 ) size = -size;
8792888337
pDb->pSchema->cache_size = size;
8792988338
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
8793088339
}
8793188340
8793288341
/*
@@ -93787,12 +94196,16 @@
9378794196
int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
9378894197
ExprList *pChanges, /* Columns that change in an UPDATE statement */
9378994198
int *pMask /* OUT: Mask of TRIGGER_BEFORE|TRIGGER_AFTER */
9379094199
){
9379194200
int mask = 0;
93792
- Trigger *pList = sqlite3TriggerList(pParse, pTab);
94201
+ Trigger *pList = 0;
9379394202
Trigger *p;
94203
+
94204
+ if( (pParse->db->flags & SQLITE_EnableTrigger)!=0 ){
94205
+ pList = sqlite3TriggerList(pParse, pTab);
94206
+ }
9379494207
assert( pList==0 || IsVirtual(pTab)==0 );
9379594208
for(p=pList; p; p=p->pNext){
9379694209
if( p->op==op && checkColumnOverlap(p->pColumns, pChanges) ){
9379794210
mask |= p->tr_tm;
9379894211
}
@@ -95642,11 +96055,11 @@
9564296055
v = sqlite3GetVdbe(pParse);
9564396056
sqlite3ChangeCookie(pParse, iDb);
9564496057
9564596058
sqlite3VdbeAddOp2(v, OP_Expire, 0, 0);
9564696059
zWhere = sqlite3MPrintf(db, "name='%q' AND type='table'", pTab->zName);
95647
- sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 1, 0, zWhere, P4_DYNAMIC);
96060
+ sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC);
9564896061
sqlite3VdbeAddOp4(v, OP_VCreate, iDb, 0, 0,
9564996062
pTab->zName, sqlite3Strlen30(pTab->zName) + 1);
9565096063
}
9565196064
9565296065
/* If we are rereading the sqlite_master table create the in-memory
@@ -98732,11 +99145,12 @@
9873299145
/*
9873399146
** Estimate the number of rows that will be returned based on
9873499147
** an equality constraint x=VALUE and where that VALUE occurs in
9873599148
** the histogram data. This only works when x is the left-most
9873699149
** column of an index and sqlite_stat2 histogram data is available
98737
-** for that index.
99150
+** for that index. When pExpr==NULL that means the constraint is
99151
+** "x IS NULL" instead of "x=VALUE".
9873899152
**
9873999153
** Write the estimated row count into *pnRow and return SQLITE_OK.
9874099154
** If unable to make an estimate, leave *pnRow unchanged and return
9874199155
** non-zero.
9874299156
**
@@ -98757,12 +99171,16 @@
9875799171
int rc; /* Subfunction return code */
9875899172
double nRowEst; /* New estimate of the number of rows */
9875999173
9876099174
assert( p->aSample!=0 );
9876199175
aff = p->pTable->aCol[p->aiColumn[0]].affinity;
98762
- rc = valueFromExpr(pParse, pExpr, aff, &pRhs);
98763
- if( rc ) goto whereEqualScanEst_cancel;
99176
+ if( pExpr ){
99177
+ rc = valueFromExpr(pParse, pExpr, aff, &pRhs);
99178
+ if( rc ) goto whereEqualScanEst_cancel;
99179
+ }else{
99180
+ pRhs = sqlite3ValueNew(pParse->db);
99181
+ }
9876499182
if( pRhs==0 ) return SQLITE_NOTFOUND;
9876599183
rc = whereRangeRegion(pParse, p, pRhs, 0, &iLower);
9876699184
if( rc ) goto whereEqualScanEst_cancel;
9876799185
rc = whereRangeRegion(pParse, p, pRhs, 1, &iUpper);
9876899186
if( rc ) goto whereEqualScanEst_cancel;
@@ -99147,11 +99565,13 @@
9914799565
** data is available for column x, then it might be possible
9914899566
** to get a better estimate on the number of rows based on
9914999567
** VALUE and how common that value is according to the histogram.
9915099568
*/
9915199569
if( nRow>(double)1 && nEq==1 && pFirstTerm!=0 ){
99152
- if( pFirstTerm->eOperator==WO_EQ ){
99570
+ if( pFirstTerm->eOperator & (WO_EQ|WO_ISNULL) ){
99571
+ testcase( pFirstTerm->eOperator==WO_EQ );
99572
+ testcase( pFirstTerm->pOperator==WO_ISNULL );
9915399573
whereEqualScanEst(pParse, pProbe, pFirstTerm->pExpr->pRight, &nRow);
9915499574
}else if( pFirstTerm->eOperator==WO_IN && bInEst==0 ){
9915599575
whereInScanEst(pParse, pProbe, pFirstTerm->pExpr->x.pList, &nRow);
9915699576
}
9915799577
}
@@ -100213,11 +100633,17 @@
100213100633
}
100214100634
100215100635
/* Record the instruction used to terminate the loop. Disable
100216100636
** WHERE clause terms made redundant by the index range scan.
100217100637
*/
100218
- pLevel->op = bRev ? OP_Prev : OP_Next;
100638
+ if( pLevel->plan.wsFlags & WHERE_UNIQUE ){
100639
+ pLevel->op = OP_Noop;
100640
+ }else if( bRev ){
100641
+ pLevel->op = OP_Prev;
100642
+ }else{
100643
+ pLevel->op = OP_Next;
100644
+ }
100219100645
pLevel->p1 = iIdxCur;
100220100646
}else
100221100647
100222100648
#ifndef SQLITE_OMIT_OR_OPTIMIZATION
100223100649
if( pLevel->plan.wsFlags & WHERE_MULTI_OR ){
@@ -106160,10 +106586,17 @@
106160106586
case SQLITE_CONFIG_HEAP: {
106161106587
/* Designate a buffer for heap memory space */
106162106588
sqlite3GlobalConfig.pHeap = va_arg(ap, void*);
106163106589
sqlite3GlobalConfig.nHeap = va_arg(ap, int);
106164106590
sqlite3GlobalConfig.mnReq = va_arg(ap, int);
106591
+
106592
+ if( sqlite3GlobalConfig.mnReq<1 ){
106593
+ sqlite3GlobalConfig.mnReq = 1;
106594
+ }else if( sqlite3GlobalConfig.mnReq>(1<<12) ){
106595
+ /* cap min request size at 2^12 */
106596
+ sqlite3GlobalConfig.mnReq = (1<<12);
106597
+ }
106165106598
106166106599
if( sqlite3GlobalConfig.pHeap==0 ){
106167106600
/* If the heap pointer is NULL, then restore the malloc implementation
106168106601
** back to NULL pointers too. This will cause the malloc to go
106169106602
** back to its default implementation when sqlite3_initialize() is
@@ -106301,11 +106734,39 @@
106301106734
int cnt = va_arg(ap, int); /* IMP: R-04460-53386 */
106302106735
rc = setupLookaside(db, pBuf, sz, cnt);
106303106736
break;
106304106737
}
106305106738
default: {
106739
+ static const struct {
106740
+ int op; /* The opcode */
106741
+ u32 mask; /* Mask of the bit in sqlite3.flags to set/clear */
106742
+ } aFlagOp[] = {
106743
+ { SQLITE_DBCONFIG_ENABLE_FKEY, SQLITE_ForeignKeys },
106744
+ { SQLITE_DBCONFIG_ENABLE_TRIGGER, SQLITE_EnableTrigger },
106745
+ };
106746
+ unsigned int i;
106306106747
rc = SQLITE_ERROR; /* IMP: R-42790-23372 */
106748
+ for(i=0; i<ArraySize(aFlagOp); i++){
106749
+ if( aFlagOp[i].op==op ){
106750
+ int onoff = va_arg(ap, int);
106751
+ int *pRes = va_arg(ap, int*);
106752
+ int oldFlags = db->flags;
106753
+ if( onoff>0 ){
106754
+ db->flags |= aFlagOp[i].mask;
106755
+ }else if( onoff==0 ){
106756
+ db->flags &= ~aFlagOp[i].mask;
106757
+ }
106758
+ if( oldFlags!=db->flags ){
106759
+ sqlite3ExpirePreparedStatements(db);
106760
+ }
106761
+ if( pRes ){
106762
+ *pRes = (db->flags & aFlagOp[i].mask)!=0;
106763
+ }
106764
+ rc = SQLITE_OK;
106765
+ break;
106766
+ }
106767
+ }
106307106768
break;
106308106769
}
106309106770
}
106310106771
va_end(ap);
106311106772
return rc;
@@ -107474,12 +107935,12 @@
107474107935
# error SQLITE_MAX_VDBE_OP must be at least 40
107475107936
#endif
107476107937
#if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>1000
107477107938
# error SQLITE_MAX_FUNCTION_ARG must be between 0 and 1000
107478107939
#endif
107479
-#if SQLITE_MAX_ATTACHED<0 || SQLITE_MAX_ATTACHED>30
107480
-# error SQLITE_MAX_ATTACHED must be between 0 and 30
107940
+#if SQLITE_MAX_ATTACHED<0 || SQLITE_MAX_ATTACHED>62
107941
+# error SQLITE_MAX_ATTACHED must be between 0 and 62
107481107942
#endif
107482107943
#if SQLITE_MAX_LIKE_PATTERN_LENGTH<1
107483107944
# error SQLITE_MAX_LIKE_PATTERN_LENGTH must be at least 1
107484107945
#endif
107485107946
#if SQLITE_MAX_COLUMN>32767
@@ -107634,11 +108095,11 @@
107634108095
assert( sizeof(db->aLimit)==sizeof(aHardLimit) );
107635108096
memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit));
107636108097
db->autoCommit = 1;
107637108098
db->nextAutovac = -1;
107638108099
db->nextPagesize = 0;
107639
- db->flags |= SQLITE_ShortColNames | SQLITE_AutoIndex
108100
+ db->flags |= SQLITE_ShortColNames | SQLITE_AutoIndex | SQLITE_EnableTrigger
107640108101
#if SQLITE_DEFAULT_FILE_FORMAT<4
107641108102
| SQLITE_LegacyFileFmt
107642108103
#endif
107643108104
#ifdef SQLITE_ENABLE_LOAD_EXTENSION
107644108105
| SQLITE_LoadExtension
@@ -119847,17 +120308,17 @@
119847120308
Fts3Expr *pExpr, /* Phrase expression node */
119848120309
int iPhrase, /* Phrase number */
119849120310
void *pCtx /* Pointer to MatchInfo structure */
119850120311
){
119851120312
MatchInfo *p = (MatchInfo *)pCtx;
120313
+ int iStart = iPhrase * p->nCol * 3;
120314
+ int i;
120315
+
120316
+ for(i=0; i<p->nCol; i++) p->aMatchinfo[iStart+i*3] = 0;
119852120317
119853120318
if( pExpr->aDoclist ){
119854120319
char *pCsr;
119855
- int iStart = iPhrase * p->nCol * 3;
119856
- int i;
119857
-
119858
- for(i=0; i<p->nCol; i++) p->aMatchinfo[iStart+i*3] = 0;
119859120320
119860120321
pCsr = sqlite3Fts3FindPositions(pExpr, p->pCursor->iPrevId, -1);
119861120322
if( pCsr ){
119862120323
fts3LoadColumnlistCounts(&pCsr, &p->aMatchinfo[iStart], 0);
119863120324
}
@@ -121944,19 +122405,19 @@
121944122405
** to which the constraint applies. The leftmost coordinate column
121945122406
** is 'a', the second from the left 'b' etc.
121946122407
*/
121947122408
static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
121948122409
int rc = SQLITE_OK;
121949
- int ii, cCol;
122410
+ int ii;
121950122411
121951122412
int iIdx = 0;
121952122413
char zIdxStr[RTREE_MAX_DIMENSIONS*8+1];
121953122414
memset(zIdxStr, 0, sizeof(zIdxStr));
121954122415
UNUSED_PARAMETER(tab);
121955122416
121956122417
assert( pIdxInfo->idxStr==0 );
121957
- for(ii=0; ii<pIdxInfo->nConstraint; ii++){
122418
+ for(ii=0; ii<pIdxInfo->nConstraint && iIdx<(sizeof(zIdxStr)-1); ii++){
121958122419
struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii];
121959122420
121960122421
if( p->usable && p->iColumn==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){
121961122422
/* We have an equality constraint on the rowid. Use strategy 1. */
121962122423
int jj;
@@ -121976,13 +122437,11 @@
121976122437
pIdxInfo->estimatedCost = 10.0;
121977122438
return SQLITE_OK;
121978122439
}
121979122440
121980122441
if( p->usable && (p->iColumn>0 || p->op==SQLITE_INDEX_CONSTRAINT_MATCH) ){
121981
- int j, opmsk;
121982
- static const unsigned char compatible[] = { 0, 0, 1, 1, 2, 2 };
121983
- u8 op = 0;
122442
+ u8 op;
121984122443
switch( p->op ){
121985122444
case SQLITE_INDEX_CONSTRAINT_EQ: op = RTREE_EQ; break;
121986122445
case SQLITE_INDEX_CONSTRAINT_GT: op = RTREE_GT; break;
121987122446
case SQLITE_INDEX_CONSTRAINT_LE: op = RTREE_LE; break;
121988122447
case SQLITE_INDEX_CONSTRAINT_LT: op = RTREE_LT; break;
@@ -121990,41 +122449,14 @@
121990122449
default:
121991122450
assert( p->op==SQLITE_INDEX_CONSTRAINT_MATCH );
121992122451
op = RTREE_MATCH;
121993122452
break;
121994122453
}
121995
- assert( op!=0 );
121996
-
121997
- /* Make sure this particular constraint has not been used before.
121998
- ** If it has been used before, ignore it.
121999
- **
122000
- ** A <= or < can be used if there is a prior >= or >.
122001
- ** A >= or > can be used if there is a prior < or <=.
122002
- ** A <= or < is disqualified if there is a prior <=, <, or ==.
122003
- ** A >= or > is disqualified if there is a prior >=, >, or ==.
122004
- ** A == is disqualifed if there is any prior constraint.
122005
- */
122006
- assert( compatible[RTREE_EQ & 7]==0 );
122007
- assert( compatible[RTREE_LT & 7]==1 );
122008
- assert( compatible[RTREE_LE & 7]==1 );
122009
- assert( compatible[RTREE_GT & 7]==2 );
122010
- assert( compatible[RTREE_GE & 7]==2 );
122011
- cCol = p->iColumn - 1 + 'a';
122012
- opmsk = compatible[op & 7];
122013
- for(j=0; j<iIdx; j+=2){
122014
- if( zIdxStr[j+1]==cCol && (compatible[zIdxStr[j] & 7] & opmsk)!=0 ){
122015
- op = 0;
122016
- break;
122017
- }
122018
- }
122019
- if( op ){
122020
- assert( iIdx<sizeof(zIdxStr)-1 );
122021
- zIdxStr[iIdx++] = op;
122022
- zIdxStr[iIdx++] = cCol;
122023
- pIdxInfo->aConstraintUsage[ii].argvIndex = (iIdx/2);
122024
- pIdxInfo->aConstraintUsage[ii].omit = 1;
122025
- }
122454
+ zIdxStr[iIdx++] = op;
122455
+ zIdxStr[iIdx++] = p->iColumn - 1 + 'a';
122456
+ pIdxInfo->aConstraintUsage[ii].argvIndex = (iIdx/2);
122457
+ pIdxInfo->aConstraintUsage[ii].omit = 1;
122026122458
}
122027122459
}
122028122460
122029122461
pIdxInfo->idxNum = 2;
122030122462
pIdxInfo->needToFreeIdxStr = 1;
122031122463
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -650,11 +650,11 @@
650 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
651 ** [sqlite_version()] and [sqlite_source_id()].
652 */
653 #define SQLITE_VERSION "3.7.6"
654 #define SQLITE_VERSION_NUMBER 3007006
655 #define SQLITE_SOURCE_ID "2011-03-06 21:54:33 3bfbf026dd6a0eeef07f8f5f1ebf74c9cfebcd61"
656
657 /*
658 ** CAPI3REF: Run-Time Library Version Numbers
659 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
660 **
@@ -1439,14 +1439,27 @@
1439 ** a 24-hour day).
1440 ** ^SQLite will use the xCurrentTimeInt64() method to get the current
1441 ** date and time if that method is available (if iVersion is 2 or
1442 ** greater and the function pointer is not NULL) and will fall back
1443 ** to xCurrentTime() if xCurrentTimeInt64() is unavailable.
 
 
 
 
 
 
 
 
 
 
 
 
1444 */
1445 typedef struct sqlite3_vfs sqlite3_vfs;
 
1446 struct sqlite3_vfs {
1447 int iVersion; /* Structure version number (currently 2) */
1448 int szOsFile; /* Size of subclassed sqlite3_file */
1449 int mxPathname; /* Maximum file pathname length */
1450 sqlite3_vfs *pNext; /* Next registered VFS */
1451 const char *zName; /* Name of this virtual file system */
1452 void *pAppData; /* Pointer to application-specific data */
@@ -1468,10 +1481,17 @@
1468 ** definition. Those that follow are added in version 2 or later
1469 */
1470 int (*xCurrentTimeInt64)(sqlite3_vfs*, sqlite3_int64*);
1471 /*
1472 ** The methods above are in versions 1 and 2 of the sqlite_vfs object.
 
 
 
 
 
 
 
1473 ** New fields may be appended in figure versions. The iVersion
1474 ** value will increment whenever this happens.
1475 */
1476 };
1477
@@ -1652,21 +1672,16 @@
1652 ** CAPI3REF: Configure database connections
1653 **
1654 ** The sqlite3_db_config() interface is used to make configuration
1655 ** changes to a [database connection]. The interface is similar to
1656 ** [sqlite3_config()] except that the changes apply to a single
1657 ** [database connection] (specified in the first argument). The
1658 ** sqlite3_db_config() interface should only be used immediately after
1659 ** the database connection is created using [sqlite3_open()],
1660 ** [sqlite3_open16()], or [sqlite3_open_v2()].
1661 **
1662 ** The second argument to sqlite3_db_config(D,V,...) is the
1663 ** configuration verb - an integer code that indicates what
1664 ** aspect of the [database connection] is being configured.
1665 ** The only choice for this value is [SQLITE_DBCONFIG_LOOKASIDE].
1666 ** New verbs are likely to be added in future releases of SQLite.
1667 ** Additional arguments depend on the verb.
1668 **
1669 ** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if
1670 ** the call is considered successful.
1671 */
1672 SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
@@ -1887,11 +1902,13 @@
1887 ** undoing any prior invocation of [SQLITE_CONFIG_MALLOC]. ^If the
1888 ** memory pointer is not NULL and either [SQLITE_ENABLE_MEMSYS3] or
1889 ** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory
1890 ** allocator is engaged to handle all of SQLites memory allocation needs.
1891 ** The first pointer (the memory pointer) must be aligned to an 8-byte
1892 ** boundary or subsequent behavior of SQLite will be undefined.</dd>
 
 
1893 **
1894 ** <dt>SQLITE_CONFIG_MUTEX</dt>
1895 ** <dd> ^(This option takes a single argument which is a pointer to an
1896 ** instance of the [sqlite3_mutex_methods] structure. The argument specifies
1897 ** alternative low-level mutex routines to be used in place
@@ -2008,13 +2025,35 @@
2008 ** [sqlite3_db_status](D,[SQLITE_CONFIG_LOOKASIDE],...) is zero.
2009 ** Any attempt to change the lookaside memory configuration when lookaside
2010 ** memory is in use leaves the configuration unchanged and returns
2011 ** [SQLITE_BUSY].)^</dd>
2012 **
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2013 ** </dl>
2014 */
2015 #define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */
 
 
2016
2017
2018 /*
2019 ** CAPI3REF: Enable Or Disable Extended Result Codes
2020 **
@@ -8974,10 +9013,11 @@
8974 /*
8975 ** An instance of the following structure stores a database schema.
8976 */
8977 struct Schema {
8978 int schema_cookie; /* Database schema version number for this file */
 
8979 Hash tblHash; /* All tables indexed by name */
8980 Hash idxHash; /* All (named) indices indexed by name */
8981 Hash trigHash; /* All triggers indexed by name */
8982 Hash fkeyHash; /* All foreign keys by referenced table name */
8983 Table *pSeqTab; /* The sqlite_sequence table used by AUTOINCREMENT */
@@ -9227,10 +9267,11 @@
9227 #define SQLITE_RecTriggers 0x02000000 /* Enable recursive triggers */
9228 #define SQLITE_ForeignKeys 0x04000000 /* Enforce foreign key constraints */
9229 #define SQLITE_AutoIndex 0x08000000 /* Enable automatic indexes */
9230 #define SQLITE_PreferBuiltin 0x10000000 /* Preference to built-in funcs */
9231 #define SQLITE_LoadExtension 0x20000000 /* Enable load_extension */
 
9232
9233 /*
9234 ** Bits of the sqlite3.flags field that are used by the
9235 ** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface.
9236 ** These must be the low-order bits of the flags field.
@@ -9926,11 +9967,11 @@
9926 u8 op; /* Operation performed by this node */
9927 char affinity; /* The affinity of the column or 0 if not a column */
9928 u16 flags; /* Various flags. EP_* See below */
9929 union {
9930 char *zToken; /* Token value. Zero terminated and dequoted */
9931 int iValue; /* Integer value if EP_IntValue */
9932 } u;
9933
9934 /* If the EP_TokenOnly flag is set in the Expr.flags mask, then no
9935 ** space is allocated for the fields below this point. An attempt to
9936 ** access them will result in a segfault or malfunction.
@@ -10426,10 +10467,17 @@
10426 SubProgram *pProgram; /* Program implementing pTrigger/orconf */
10427 u32 aColmask[2]; /* Masks of old.*, new.* columns accessed */
10428 TriggerPrg *pNext; /* Next entry in Parse.pTriggerPrg list */
10429 };
10430
 
 
 
 
 
 
 
10431 /*
10432 ** An SQL parser context. A copy of this structure is passed through
10433 ** the parser and down into all the parser action routine in order to
10434 ** carry around information that is global to the entire parse.
10435 **
@@ -10474,12 +10522,12 @@
10474 u8 tempReg; /* iReg is a temp register that needs to be freed */
10475 int iLevel; /* Nesting level */
10476 int iReg; /* Reg with value of this column. 0 means none. */
10477 int lru; /* Least recently used entry has the smallest value */
10478 } aColCache[SQLITE_N_COLCACHE]; /* One for each column cache entry */
10479 u32 writeMask; /* Start a write transaction on these databases */
10480 u32 cookieMask; /* Bitmask of schema verified databases */
10481 u8 isMultiWrite; /* True if statement may affect/insert multiple rows */
10482 u8 mayAbort; /* True if statement may throw an ABORT exception */
10483 int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */
10484 int cookieValue[SQLITE_MAX_ATTACHED+2]; /* Values of cookies to verify */
10485 #ifndef SQLITE_OMIT_SHARED_CACHE
@@ -11209,10 +11257,11 @@
11209 SQLITE_PRIVATE int sqlite3CheckObjectName(Parse *, const char *);
11210 SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *, int);
11211 SQLITE_PRIVATE int sqlite3AddInt64(i64*,i64);
11212 SQLITE_PRIVATE int sqlite3SubInt64(i64*,i64);
11213 SQLITE_PRIVATE int sqlite3MulInt64(i64*,i64);
 
11214
11215 SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value*, u8);
11216 SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value*, u8);
11217 SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8,
11218 void(*)(void*));
@@ -12023,10 +12072,13 @@
12023 "OMIT_TRIGGER",
12024 #endif
12025 #ifdef SQLITE_OMIT_TRUNCATE_OPTIMIZATION
12026 "OMIT_TRUNCATE_OPTIMIZATION",
12027 #endif
 
 
 
12028 #ifdef SQLITE_OMIT_UTF16
12029 "OMIT_UTF16",
12030 #endif
12031 #ifdef SQLITE_OMIT_VACUUM
12032 "OMIT_VACUUM",
@@ -12436,11 +12488,11 @@
12436 u8 inVtabMethod; /* See comments above */
12437 u8 usesStmtJournal; /* True if uses a statement journal */
12438 u8 readOnly; /* True for read-only statements */
12439 u8 isPrepareV2; /* True if prepared with prepare_v2() */
12440 int nChange; /* Number of db changes made since last reset */
12441 int btreeMask; /* Bitmask of db->aDb[] entries referenced */
12442 int iStatement; /* Statement number (or 0 if has not opened stmt) */
12443 int aCounter[3]; /* Counters used by sqlite3_stmt_status() */
12444 BtreeMutexArray aMutex; /* An array of Btree used here and needing locks */
12445 #ifndef SQLITE_OMIT_TRACE
12446 i64 startTime; /* Time when query started - used for profiling */
@@ -16155,11 +16207,11 @@
16155 ** memsys5Log(8) -> 3
16156 ** memsys5Log(9) -> 4
16157 */
16158 static int memsys5Log(int iValue){
16159 int iLog;
16160 for(iLog=0; (1<<iLog)<iValue; iLog++);
16161 return iLog;
16162 }
16163
16164 /*
16165 ** Initialize the memory allocator.
@@ -16186,10 +16238,11 @@
16186
16187 nByte = sqlite3GlobalConfig.nHeap;
16188 zByte = (u8*)sqlite3GlobalConfig.pHeap;
16189 assert( zByte!=0 ); /* sqlite3_config() does not allow otherwise */
16190
 
16191 nMinLog = memsys5Log(sqlite3GlobalConfig.mnReq);
16192 mem5.szAtom = (1<<nMinLog);
16193 while( (int)sizeof(Mem5Link)>mem5.szAtom ){
16194 mem5.szAtom = mem5.szAtom << 1;
16195 }
@@ -16689,15 +16742,20 @@
16689 ** Each recursive mutex is an instance of the following structure.
16690 */
16691 struct sqlite3_mutex {
16692 HMTX mutex; /* Mutex controlling the lock */
16693 int id; /* Mutex type */
16694 int nRef; /* Number of references */
16695 TID owner; /* Thread holding this mutex */
 
16696 };
16697
16698 #define OS2_MUTEX_INITIALIZER 0,0,0,0
 
 
 
 
16699
16700 /*
16701 ** Initialize and deinitialize the mutex subsystem.
16702 */
16703 static int os2MutexInit(void){ return SQLITE_OK; }
@@ -16709,15 +16767,18 @@
16709 ** that means that a mutex could not be allocated.
16710 ** SQLite will unwind its stack and return an error. The argument
16711 ** to sqlite3_mutex_alloc() is one of these integer constants:
16712 **
16713 ** <ul>
16714 ** <li> SQLITE_MUTEX_FAST 0
16715 ** <li> SQLITE_MUTEX_RECURSIVE 1
16716 ** <li> SQLITE_MUTEX_STATIC_MASTER 2
16717 ** <li> SQLITE_MUTEX_STATIC_MEM 3
16718 ** <li> SQLITE_MUTEX_STATIC_PRNG 4
 
 
 
16719 ** </ul>
16720 **
16721 ** The first two constants cause sqlite3_mutex_alloc() to create
16722 ** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
16723 ** is used but not necessarily so when SQLITE_MUTEX_FAST is used.
@@ -16727,11 +16788,11 @@
16727 ** cases where it really needs one. If a faster non-recursive mutex
16728 ** implementation is available on the host platform, the mutex subsystem
16729 ** might return such a mutex in response to SQLITE_MUTEX_FAST.
16730 **
16731 ** The other allowed parameters to sqlite3_mutex_alloc() each return
16732 ** a pointer to a static preexisting mutex. Three static mutexes are
16733 ** used by the current version of SQLite. Future versions of SQLite
16734 ** may add additional static mutexes. Static mutexes are for internal
16735 ** use by SQLite only. Applications that use SQLite mutexes should
16736 ** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or
16737 ** SQLITE_MUTEX_RECURSIVE.
@@ -16757,17 +16818,17 @@
16757 }
16758 break;
16759 }
16760 default: {
16761 static volatile int isInit = 0;
16762 static sqlite3_mutex staticMutexes[] = {
16763 { OS2_MUTEX_INITIALIZER, },
16764 { OS2_MUTEX_INITIALIZER, },
16765 { OS2_MUTEX_INITIALIZER, },
16766 { OS2_MUTEX_INITIALIZER, },
16767 { OS2_MUTEX_INITIALIZER, },
16768 { OS2_MUTEX_INITIALIZER, },
16769 };
16770 if ( !isInit ){
16771 APIRET rc;
16772 PTIB ptib;
16773 PPIB ppib;
@@ -16809,13 +16870,18 @@
16809 /*
16810 ** This routine deallocates a previously allocated mutex.
16811 ** SQLite is careful to deallocate every mutex that it allocates.
16812 */
16813 static void os2MutexFree(sqlite3_mutex *p){
16814 if( p==0 ) return;
16815 assert( p->nRef==0 );
 
 
 
 
16816 assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
 
16817 DosCloseMutexSem( p->mutex );
16818 sqlite3_free( p );
16819 }
16820
16821 #ifdef SQLITE_DEBUG
@@ -16826,30 +16892,33 @@
16826 static int os2MutexHeld(sqlite3_mutex *p){
16827 TID tid;
16828 PID pid;
16829 ULONG ulCount;
16830 PTIB ptib;
16831 if( p!=0 ) {
16832 DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount);
16833 } else {
16834 DosGetInfoBlocks(&ptib, NULL);
16835 tid = ptib->tib_ptib2->tib2_ultid;
16836 }
16837 return p==0 || (p->nRef!=0 && p->owner==tid);
16838 }
16839 static int os2MutexNotheld(sqlite3_mutex *p){
16840 TID tid;
16841 PID pid;
16842 ULONG ulCount;
16843 PTIB ptib;
16844 if( p!= 0 ) {
16845 DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount);
16846 } else {
16847 DosGetInfoBlocks(&ptib, NULL);
16848 tid = ptib->tib_ptib2->tib2_ultid;
16849 }
16850 return p==0 || p->nRef==0 || p->owner!=tid;
 
 
 
 
 
16851 }
16852 #endif
16853
16854 /*
16855 ** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
@@ -16861,36 +16930,25 @@
16861 ** mutex must be exited an equal number of times before another thread
16862 ** can enter. If the same thread tries to enter any other kind of mutex
16863 ** more than once, the behavior is undefined.
16864 */
16865 static void os2MutexEnter(sqlite3_mutex *p){
16866 TID tid;
16867 PID holder1;
16868 ULONG holder2;
16869 if( p==0 ) return;
16870 assert( p->id==SQLITE_MUTEX_RECURSIVE || os2MutexNotheld(p) );
16871 DosRequestMutexSem(p->mutex, SEM_INDEFINITE_WAIT);
16872 DosQueryMutexSem(p->mutex, &holder1, &tid, &holder2);
16873 p->owner = tid;
16874 p->nRef++;
16875 }
16876 static int os2MutexTry(sqlite3_mutex *p){
16877 int rc;
16878 TID tid;
16879 PID holder1;
16880 ULONG holder2;
16881 if( p==0 ) return SQLITE_OK;
16882 assert( p->id==SQLITE_MUTEX_RECURSIVE || os2MutexNotheld(p) );
16883 if( DosRequestMutexSem(p->mutex, SEM_IMMEDIATE_RETURN) == NO_ERROR) {
16884 DosQueryMutexSem(p->mutex, &holder1, &tid, &holder2);
16885 p->owner = tid;
16886 p->nRef++;
16887 rc = SQLITE_OK;
16888 } else {
16889 rc = SQLITE_BUSY;
 
16890 }
16891
16892 return rc;
16893 }
16894
16895 /*
16896 ** The sqlite3_mutex_leave() routine exits a mutex that was
@@ -16897,23 +16955,18 @@
16897 ** previously entered by the same thread. The behavior
16898 ** is undefined if the mutex is not currently entered or
16899 ** is not currently allocated. SQLite will never do either.
16900 */
16901 static void os2MutexLeave(sqlite3_mutex *p){
16902 TID tid;
16903 PID holder1;
16904 ULONG holder2;
16905 if( p==0 ) return;
16906 assert( p->nRef>0 );
16907 DosQueryMutexSem(p->mutex, &holder1, &tid, &holder2);
16908 assert( p->owner==tid );
16909 p->nRef--;
16910 assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
16911 DosReleaseMutexSem(p->mutex);
 
 
 
16912 }
16913
16914 SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
16915 static const sqlite3_mutex_methods sMutex = {
16916 os2MutexInit,
16917 os2MutexEnd,
16918 os2MutexAlloc,
16919 os2MutexFree,
@@ -16921,10 +16974,13 @@
16921 os2MutexTry,
16922 os2MutexLeave,
16923 #ifdef SQLITE_DEBUG
16924 os2MutexHeld,
16925 os2MutexNotheld
 
 
 
16926 #endif
16927 };
16928
16929 return &sMutex;
16930 }
@@ -17564,11 +17620,11 @@
17564 #else
17565 UNUSED_PARAMETER(p);
17566 #endif
17567 #ifdef SQLITE_DEBUG
17568 if( rc==SQLITE_OK && p->trace ){
17569 printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
17570 }
17571 #endif
17572 return rc;
17573 }
17574
@@ -21270,10 +21326,20 @@
21270 r *= TWOPOWER32;
21271 if( sqlite3AddInt64(&r, iA0*iB0) ) return 1;
21272 *pA = r;
21273 return 0;
21274 }
 
 
 
 
 
 
 
 
 
 
21275
21276 /************** End of util.c ************************************************/
21277 /************** Begin file hash.c ********************************************/
21278 /*
21279 ** 2001 September 22
@@ -22560,23 +22626,27 @@
22560 /*
22561 ** This vector defines all the methods that can operate on an
22562 ** sqlite3_file for os2.
22563 */
22564 static const sqlite3_io_methods os2IoMethod = {
22565 1, /* iVersion */
22566 os2Close,
22567 os2Read,
22568 os2Write,
22569 os2Truncate,
22570 os2Sync,
22571 os2FileSize,
22572 os2Lock,
22573 os2Unlock,
22574 os2CheckReservedLock,
22575 os2FileControl,
22576 os2SectorSize,
22577 os2DeviceCharacteristics
 
 
 
 
22578 };
22579
22580 /***************************************************************************
22581 ** Here ends the I/O methods that form the sqlite3_io_methods object.
22582 **
@@ -22664,115 +22734,151 @@
22664 /*
22665 ** Open a file.
22666 */
22667 static int os2Open(
22668 sqlite3_vfs *pVfs, /* Not used */
22669 const char *zName, /* Name of the file */
22670 sqlite3_file *id, /* Write the SQLite file handle here */
22671 int flags, /* Open mode flags */
22672 int *pOutFlags /* Status return flags */
22673 ){
22674 HFILE h;
22675 ULONG ulFileAttribute = FILE_NORMAL;
22676 ULONG ulOpenFlags = 0;
22677 ULONG ulOpenMode = 0;
 
 
22678 os2File *pFile = (os2File*)id;
22679 APIRET rc = NO_ERROR;
22680 ULONG ulAction;
22681 char *zNameCp;
22682 char zTmpname[CCHMAXPATH+1]; /* Buffer to hold name of temp file */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22683
22684 /* If the second argument to this function is NULL, generate a
22685 ** temporary file name to use
22686 */
22687 if( !zName ){
22688 int rc = getTempname(CCHMAXPATH+1, zTmpname);
 
22689 if( rc!=SQLITE_OK ){
22690 return rc;
22691 }
22692 zName = zTmpname;
22693 }
22694
22695
22696 memset( pFile, 0, sizeof(*pFile) );
22697
22698 OSTRACE(( "OPEN want %d\n", flags ));
22699
22700 if( flags & SQLITE_OPEN_READWRITE ){
22701 ulOpenMode |= OPEN_ACCESS_READWRITE;
22702 OSTRACE(( "OPEN read/write\n" ));
22703 }else{
22704 ulOpenMode |= OPEN_ACCESS_READONLY;
22705 OSTRACE(( "OPEN read only\n" ));
22706 }
22707
22708 if( flags & SQLITE_OPEN_CREATE ){
22709 ulOpenFlags |= OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW;
22710 OSTRACE(( "OPEN open new/create\n" ));
22711 }else{
22712 ulOpenFlags |= OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW;
22713 OSTRACE(( "OPEN open existing\n" ));
22714 }
22715
22716 if( flags & SQLITE_OPEN_MAIN_DB ){
22717 ulOpenMode |= OPEN_SHARE_DENYNONE;
22718 OSTRACE(( "OPEN share read/write\n" ));
22719 }else{
22720 ulOpenMode |= OPEN_SHARE_DENYWRITE;
22721 OSTRACE(( "OPEN share read only\n" ));
22722 }
22723
22724 if( flags & SQLITE_OPEN_DELETEONCLOSE ){
22725 char pathUtf8[CCHMAXPATH];
22726 #ifdef NDEBUG /* when debugging we want to make sure it is deleted */
22727 ulFileAttribute = FILE_HIDDEN;
22728 #endif
22729 os2FullPathname( pVfs, zName, CCHMAXPATH, pathUtf8 );
22730 pFile->pathToDel = convertUtf8PathToCp( pathUtf8 );
22731 OSTRACE(( "OPEN hidden/delete on close file attributes\n" ));
22732 }else{
22733 pFile->pathToDel = NULL;
22734 OSTRACE(( "OPEN normal file attribute\n" ));
22735 }
22736
22737 /* always open in random access mode for possibly better speed */
22738 ulOpenMode |= OPEN_FLAGS_RANDOM;
22739 ulOpenMode |= OPEN_FLAGS_FAIL_ON_ERROR;
22740 ulOpenMode |= OPEN_FLAGS_NOINHERIT;
 
22741
22742 zNameCp = convertUtf8PathToCp( zName );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22743 rc = DosOpen( (PSZ)zNameCp,
22744 &h,
22745 &ulAction,
22746 0L,
22747 ulFileAttribute,
22748 ulOpenFlags,
22749 ulOpenMode,
22750 (PEAOP2)NULL );
22751 free( zNameCp );
 
22752 if( rc != NO_ERROR ){
22753 OSTRACE(( "OPEN Invalid handle rc=%d: zName=%s, ulAction=%#lx, ulAttr=%#lx, ulFlags=%#lx, ulMode=%#lx\n",
22754 rc, zName, ulAction, ulFileAttribute, ulOpenFlags, ulOpenMode ));
22755 if( pFile->pathToDel )
22756 free( pFile->pathToDel );
22757 pFile->pathToDel = NULL;
22758 if( flags & SQLITE_OPEN_READWRITE ){
22759 OSTRACE(( "OPEN %d Invalid handle\n",
22760 ((flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE) ));
22761 return os2Open( pVfs, zName, id,
22762 ((flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE),
22763 pOutFlags );
22764 }else{
22765 return SQLITE_CANTOPEN;
22766 }
22767 }
22768
22769 if( pOutFlags ){
22770 *pOutFlags = flags & SQLITE_OPEN_READWRITE ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY;
22771 }
22772
22773 pFile->pMethod = &os2IoMethod;
22774 pFile->h = h;
22775 OpenCounter(+1);
22776 OSTRACE(( "OPEN %d pOutFlags=%d\n", pFile->h, pOutFlags ));
22777 return SQLITE_OK;
22778 }
@@ -22783,17 +22889,20 @@
22783 static int os2Delete(
22784 sqlite3_vfs *pVfs, /* Not used on os2 */
22785 const char *zFilename, /* Name of file to delete */
22786 int syncDir /* Not used on os2 */
22787 ){
22788 APIRET rc = NO_ERROR;
22789 char *zFilenameCp = convertUtf8PathToCp( zFilename );
22790 SimulateIOError( return SQLITE_IOERR_DELETE );
 
22791 rc = DosDelete( (PSZ)zFilenameCp );
22792 free( zFilenameCp );
22793 OSTRACE(( "DELETE \"%s\"\n", zFilename ));
22794 return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR_DELETE;
 
 
22795 }
22796
22797 /*
22798 ** Check the existance and status of a file.
22799 */
@@ -22854,11 +22963,11 @@
22854 ** os2Dlopen returns zero if DosLoadModule is not successful.
22855 */
22856 static void os2DlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
22857 /* no-op */
22858 }
22859 static void *os2DlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){
22860 PFN pfn;
22861 APIRET rc;
22862 rc = DosQueryProcAddr((HMODULE)pHandle, 0L, zSymbol, &pfn);
22863 if( rc != NO_ERROR ){
22864 /* if the symbol itself was not found, search again for the same
@@ -22866,11 +22975,11 @@
22866 * on the calling convention */
22867 char _zSymbol[256] = "_";
22868 strncat(_zSymbol, zSymbol, 255);
22869 rc = DosQueryProcAddr((HMODULE)pHandle, 0L, _zSymbol, &pfn);
22870 }
22871 return rc != NO_ERROR ? 0 : (void*)pfn;
22872 }
22873 static void os2DlClose(sqlite3_vfs *pVfs, void *pHandle){
22874 DosFreeModule((HMODULE)pHandle);
22875 }
22876 #else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */
@@ -22970,14 +23079,15 @@
22970 ** return 0. Return 1 if the time and date cannot be found.
22971 */
22972 int os2CurrentTime( sqlite3_vfs *pVfs, double *prNow ){
22973 double now;
22974 SHORT minute; /* needs to be able to cope with negative timezone offset */
22975 USHORT second, hour,
22976 day, month, year;
22977 DATETIME dt;
22978 DosGetDateTime( &dt );
 
22979 second = (USHORT)dt.seconds;
22980 minute = (SHORT)dt.minutes + dt.timezone;
22981 hour = (USHORT)dt.hours;
22982 day = (USHORT)dt.day;
22983 month = (USHORT)dt.month;
@@ -22993,18 +23103,35 @@
22993
22994 /* Add the fractional hours, mins and seconds */
22995 now += (hour + 12.0)/24.0;
22996 now += minute/1440.0;
22997 now += second/86400.0;
 
22998 *prNow = now;
22999 #ifdef SQLITE_TEST
23000 if( sqlite3_current_time ){
23001 *prNow = sqlite3_current_time/86400.0 + 2440587.5;
23002 }
23003 #endif
23004 return 0;
23005 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23006
23007 static int os2GetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
23008 return 0;
23009 }
23010
@@ -23011,11 +23138,11 @@
23011 /*
23012 ** Initialize and deinitialize the operating system interface.
23013 */
23014 SQLITE_API int sqlite3_os_init(void){
23015 static sqlite3_vfs os2Vfs = {
23016 1, /* iVersion */
23017 sizeof(os2File), /* szOsFile */
23018 CCHMAXPATH, /* mxPathname */
23019 0, /* pNext */
23020 "os2", /* zName */
23021 0, /* pAppData */
@@ -23030,10 +23157,14 @@
23030 os2DlClose, /* xDlClose */
23031 os2Randomness, /* xRandomness */
23032 os2Sleep, /* xSleep */
23033 os2CurrentTime, /* xCurrentTime */
23034 os2GetLastError, /* xGetLastError */
 
 
 
 
23035 };
23036 sqlite3_vfs_register(&os2Vfs, 1);
23037 initUconvObjects();
23038 return SQLITE_OK;
23039 }
@@ -23249,14 +23380,14 @@
23249 sqlite3_io_methods const *pMethod; /* Always the first entry */
23250 unixInodeInfo *pInode; /* Info about locks on this inode */
23251 int h; /* The file descriptor */
23252 int dirfd; /* File descriptor for the directory */
23253 unsigned char eFileLock; /* The type of lock held on this fd */
 
23254 int lastErrno; /* The unix errno from last I/O error */
23255 void *lockingContext; /* Locking style specific state */
23256 UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */
23257 int fileFlags; /* Miscellanous flags */
23258 const char *zPath; /* Name of the file */
23259 unixShm *pShm; /* Shared memory segment information */
23260 int szChunk; /* Configured by FCNTL_CHUNK_SIZE */
23261 #if SQLITE_ENABLE_LOCKING_STYLE
23262 int openFlags; /* The flags specified at open() */
@@ -23287,13 +23418,14 @@
23287 char aPadding[32];
23288 #endif
23289 };
23290
23291 /*
23292 ** The following macros define bits in unixFile.fileFlags
23293 */
23294 #define SQLITE_WHOLE_FILE_LOCKING 0x0001 /* Use whole-file locking */
 
23295
23296 /*
23297 ** Include code that is common to all os_*.c files
23298 */
23299 /************** Include os_common.h in the middle of os_unix.c ***************/
@@ -23518,20 +23650,10 @@
23518 #endif
23519 #ifndef O_BINARY
23520 # define O_BINARY 0
23521 #endif
23522
23523 /*
23524 ** The DJGPP compiler environment looks mostly like Unix, but it
23525 ** lacks the fcntl() system call. So redefine fcntl() to be something
23526 ** that always succeeds. This means that locking does not occur under
23527 ** DJGPP. But it is DOS - what did you expect?
23528 */
23529 #ifdef __DJGPP__
23530 # define fcntl(A,B,C) 0
23531 #endif
23532
23533 /*
23534 ** The threadid macro resolves to the thread-id or to 0. Used for
23535 ** testing and debugging only.
23536 */
23537 #if SQLITE_THREADSAFE
@@ -23538,10 +23660,197 @@
23538 #define threadid pthread_self()
23539 #else
23540 #define threadid 0
23541 #endif
23542
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23543
23544 /*
23545 ** Helper functions to obtain and relinquish the global mutex. The
23546 ** global mutex is used to protect the unixInodeInfo and
23547 ** vxworksFileId objects used by this file, all of which may be
@@ -23602,11 +23911,11 @@
23602 if( op==F_GETLK ){
23603 zOpName = "GETLK";
23604 }else if( op==F_SETLK ){
23605 zOpName = "SETLK";
23606 }else{
23607 s = fcntl(fd, op, p);
23608 sqlite3DebugPrintf("fcntl unknown %d %d %d\n", fd, op, s);
23609 return s;
23610 }
23611 if( p->l_type==F_RDLCK ){
23612 zType = "RDLCK";
@@ -23616,19 +23925,19 @@
23616 zType = "UNLCK";
23617 }else{
23618 assert( 0 );
23619 }
23620 assert( p->l_whence==SEEK_SET );
23621 s = fcntl(fd, op, p);
23622 savedErrno = errno;
23623 sqlite3DebugPrintf("fcntl %d %d %s %s %d %d %d %d\n",
23624 threadid, fd, zOpName, zType, (int)p->l_start, (int)p->l_len,
23625 (int)p->l_pid, s);
23626 if( s==(-1) && op==F_SETLK && (p->l_type==F_RDLCK || p->l_type==F_WRLCK) ){
23627 struct flock l2;
23628 l2 = *p;
23629 fcntl(fd, F_GETLK, &l2);
23630 if( l2.l_type==F_RDLCK ){
23631 zType = "RDLCK";
23632 }else if( l2.l_type==F_WRLCK ){
23633 zType = "WRLCK";
23634 }else if( l2.l_type==F_UNLCK ){
@@ -23640,27 +23949,22 @@
23640 zType, (int)l2.l_start, (int)l2.l_len, (int)l2.l_pid);
23641 }
23642 errno = savedErrno;
23643 return s;
23644 }
23645 #define fcntl lockTrace
 
23646 #endif /* SQLITE_LOCK_TRACE */
23647
23648
23649 /*
23650 ** Retry ftruncate() calls that fail due to EINTR
23651 */
23652 #ifdef EINTR
23653 static int robust_ftruncate(int h, sqlite3_int64 sz){
23654 int rc;
23655 do{ rc = ftruncate(h,sz); }while( rc<0 && errno==EINTR );
23656 return rc;
23657 }
23658 #else
23659 # define robust_ftruncate(a,b) ftruncate(a,b)
23660 #endif
23661
23662
23663 /*
23664 ** This routine translates a standard POSIX errno code into something
23665 ** useful to the clients of the sqlite3 functions. Specifically, it is
23666 ** intended to translate a variety of "try again" errors into SQLITE_BUSY
@@ -23978,11 +24282,12 @@
23978 ** object keeps a count of the number of unixFile pointing to it.
23979 */
23980 struct unixInodeInfo {
23981 struct unixFileId fileId; /* The lookup key */
23982 int nShared; /* Number of SHARED locks held */
23983 int eFileLock; /* One of SHARED_LOCK, RESERVED_LOCK etc. */
 
23984 int nRef; /* Number of pointers to this structure */
23985 unixShmNode *pShmNode; /* Shared memory associated with this inode */
23986 int nLock; /* Number of outstanding file locks */
23987 UnixUnusedFd *pUnused; /* Unused file descriptors to close */
23988 unixInodeInfo *pNext; /* List of all unixInodeInfo objects */
@@ -24083,11 +24388,11 @@
24083 ** file descriptor might have already been reused by another thread.
24084 ** So we don't even try to recover from an EINTR. Just log the error
24085 ** and move on.
24086 */
24087 static void robust_close(unixFile *pFile, int h, int lineno){
24088 if( close(h) ){
24089 unixLogErrorAtLine(SQLITE_IOERR_CLOSE, "close",
24090 pFile ? pFile->zPath : 0, lineno);
24091 }
24092 }
24093
@@ -24160,11 +24465,11 @@
24160
24161 /* Get low-level information about the file that we can used to
24162 ** create a unique name for the file.
24163 */
24164 fd = pFile->h;
24165 rc = fstat(fd, &statbuf);
24166 if( rc!=0 ){
24167 pFile->lastErrno = errno;
24168 #ifdef EOVERFLOW
24169 if( pFile->lastErrno==EOVERFLOW ) return SQLITE_NOLFS;
24170 #endif
@@ -24181,16 +24486,16 @@
24181 ** in the header of every SQLite database. In this way, if there
24182 ** is a race condition such that another thread has already populated
24183 ** the first page of the database, no damage is done.
24184 */
24185 if( statbuf.st_size==0 && (pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS)!=0 ){
24186 do{ rc = write(fd, "S", 1); }while( rc<0 && errno==EINTR );
24187 if( rc!=1 ){
24188 pFile->lastErrno = errno;
24189 return SQLITE_IOERR;
24190 }
24191 rc = fstat(fd, &statbuf);
24192 if( rc!=0 ){
24193 pFile->lastErrno = errno;
24194 return SQLITE_IOERR;
24195 }
24196 }
@@ -24249,17 +24554,17 @@
24249 }
24250
24251 /* Otherwise see if some other process holds it.
24252 */
24253 #ifndef __DJGPP__
24254 if( !reserved ){
24255 struct flock lock;
24256 lock.l_whence = SEEK_SET;
24257 lock.l_start = RESERVED_BYTE;
24258 lock.l_len = 1;
24259 lock.l_type = F_WRLCK;
24260 if (-1 == fcntl(pFile->h, F_GETLK, &lock)) {
24261 int tErrno = errno;
24262 rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_CHECKRESERVEDLOCK);
24263 pFile->lastErrno = tErrno;
24264 } else if( lock.l_type!=F_UNLCK ){
24265 reserved = 1;
@@ -24271,10 +24576,54 @@
24271 OSTRACE(("TEST WR-LOCK %d %d %d (unix)\n", pFile->h, rc, reserved));
24272
24273 *pResOut = reserved;
24274 return rc;
24275 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24276
24277 /*
24278 ** Lock the file with the lock specified by parameter eFileLock - one
24279 ** of the following:
24280 **
@@ -24408,11 +24757,11 @@
24408 if( eFileLock==SHARED_LOCK
24409 || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock<PENDING_LOCK)
24410 ){
24411 lock.l_type = (eFileLock==SHARED_LOCK?F_RDLCK:F_WRLCK);
24412 lock.l_start = PENDING_BYTE;
24413 s = fcntl(pFile->h, F_SETLK, &lock);
24414 if( s==(-1) ){
24415 tErrno = errno;
24416 rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
24417 if( IS_LOCK_ERROR(rc) ){
24418 pFile->lastErrno = tErrno;
@@ -24430,18 +24779,18 @@
24430 assert( pInode->eFileLock==0 );
24431
24432 /* Now get the read-lock */
24433 lock.l_start = SHARED_FIRST;
24434 lock.l_len = SHARED_SIZE;
24435 if( (s = fcntl(pFile->h, F_SETLK, &lock))==(-1) ){
24436 tErrno = errno;
24437 }
24438 /* Drop the temporary PENDING lock */
24439 lock.l_start = PENDING_BYTE;
24440 lock.l_len = 1L;
24441 lock.l_type = F_UNLCK;
24442 if( fcntl(pFile->h, F_SETLK, &lock)!=0 ){
24443 if( s != -1 ){
24444 /* This could happen with a network mount */
24445 tErrno = errno;
24446 rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
24447 if( IS_LOCK_ERROR(rc) ){
@@ -24480,11 +24829,11 @@
24480 lock.l_len = SHARED_SIZE;
24481 break;
24482 default:
24483 assert(0);
24484 }
24485 s = fcntl(pFile->h, F_SETLK, &lock);
24486 if( s==(-1) ){
24487 tErrno = errno;
24488 rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
24489 if( IS_LOCK_ERROR(rc) ){
24490 pFile->lastErrno = tErrno;
@@ -24549,11 +24898,11 @@
24549 ** the byte range is divided into 2 parts and the first part is unlocked then
24550 ** set to a read lock, then the other part is simply unlocked. This works
24551 ** around a bug in BSD NFS lockd (also seen on MacOSX 10.3+) that fails to
24552 ** remove the write lock on a region when a read lock is set.
24553 */
24554 static int _posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
24555 unixFile *pFile = (unixFile*)id;
24556 unixInodeInfo *pInode;
24557 struct flock lock;
24558 int rc = SQLITE_OK;
24559 int h;
@@ -24605,10 +24954,11 @@
24605 ** 4: [RRRR.]
24606 */
24607 if( eFileLock==SHARED_LOCK ){
24608
24609 #if !defined(__APPLE__) || !SQLITE_ENABLE_LOCKING_STYLE
 
24610 assert( handleNFSUnlock==0 );
24611 #endif
24612 #if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
24613 if( handleNFSUnlock ){
24614 off_t divSize = SHARED_SIZE - 1;
@@ -24615,11 +24965,11 @@
24615
24616 lock.l_type = F_UNLCK;
24617 lock.l_whence = SEEK_SET;
24618 lock.l_start = SHARED_FIRST;
24619 lock.l_len = divSize;
24620 if( fcntl(h, F_SETLK, &lock)==(-1) ){
24621 tErrno = errno;
24622 rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
24623 if( IS_LOCK_ERROR(rc) ){
24624 pFile->lastErrno = tErrno;
24625 }
@@ -24627,11 +24977,11 @@
24627 }
24628 lock.l_type = F_RDLCK;
24629 lock.l_whence = SEEK_SET;
24630 lock.l_start = SHARED_FIRST;
24631 lock.l_len = divSize;
24632 if( fcntl(h, F_SETLK, &lock)==(-1) ){
24633 tErrno = errno;
24634 rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);
24635 if( IS_LOCK_ERROR(rc) ){
24636 pFile->lastErrno = tErrno;
24637 }
@@ -24639,11 +24989,11 @@
24639 }
24640 lock.l_type = F_UNLCK;
24641 lock.l_whence = SEEK_SET;
24642 lock.l_start = SHARED_FIRST+divSize;
24643 lock.l_len = SHARED_SIZE-divSize;
24644 if( fcntl(h, F_SETLK, &lock)==(-1) ){
24645 tErrno = errno;
24646 rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
24647 if( IS_LOCK_ERROR(rc) ){
24648 pFile->lastErrno = tErrno;
24649 }
@@ -24654,11 +25004,11 @@
24654 {
24655 lock.l_type = F_RDLCK;
24656 lock.l_whence = SEEK_SET;
24657 lock.l_start = SHARED_FIRST;
24658 lock.l_len = SHARED_SIZE;
24659 if( fcntl(h, F_SETLK, &lock)==(-1) ){
24660 tErrno = errno;
24661 rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);
24662 if( IS_LOCK_ERROR(rc) ){
24663 pFile->lastErrno = tErrno;
24664 }
@@ -24668,11 +25018,11 @@
24668 }
24669 lock.l_type = F_UNLCK;
24670 lock.l_whence = SEEK_SET;
24671 lock.l_start = PENDING_BYTE;
24672 lock.l_len = 2L; assert( PENDING_BYTE+1==RESERVED_BYTE );
24673 if( fcntl(h, F_SETLK, &lock)!=(-1) ){
24674 pInode->eFileLock = SHARED_LOCK;
24675 }else{
24676 tErrno = errno;
24677 rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
24678 if( IS_LOCK_ERROR(rc) ){
@@ -24692,11 +25042,11 @@
24692 lock.l_whence = SEEK_SET;
24693 lock.l_start = lock.l_len = 0L;
24694 SimulateIOErrorBenign(1);
24695 SimulateIOError( h=(-1) )
24696 SimulateIOErrorBenign(0);
24697 if( fcntl(h, F_SETLK, &lock)!=(-1) ){
24698 pInode->eFileLock = NO_LOCK;
24699 }else{
24700 tErrno = errno;
24701 rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
24702 if( IS_LOCK_ERROR(rc) ){
@@ -24730,11 +25080,11 @@
24730 **
24731 ** If the locking level of the file descriptor is already at or below
24732 ** the requested locking level, this routine is a no-op.
24733 */
24734 static int unixUnlock(sqlite3_file *id, int eFileLock){
24735 return _posixUnlock(id, eFileLock, 0);
24736 }
24737
24738 /*
24739 ** This function performs the parts of the "close file" operation
24740 ** common to all locking schemes. It closes the directory and file
@@ -24780,10 +25130,12 @@
24780 int rc = SQLITE_OK;
24781 if( id ){
24782 unixFile *pFile = (unixFile *)id;
24783 unixUnlock(id, NO_LOCK);
24784 unixEnterMutex();
 
 
24785 if( pFile->pInode && pFile->pInode->nLock ){
24786 /* If there are outstanding locks, do not actually close the file just
24787 ** yet because that would clear those locks. Instead, add the file
24788 ** descriptor to pInode->pUnused list. It will be automatically closed
24789 ** when the last lock is cleared.
@@ -24894,11 +25246,11 @@
24894 ** holds a lock on the file. No need to check further. */
24895 reserved = 1;
24896 }else{
24897 /* The lock is held if and only if the lockfile exists */
24898 const char *zLockFile = (const char*)pFile->lockingContext;
24899 reserved = access(zLockFile, 0)==0;
24900 }
24901 OSTRACE(("TEST WR-LOCK %d %d %d (dotlock)\n", pFile->h, rc, reserved));
24902 *pResOut = reserved;
24903 return rc;
24904 }
@@ -24948,11 +25300,11 @@
24948 #endif
24949 return SQLITE_OK;
24950 }
24951
24952 /* grab an exclusive lock */
24953 fd = open(zLockFile,O_RDONLY|O_CREAT|O_EXCL,0600);
24954 if( fd<0 ){
24955 /* failed to open/create the file, someone else may have stolen the lock */
24956 int tErrno = errno;
24957 if( EEXIST == tErrno ){
24958 rc = SQLITE_BUSY;
@@ -25911,11 +26263,11 @@
25911 **
25912 ** If the locking level of the file descriptor is already at or below
25913 ** the requested locking level, this routine is a no-op.
25914 */
25915 static int nfsUnlock(sqlite3_file *id, int eFileLock){
25916 return _posixUnlock(id, eFileLock, 1);
25917 }
25918
25919 #endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
25920 /*
25921 ** The code above is the NFS lock implementation. The code is specific
@@ -25953,14 +26305,14 @@
25953 #if (!defined(USE_PREAD) && !defined(USE_PREAD64))
25954 i64 newOffset;
25955 #endif
25956 TIMER_START;
25957 #if defined(USE_PREAD)
25958 do{ got = pread(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR );
25959 SimulateIOError( got = -1 );
25960 #elif defined(USE_PREAD64)
25961 do{ got = pread64(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR );
25962 SimulateIOError( got = -1 );
25963 #else
25964 newOffset = lseek(id->h, offset, SEEK_SET);
25965 SimulateIOError( newOffset-- );
25966 if( newOffset!=offset ){
@@ -25969,11 +26321,11 @@
25969 }else{
25970 ((unixFile*)id)->lastErrno = 0;
25971 }
25972 return -1;
25973 }
25974 do{ got = read(id->h, pBuf, cnt); }while( got<0 && errno==EINTR );
25975 #endif
25976 TIMER_END;
25977 if( got<0 ){
25978 ((unixFile*)id)->lastErrno = errno;
25979 }
@@ -26031,13 +26383,13 @@
26031 #if (!defined(USE_PREAD) && !defined(USE_PREAD64))
26032 i64 newOffset;
26033 #endif
26034 TIMER_START;
26035 #if defined(USE_PREAD)
26036 do{ got = pwrite(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR );
26037 #elif defined(USE_PREAD64)
26038 do{ got = pwrite64(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR );
26039 #else
26040 newOffset = lseek(id->h, offset, SEEK_SET);
26041 if( newOffset!=offset ){
26042 if( newOffset == -1 ){
26043 ((unixFile*)id)->lastErrno = errno;
@@ -26044,11 +26396,11 @@
26044 }else{
26045 ((unixFile*)id)->lastErrno = 0;
26046 }
26047 return -1;
26048 }
26049 do{ got = write(id->h, pBuf, cnt); }while( got<0 && errno==EINTR );
26050 #endif
26051 TIMER_END;
26052 if( got<0 ){
26053 ((unixFile*)id)->lastErrno = errno;
26054 }
@@ -26212,11 +26564,11 @@
26212 */
26213 #ifdef SQLITE_NO_SYNC
26214 rc = SQLITE_OK;
26215 #elif HAVE_FULLFSYNC
26216 if( fullSync ){
26217 rc = fcntl(fd, F_FULLFSYNC, 0);
26218 }else{
26219 rc = 1;
26220 }
26221 /* If the FULLFSYNC failed, fall back to attempting an fsync().
26222 ** It shouldn't be possible for fullfsync to fail on the local
@@ -26359,11 +26711,11 @@
26359 */
26360 static int unixFileSize(sqlite3_file *id, i64 *pSize){
26361 int rc;
26362 struct stat buf;
26363 assert( id );
26364 rc = fstat(((unixFile*)id)->h, &buf);
26365 SimulateIOError( rc=1 );
26366 if( rc!=0 ){
26367 ((unixFile*)id)->lastErrno = errno;
26368 return SQLITE_IOERR_FSTAT;
26369 }
@@ -26400,18 +26752,18 @@
26400 static int fcntlSizeHint(unixFile *pFile, i64 nByte){
26401 if( pFile->szChunk ){
26402 i64 nSize; /* Required file size */
26403 struct stat buf; /* Used to hold return values of fstat() */
26404
26405 if( fstat(pFile->h, &buf) ) return SQLITE_IOERR_FSTAT;
26406
26407 nSize = ((nByte+pFile->szChunk-1) / pFile->szChunk) * pFile->szChunk;
26408 if( nSize>(i64)buf.st_size ){
26409 #if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
26410 int rc;
26411 do{
26412 rc = posix_fallocate(pFile-.h, buf.st_size, nSize-buf.st_size;
26413 }while( rc<0 && errno=EINTR );
26414 if( rc ) return SQLITE_IOERR_WRITE;
26415 #else
26416 /* If the OS does not have posix_fallocate(), fake it. First use
26417 ** ftruncate() to set the file size, then write a single byte to
@@ -26608,19 +26960,21 @@
26608 assert( n==1 || lockType!=F_RDLCK );
26609
26610 /* Locks are within range */
26611 assert( n>=1 && n<SQLITE_SHM_NLOCK );
26612
26613 /* Initialize the locking parameters */
26614 memset(&f, 0, sizeof(f));
26615 f.l_type = lockType;
26616 f.l_whence = SEEK_SET;
26617 f.l_start = ofst;
26618 f.l_len = n;
26619
26620 rc = fcntl(pShmNode->h, F_SETLK, &f);
26621 rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY;
 
 
26622
26623 /* Update the global lock state and do debug tracing */
26624 #ifdef SQLITE_DEBUG
26625 { u16 mask;
26626 OSTRACE(("SHM-LOCK "));
@@ -26671,11 +27025,15 @@
26671 if( p && p->nRef==0 ){
26672 int i;
26673 assert( p->pInode==pFd->pInode );
26674 if( p->mutex ) sqlite3_mutex_free(p->mutex);
26675 for(i=0; i<p->nRegion; i++){
26676 munmap(p->apRegion[i], p->szRegion);
 
 
 
 
26677 }
26678 sqlite3_free(p->apRegion);
26679 if( p->h>=0 ){
26680 robust_close(pFd, p->h, __LINE__);
26681 p->h = -1;
@@ -26711,10 +27069,16 @@
26711 ** "unsupported" and may go away in a future SQLite release.
26712 **
26713 ** When opening a new shared-memory file, if no other instances of that
26714 ** file are currently open, in this process or in other processes, then
26715 ** the file must be truncated to zero length or have its header cleared.
 
 
 
 
 
 
26716 */
26717 static int unixOpenSharedMemory(unixFile *pDbFd){
26718 struct unixShm *p = 0; /* The connection to be opened */
26719 struct unixShmNode *pShmNode; /* The underlying mmapped file */
26720 int rc; /* Result code */
@@ -26740,11 +27104,11 @@
26740 /* Call fstat() to figure out the permissions on the database file. If
26741 ** a new *-shm file is created, an attempt will be made to create it
26742 ** with the same permissions. The actual permissions the file is created
26743 ** with are subject to the current umask setting.
26744 */
26745 if( fstat(pDbFd->h, &sStat) ){
26746 rc = SQLITE_IOERR_FSTAT;
26747 goto shm_open_err;
26748 }
26749
26750 #ifdef SQLITE_SHM_DIRECTORY
@@ -26773,29 +27137,32 @@
26773 if( pShmNode->mutex==0 ){
26774 rc = SQLITE_NOMEM;
26775 goto shm_open_err;
26776 }
26777
26778 pShmNode->h = open(zShmFilename, O_RDWR|O_CREAT, (sStat.st_mode & 0777));
26779 if( pShmNode->h<0 ){
26780 rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename);
26781 goto shm_open_err;
26782 }
26783
26784 /* Check to see if another process is holding the dead-man switch.
26785 ** If not, truncate the file to zero length.
26786 */
26787 rc = SQLITE_OK;
26788 if( unixShmSystemLock(pShmNode, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){
26789 if( robust_ftruncate(pShmNode->h, 0) ){
26790 rc = unixLogError(SQLITE_IOERR_SHMOPEN, "ftruncate", zShmFilename);
26791 }
26792 }
26793 if( rc==SQLITE_OK ){
26794 rc = unixShmSystemLock(pShmNode, F_RDLCK, UNIX_SHM_DMS, 1);
26795 }
26796 if( rc ) goto shm_open_err;
 
 
 
26797 }
26798
26799 /* Make the new connection a child of the unixShmNode */
26800 p->pShmNode = pShmNode;
26801 #ifdef SQLITE_DEBUG
@@ -26865,38 +27232,44 @@
26865
26866 p = pDbFd->pShm;
26867 pShmNode = p->pShmNode;
26868 sqlite3_mutex_enter(pShmNode->mutex);
26869 assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
 
 
 
26870
26871 if( pShmNode->nRegion<=iRegion ){
26872 char **apNew; /* New apRegion[] array */
26873 int nByte = (iRegion+1)*szRegion; /* Minimum required file size */
26874 struct stat sStat; /* Used by fstat() */
26875
26876 pShmNode->szRegion = szRegion;
26877
26878 /* The requested region is not mapped into this processes address space.
26879 ** Check to see if it has been allocated (i.e. if the wal-index file is
26880 ** large enough to contain the requested region).
26881 */
26882 if( fstat(pShmNode->h, &sStat) ){
26883 rc = SQLITE_IOERR_SHMSIZE;
26884 goto shmpage_out;
26885 }
26886
26887 if( sStat.st_size<nByte ){
26888 /* The requested memory region does not exist. If bExtend is set to
26889 ** false, exit early. *pp will be set to NULL and SQLITE_OK returned.
26890 **
26891 ** Alternatively, if bExtend is true, use ftruncate() to allocate
26892 ** the requested memory region.
26893 */
26894 if( !bExtend ) goto shmpage_out;
26895 if( robust_ftruncate(pShmNode->h, nByte) ){
26896 rc = unixLogError(SQLITE_IOERR_SHMSIZE,"ftruncate",pShmNode->zFilename);
26897 goto shmpage_out;
 
 
 
26898 }
26899 }
26900
26901 /* Map the requested memory region into this processes address space. */
26902 apNew = (char **)sqlite3_realloc(
@@ -26906,16 +27279,26 @@
26906 rc = SQLITE_IOERR_NOMEM;
26907 goto shmpage_out;
26908 }
26909 pShmNode->apRegion = apNew;
26910 while(pShmNode->nRegion<=iRegion){
26911 void *pMem = mmap(0, szRegion, PROT_READ|PROT_WRITE,
26912 MAP_SHARED, pShmNode->h, pShmNode->nRegion*szRegion
26913 );
26914 if( pMem==MAP_FAILED ){
26915 rc = SQLITE_IOERR;
26916 goto shmpage_out;
 
 
 
 
 
 
 
 
 
 
26917 }
26918 pShmNode->apRegion[pShmNode->nRegion] = pMem;
26919 pShmNode->nRegion++;
26920 }
26921 }
@@ -26958,10 +27341,12 @@
26958 assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED)
26959 || flags==(SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE)
26960 || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED)
26961 || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
26962 assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
 
 
26963
26964 mask = (1<<(ofst+n)) - (1<<ofst);
26965 assert( n>1 || mask==(1<<ofst) );
26966 sqlite3_mutex_enter(pShmNode->mutex);
26967 if( flags & SQLITE_SHM_UNLOCK ){
@@ -27095,11 +27480,11 @@
27095 ** shared-memory file, too */
27096 unixEnterMutex();
27097 assert( pShmNode->nRef>0 );
27098 pShmNode->nRef--;
27099 if( pShmNode->nRef==0 ){
27100 if( deleteFlag ) unlink(pShmNode->zFilename);
27101 unixShmPurge(pDbFd);
27102 }
27103 unixLeaveMutex();
27104
27105 return SQLITE_OK;
@@ -27336,11 +27721,11 @@
27336 */
27337 lockInfo.l_len = 1;
27338 lockInfo.l_start = 0;
27339 lockInfo.l_whence = SEEK_SET;
27340 lockInfo.l_type = F_RDLCK;
27341 if( fcntl(pNew->h, F_GETLK, &lockInfo)!=-1 ) {
27342 if( strcmp(fsInfo.f_fstypename, "nfs")==0 ){
27343 return &nfsIoMethods;
27344 } else {
27345 return &posixIoMethods;
27346 }
@@ -27378,11 +27763,11 @@
27378 */
27379 lockInfo.l_len = 1;
27380 lockInfo.l_start = 0;
27381 lockInfo.l_whence = SEEK_SET;
27382 lockInfo.l_type = F_RDLCK;
27383 if( fcntl(pNew->h, F_GETLK, &lockInfo)!=-1 ) {
27384 return &posixIoMethods;
27385 }else{
27386 return &semIoMethods;
27387 }
27388 }
@@ -27412,11 +27797,12 @@
27412 int h, /* Open file descriptor of file being opened */
27413 int dirfd, /* Directory file descriptor */
27414 sqlite3_file *pId, /* Write to the unixFile structure here */
27415 const char *zFilename, /* Name of the file being opened */
27416 int noLock, /* Omit locking if true */
27417 int isDelete /* Delete on close if true */
 
27418 ){
27419 const sqlite3_io_methods *pLockingStyle;
27420 unixFile *pNew = (unixFile *)pId;
27421 int rc = SQLITE_OK;
27422
@@ -27439,12 +27825,19 @@
27439 #endif
27440
27441 OSTRACE(("OPEN %-3d %s\n", h, zFilename));
27442 pNew->h = h;
27443 pNew->dirfd = dirfd;
27444 pNew->fileFlags = 0;
27445 pNew->zPath = zFilename;
 
 
 
 
 
 
 
 
27446
27447 #if OS_VXWORKS
27448 pNew->pId = vxworksFindFileId(zFilename);
27449 if( pNew->pId==0 ){
27450 noLock = 1;
@@ -27601,14 +27994,14 @@
27601
27602 sqlite3_snprintf(MAX_PATHNAME, zDirname, "%s", zFilename);
27603 for(ii=(int)strlen(zDirname); ii>1 && zDirname[ii]!='/'; ii--);
27604 if( ii>0 ){
27605 zDirname[ii] = '\0';
27606 fd = open(zDirname, O_RDONLY|O_BINARY, 0);
27607 if( fd>=0 ){
27608 #ifdef FD_CLOEXEC
27609 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
27610 #endif
27611 OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname));
27612 }
27613 }
27614 *pFd = fd;
@@ -27634,13 +28027,13 @@
27634
27635 azDirs[0] = sqlite3_temp_directory;
27636 if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR");
27637 for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); zDir=azDirs[i++]){
27638 if( zDir==0 ) continue;
27639 if( stat(zDir, &buf) ) continue;
27640 if( !S_ISDIR(buf.st_mode) ) continue;
27641 if( access(zDir, 07) ) continue;
27642 break;
27643 }
27644 return zDir;
27645 }
27646
@@ -27679,11 +28072,11 @@
27679 sqlite3_randomness(15, &zBuf[j]);
27680 for(i=0; i<15; i++, j++){
27681 zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
27682 }
27683 zBuf[j] = 0;
27684 }while( access(zBuf,0)==0 );
27685 return SQLITE_OK;
27686 }
27687
27688 #if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
27689 /*
@@ -27940,19 +28333,20 @@
27940 if( rc!=SQLITE_OK ){
27941 assert( !p->pUnused );
27942 assert( eType==SQLITE_OPEN_WAL || eType==SQLITE_OPEN_MAIN_JOURNAL );
27943 return rc;
27944 }
27945 fd = open(zName, openFlags, openMode);
27946 OSTRACE(("OPENX %-3d %s 0%o\n", fd, zName, openFlags));
27947 if( fd<0 && errno!=EISDIR && isReadWrite && !isExclusive ){
27948 /* Failed to open the file for read/write access. Try read-only. */
27949 flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
27950 openFlags &= ~(O_RDWR|O_CREAT);
27951 flags |= SQLITE_OPEN_READONLY;
27952 openFlags |= O_RDONLY;
27953 fd = open(zName, openFlags, openMode);
 
27954 }
27955 if( fd<0 ){
27956 rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
27957 goto open_finished;
27958 }
@@ -27992,11 +28386,11 @@
27992 goto open_finished;
27993 }
27994 }
27995
27996 #ifdef FD_CLOEXEC
27997 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
27998 #endif
27999
28000 noLock = eType!=SQLITE_OPEN_MAIN_DB;
28001
28002
@@ -28044,11 +28438,12 @@
28044 goto open_finished;
28045 }
28046 useProxy = !(fsInfo.f_flags&MNT_LOCAL);
28047 }
28048 if( useProxy ){
28049 rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock, isDelete);
 
28050 if( rc==SQLITE_OK ){
28051 rc = proxyTransformUnixFile((unixFile*)pFile, ":auto:");
28052 if( rc!=SQLITE_OK ){
28053 /* Use unixClose to clean up the resources added in fillInUnixFile
28054 ** and clear all the structure's references. Specifically,
@@ -28061,11 +28456,12 @@
28061 goto open_finished;
28062 }
28063 }
28064 #endif
28065
28066 rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock, isDelete);
 
28067 open_finished:
28068 if( rc!=SQLITE_OK ){
28069 sqlite3_free(p->pUnused);
28070 }
28071 return rc;
@@ -28138,11 +28534,11 @@
28138 break;
28139
28140 default:
28141 assert(!"Invalid flags argument");
28142 }
28143 *pResOut = (access(zPath, amode)==0);
28144 if( flags==SQLITE_ACCESS_EXISTS && *pResOut ){
28145 struct stat buf;
28146 if( 0==stat(zPath, &buf) && buf.st_size==0 ){
28147 *pResOut = 0;
28148 }
@@ -28180,11 +28576,11 @@
28180 zOut[nOut-1] = '\0';
28181 if( zPath[0]=='/' ){
28182 sqlite3_snprintf(nOut, zOut, "%s", zPath);
28183 }else{
28184 int nCwd;
28185 if( getcwd(zOut, nOut-1)==0 ){
28186 return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath);
28187 }
28188 nCwd = (int)strlen(zOut);
28189 sqlite3_snprintf(nOut-nCwd, &zOut[nCwd], "/%s", zPath);
28190 }
@@ -28275,21 +28671,21 @@
28275 */
28276 memset(zBuf, 0, nBuf);
28277 #if !defined(SQLITE_TEST)
28278 {
28279 int pid, fd;
28280 fd = open("/dev/urandom", O_RDONLY);
28281 if( fd<0 ){
28282 time_t t;
28283 time(&t);
28284 memcpy(zBuf, &t, sizeof(t));
28285 pid = getpid();
28286 memcpy(&zBuf[sizeof(t)], &pid, sizeof(pid));
28287 assert( sizeof(t)+sizeof(pid)<=(size_t)nBuf );
28288 nBuf = sizeof(t) + sizeof(pid);
28289 }else{
28290 do{ nBuf = read(fd, zBuf, nBuf); }while( nBuf<0 && errno==EINTR );
28291 robust_close(0, fd, __LINE__);
28292 }
28293 }
28294 #endif
28295 return nBuf;
@@ -28684,21 +29080,21 @@
28684 if( !pUnused ){
28685 return SQLITE_NOMEM;
28686 }
28687 }
28688 if( fd<0 ){
28689 fd = open(path, openFlags, SQLITE_DEFAULT_FILE_PERMISSIONS);
28690 terrno = errno;
28691 if( fd<0 && errno==ENOENT && islockfile ){
28692 if( proxyCreateLockPath(path) == SQLITE_OK ){
28693 fd = open(path, openFlags, SQLITE_DEFAULT_FILE_PERMISSIONS);
28694 }
28695 }
28696 }
28697 if( fd<0 ){
28698 openFlags = O_RDONLY;
28699 fd = open(path, openFlags, SQLITE_DEFAULT_FILE_PERMISSIONS);
28700 terrno = errno;
28701 }
28702 if( fd<0 ){
28703 if( islockfile ){
28704 return SQLITE_BUSY;
@@ -28723,11 +29119,11 @@
28723 dummyVfs.pAppData = (void*)&autolockIoFinder;
28724 pUnused->fd = fd;
28725 pUnused->flags = openFlags;
28726 pNew->pUnused = pUnused;
28727
28728 rc = fillInUnixFile(&dummyVfs, fd, dirfd, (sqlite3_file*)pNew, path, 0, 0);
28729 if( rc==SQLITE_OK ){
28730 *ppFile = pNew;
28731 return SQLITE_OK;
28732 }
28733 end_create_proxy:
@@ -28808,22 +29204,23 @@
28808 (strlcpy(&tPath[pathLen-5], "break", 6) != 5) ){
28809 sqlite3_snprintf(sizeof(errmsg),errmsg,"path error (len %d)",(int)pathLen);
28810 goto end_breaklock;
28811 }
28812 /* read the conch content */
28813 readLen = pread(conchFile->h, buf, PROXY_MAXCONCHLEN, 0);
28814 if( readLen<PROXY_PATHINDEX ){
28815 sqlite3_snprintf(sizeof(errmsg),errmsg,"read error (len %d)",(int)readLen);
28816 goto end_breaklock;
28817 }
28818 /* write it out to the temporary break file */
28819 fd = open(tPath, (O_RDWR|O_CREAT|O_EXCL), SQLITE_DEFAULT_FILE_PERMISSIONS);
 
28820 if( fd<0 ){
28821 sqlite3_snprintf(sizeof(errmsg), errmsg, "create failed (%d)", errno);
28822 goto end_breaklock;
28823 }
28824 if( pwrite(fd, buf, readLen, 0) != (ssize_t)readLen ){
28825 sqlite3_snprintf(sizeof(errmsg), errmsg, "write failed (%d)", errno);
28826 goto end_breaklock;
28827 }
28828 if( rename(tPath, cPath) ){
28829 sqlite3_snprintf(sizeof(errmsg), errmsg, "rename failed (%d)", errno);
@@ -28865,11 +29262,11 @@
28865 * 2nd try: fail if the mod time changed or host id is different, wait
28866 * 10 sec and try again
28867 * 3rd try: break the lock unless the mod time has changed.
28868 */
28869 struct stat buf;
28870 if( fstat(conchFile->h, &buf) ){
28871 pFile->lastErrno = errno;
28872 return SQLITE_IOERR_LOCK;
28873 }
28874
28875 if( nTries==1 ){
@@ -28884,11 +29281,11 @@
28884 return SQLITE_BUSY;
28885 }
28886
28887 if( nTries==2 ){
28888 char tBuf[PROXY_MAXCONCHLEN];
28889 int len = pread(conchFile->h, tBuf, PROXY_MAXCONCHLEN, 0);
28890 if( len<0 ){
28891 pFile->lastErrno = errno;
28892 return SQLITE_IOERR_LOCK;
28893 }
28894 if( len>PROXY_PATHINDEX && tBuf[0]==(char)PROXY_CONCHVERSION){
@@ -29054,20 +29451,20 @@
29054 /* If we created a new conch file (not just updated the contents of a
29055 ** valid conch file), try to match the permissions of the database
29056 */
29057 if( rc==SQLITE_OK && createConch ){
29058 struct stat buf;
29059 int err = fstat(pFile->h, &buf);
29060 if( err==0 ){
29061 mode_t cmode = buf.st_mode&(S_IRUSR|S_IWUSR | S_IRGRP|S_IWGRP |
29062 S_IROTH|S_IWOTH);
29063 /* try to match the database file R/W permissions, ignore failure */
29064 #ifndef SQLITE_PROXY_DEBUG
29065 fchmod(conchFile->h, cmode);
29066 #else
29067 do{
29068 rc = fchmod(conchFile->h, cmode);
29069 }while( rc==(-1) && errno==EINTR );
29070 if( rc!=0 ){
29071 int code = errno;
29072 fprintf(stderr, "fchmod %o FAILED with %d %s\n",
29073 cmode, code, strerror(code));
@@ -29089,11 +29486,11 @@
29089 if( rc==SQLITE_OK && pFile->openFlags ){
29090 if( pFile->h>=0 ){
29091 robust_close(pFile, pFile->h, __LINE__);
29092 }
29093 pFile->h = -1;
29094 int fd = open(pCtx->dbPath, pFile->openFlags,
29095 SQLITE_DEFAULT_FILE_PERMISSIONS);
29096 OSTRACE(("TRANSPROXY: OPEN %d\n", fd));
29097 if( fd>=0 ){
29098 pFile->h = fd;
29099 }else{
@@ -29315,11 +29712,11 @@
29315 */
29316 struct statfs fsInfo;
29317 struct stat conchInfo;
29318 int goLockless = 0;
29319
29320 if( stat(pCtx->conchFilePath, &conchInfo) == -1 ) {
29321 int err = errno;
29322 if( (err==ENOENT) && (statfs(dbPath, &fsInfo) != -1) ){
29323 goLockless = (fsInfo.f_flags&MNT_RDONLY) == MNT_RDONLY;
29324 }
29325 }
@@ -29600,11 +29997,11 @@
29600 ** more than that; it looks at the filesystem type that hosts the
29601 ** database file and tries to choose an locking method appropriate for
29602 ** that filesystem time.
29603 */
29604 #define UNIXVFS(VFSNAME, FINDER) { \
29605 2, /* iVersion */ \
29606 sizeof(unixFile), /* szOsFile */ \
29607 MAX_PATHNAME, /* mxPathname */ \
29608 0, /* pNext */ \
29609 VFSNAME, /* zName */ \
29610 (void*)&FINDER, /* pAppData */ \
@@ -29619,10 +30016,13 @@
29619 unixRandomness, /* xRandomness */ \
29620 unixSleep, /* xSleep */ \
29621 unixCurrentTime, /* xCurrentTime */ \
29622 unixGetLastError, /* xGetLastError */ \
29623 unixCurrentTimeInt64, /* xCurrentTimeInt64 */ \
 
 
 
29624 }
29625
29626 /*
29627 ** All default VFSes for unix are contained in the following array.
29628 **
@@ -29636,10 +30036,11 @@
29636 #else
29637 UNIXVFS("unix", posixIoFinder ),
29638 #endif
29639 UNIXVFS("unix-none", nolockIoFinder ),
29640 UNIXVFS("unix-dotfile", dotlockIoFinder ),
 
29641 #if OS_VXWORKS
29642 UNIXVFS("unix-namedsem", semIoFinder ),
29643 #endif
29644 #if SQLITE_ENABLE_LOCKING_STYLE
29645 UNIXVFS("unix-posix", posixIoFinder ),
@@ -32626,11 +33027,11 @@
32626 /*
32627 ** Initialize and deinitialize the operating system interface.
32628 */
32629 SQLITE_API int sqlite3_os_init(void){
32630 static sqlite3_vfs winVfs = {
32631 2, /* iVersion */
32632 sizeof(winFile), /* szOsFile */
32633 MAX_PATH, /* mxPathname */
32634 0, /* pNext */
32635 "win32", /* zName */
32636 0, /* pAppData */
@@ -32645,10 +33046,13 @@
32645 winRandomness, /* xRandomness */
32646 winSleep, /* xSleep */
32647 winCurrentTime, /* xCurrentTime */
32648 winGetLastError, /* xGetLastError */
32649 winCurrentTimeInt64, /* xCurrentTimeInt64 */
 
 
 
32650 };
32651
32652 #ifndef SQLITE_OMIT_WAL
32653 /* get memory map allocation granularity */
32654 memset(&winSysInfo, 0, sizeof(SYSTEM_INFO));
@@ -50782,15 +51186,13 @@
50782 }
50783 if( nearby>0 ){
50784 u32 i;
50785 int dist;
50786 closest = 0;
50787 dist = get4byte(&aData[8]) - nearby;
50788 if( dist<0 ) dist = -dist;
50789 for(i=1; i<k; i++){
50790 int d2 = get4byte(&aData[8+i*4]) - nearby;
50791 if( d2<0 ) d2 = -d2;
50792 if( d2<dist ){
50793 closest = i;
50794 dist = d2;
50795 }
50796 }
@@ -55777,13 +56179,18 @@
55777 }
55778 }else if( op==TK_UMINUS ) {
55779 /* This branch happens for multiple negative signs. Ex: -(-5) */
55780 if( SQLITE_OK==sqlite3ValueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal) ){
55781 sqlite3VdbeMemNumerify(pVal);
55782 pVal->u.i = -1 * pVal->u.i;
55783 /* (double)-1 In case of SQLITE_OMIT_FLOATING_POINT... */
55784 pVal->r = (double)-1 * pVal->r;
 
 
 
 
 
55785 sqlite3ValueApplyAffinity(pVal, affinity, enc);
55786 }
55787 }else if( op==TK_NULL ){
55788 pVal = sqlite3ValueNew(db);
55789 if( pVal==0 ) goto no_mem;
@@ -56805,12 +57212,12 @@
56805 ** will be used so that it can acquire mutexes on them all in sorted
56806 ** order (via sqlite3VdbeMutexArrayEnter(). Mutexes are acquired
56807 ** in order (and released in reverse order) to avoid deadlocks.
56808 */
56809 SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe *p, int i){
56810 int mask;
56811 assert( i>=0 && i<p->db->nDb && i<sizeof(u32)*8 );
56812 assert( i<(int)sizeof(p->btreeMask)*8 );
56813 mask = ((u32)1)<<i;
56814 if( (p->btreeMask & mask)==0 ){
56815 p->btreeMask |= mask;
56816 sqlite3BtreeMutexArrayInsert(&p->aMutex, p->db->aDb[i].pBt);
@@ -61309,10 +61716,11 @@
61309 struct OP_SetCookie_stack_vars {
61310 Db *pDb;
61311 } au;
61312 struct OP_VerifyCookie_stack_vars {
61313 int iMeta;
 
61314 Btree *pBt;
61315 } av;
61316 struct OP_OpenWrite_stack_vars {
61317 int nField;
61318 KeyInfo *pKeyInfo;
@@ -63931,14 +64339,16 @@
63931 p->expired = 0;
63932 }
63933 break;
63934 }
63935
63936 /* Opcode: VerifyCookie P1 P2 *
63937 **
63938 ** Check the value of global database parameter number 0 (the
63939 ** schema version) and make sure it is equal to P2.
 
 
63940 ** P1 is the database number which is 0 for the main database file
63941 ** and 1 for the file holding temporary tables and some higher number
63942 ** for auxiliary databases.
63943 **
63944 ** The cookie changes its value whenever the database schema changes.
@@ -63950,21 +64360,24 @@
63950 ** invoked.
63951 */
63952 case OP_VerifyCookie: {
63953 #if 0 /* local variables moved into u.av */
63954 int iMeta;
 
63955 Btree *pBt;
63956 #endif /* local variables moved into u.av */
 
63957 assert( pOp->p1>=0 && pOp->p1<db->nDb );
63958 assert( (p->btreeMask & (1<<pOp->p1))!=0 );
63959 u.av.pBt = db->aDb[pOp->p1].pBt;
63960 if( u.av.pBt ){
63961 sqlite3BtreeGetMeta(u.av.pBt, BTREE_SCHEMA_VERSION, (u32 *)&u.av.iMeta);
 
63962 }else{
63963 u.av.iMeta = 0;
63964 }
63965 if( u.av.iMeta!=pOp->p2 ){
63966 sqlite3DbFree(db, p->zErrMsg);
63967 p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed");
63968 /* If the schema-cookie from the database file matches the cookie
63969 ** stored with the in-memory representation of the schema, do
63970 ** not reload the schema from the database file.
@@ -65694,18 +66107,14 @@
65694 rc = sqlite3BtreeCreateTable(u.bt.pDb->pBt, &u.bt.pgno, u.bt.flags);
65695 pOut->u.i = u.bt.pgno;
65696 break;
65697 }
65698
65699 /* Opcode: ParseSchema P1 P2 * P4 *
65700 **
65701 ** Read and parse all entries from the SQLITE_MASTER table of database P1
65702 ** that match the WHERE clause P4. P2 is the "force" flag. Always do
65703 ** the parsing if P2 is true. If P2 is false, then this routine is a
65704 ** no-op if the schema is not currently loaded. In other words, if P2
65705 ** is false, the SQLITE_MASTER table is only parsed if the rest of the
65706 ** schema is already loaded into the symbol table.
65707 **
65708 ** This opcode invokes the parser to create a new virtual machine,
65709 ** then runs the new virtual machine. It is thus a re-entrant opcode.
65710 */
65711 case OP_ParseSchema: {
@@ -65717,18 +66126,11 @@
65717 #endif /* local variables moved into u.bu */
65718
65719 u.bu.iDb = pOp->p1;
65720 assert( u.bu.iDb>=0 && u.bu.iDb<db->nDb );
65721
65722 /* If pOp->p2 is 0, then this opcode is being executed to read a
65723 ** single row, for example the row corresponding to a new index
65724 ** created by this VDBE, from the sqlite_master table. It only
65725 ** does this if the corresponding in-memory schema is currently
65726 ** loaded. Otherwise, the new index definition can be loaded along
65727 ** with the rest of the schema when it is required.
65728 **
65729 ** Although the mutex on the BtShared object that corresponds to
65730 ** database u.bu.iDb (the database containing the sqlite_master table
65731 ** read by this instruction) is currently held, it is necessary to
65732 ** obtain the mutexes on all attached databases before checking if
65733 ** the schema of u.bu.iDb is loaded. This is because, at the start of
65734 ** the sqlite3_exec() call below, SQLite will invoke
@@ -65740,11 +66142,11 @@
65740 ** can result in a "no such table: sqlite_master" or "malformed
65741 ** database schema" error being returned to the user.
65742 */
65743 assert( sqlite3BtreeHoldsMutex(db->aDb[u.bu.iDb].pBt) );
65744 sqlite3BtreeEnterAll(db);
65745 if( pOp->p2 || DbHasProperty(db, u.bu.iDb, DB_SchemaLoaded) ){
65746 u.bu.zMaster = SCHEMA_TABLE(u.bu.iDb);
65747 u.bu.initData.db = db;
65748 u.bu.initData.iDb = pOp->p1;
65749 u.bu.initData.pzErrMsg = &p->zErrMsg;
65750 u.bu.zSql = sqlite3MPrintf(db,
@@ -67395,10 +67797,11 @@
67395 sqlite3VdbeChangeP2(v, 0, flags);
67396
67397 /* Configure the OP_VerifyCookie */
67398 sqlite3VdbeChangeP1(v, 1, iDb);
67399 sqlite3VdbeChangeP2(v, 1, pTab->pSchema->schema_cookie);
 
67400
67401 /* Make sure a mutex is held on the table to be accessed */
67402 sqlite3VdbeUsesBtree(v, iDb);
67403
67404 /* Configure the OP_TableLock instruction */
@@ -69826,10 +70229,11 @@
69826
69827 if( pToken ){
69828 if( op!=TK_INTEGER || pToken->z==0
69829 || sqlite3GetInt32(pToken->z, &iValue)==0 ){
69830 nExtra = pToken->n+1;
 
69831 }
69832 }
69833 pNew = sqlite3DbMallocZero(db, sizeof(Expr)+nExtra);
69834 if( pNew ){
69835 pNew->op = (u8)op;
@@ -70051,10 +70455,12 @@
70051 /*
70052 ** Recursively delete an expression tree.
70053 */
70054 SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3 *db, Expr *p){
70055 if( p==0 ) return;
 
 
70056 if( !ExprHasAnyProperty(p, EP_TokenOnly) ){
70057 sqlite3ExprDelete(db, p->pLeft);
70058 sqlite3ExprDelete(db, p->pRight);
70059 if( !ExprHasProperty(p, EP_Reduced) && (p->flags2 & EP2_MallocedToken)!=0 ){
70060 sqlite3DbFree(db, p->u.zToken);
@@ -70660,17 +71066,10 @@
70660 }
70661 break;
70662 }
70663 default: break;
70664 }
70665 if( rc ){
70666 assert( ExprHasAnyProperty(p, EP_Reduced|EP_TokenOnly)
70667 || (p->flags2 & EP2_MallocedToken)==0 );
70668 p->op = TK_INTEGER;
70669 p->flags |= EP_IntValue;
70670 p->u.iValue = *pValue;
70671 }
70672 return rc;
70673 }
70674
70675 /*
70676 ** Return FALSE if there is no chance that the expression can be NULL.
@@ -71391,10 +71790,11 @@
71391 */
71392 static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
71393 Vdbe *v = pParse->pVdbe;
71394 if( pExpr->flags & EP_IntValue ){
71395 int i = pExpr->u.iValue;
 
71396 if( negFlag ) i = -i;
71397 sqlite3VdbeAddOp2(v, OP_Integer, i, iMem);
71398 }else{
71399 int c;
71400 i64 value;
@@ -75655,19 +76055,21 @@
75655 ** set for each database that is used. Generate code to start a
75656 ** transaction on each used database and to verify the schema cookie
75657 ** on each used database.
75658 */
75659 if( pParse->cookieGoto>0 ){
75660 u32 mask;
75661 int iDb;
75662 sqlite3VdbeJumpHere(v, pParse->cookieGoto-1);
75663 for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){
75664 if( (mask & pParse->cookieMask)==0 ) continue;
75665 sqlite3VdbeUsesBtree(v, iDb);
75666 sqlite3VdbeAddOp2(v,OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
75667 if( db->init.busy==0 ){
75668 sqlite3VdbeAddOp2(v,OP_VerifyCookie, iDb, pParse->cookieValue[iDb]);
 
 
75669 }
75670 }
75671 #ifndef SQLITE_OMIT_VIRTUALTABLE
75672 {
75673 int i;
@@ -75873,11 +76275,11 @@
75873 int len;
75874 Hash *pHash = &db->aDb[iDb].pSchema->idxHash;
75875
75876 len = sqlite3Strlen30(zIdxName);
75877 pIndex = sqlite3HashInsert(pHash, zIdxName, len, 0);
75878 if( pIndex ){
75879 if( pIndex->pTable->pIndex==pIndex ){
75880 pIndex->pTable->pIndex = pIndex->pNext;
75881 }else{
75882 Index *p;
75883 /* Justification of ALWAYS(); The index must be on the list of
@@ -78949,16 +79351,16 @@
78949 if( v==0 ) return; /* This only happens if there was a prior error */
78950 pToplevel->cookieGoto = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0)+1;
78951 }
78952 if( iDb>=0 ){
78953 sqlite3 *db = pToplevel->db;
78954 int mask;
78955
78956 assert( iDb<db->nDb );
78957 assert( db->aDb[iDb].pBt!=0 || iDb==1 );
78958 assert( iDb<SQLITE_MAX_ATTACHED+2 );
78959 mask = 1<<iDb;
78960 if( (pToplevel->cookieMask & mask)==0 ){
78961 pToplevel->cookieMask |= mask;
78962 pToplevel->cookieValue[iDb] = db->aDb[iDb].pSchema->schema_cookie;
78963 if( !OMIT_TEMPDB && iDb==1 ){
78964 sqlite3OpenTempDatabase(pToplevel);
@@ -78981,11 +79383,11 @@
78981 ** necessary to undo a write and the checkpoint should not be set.
78982 */
78983 SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){
78984 Parse *pToplevel = sqlite3ParseToplevel(pParse);
78985 sqlite3CodeVerifySchema(pParse, iDb);
78986 pToplevel->writeMask |= 1<<iDb;
78987 pToplevel->isMultiWrite |= setStatement;
78988 }
78989
78990 /*
78991 ** Indicate that the statement currently under construction might write
@@ -79626,11 +80028,14 @@
79626 sqlite3DeleteTable(0, pTab);
79627 }
79628 sqlite3HashClear(&temp1);
79629 sqlite3HashClear(&pSchema->fkeyHash);
79630 pSchema->pSeqTab = 0;
79631 pSchema->flags &= ~DB_SchemaLoaded;
 
 
 
79632 }
79633
79634 /*
79635 ** Find and return the schema associated with a BTree. Create
79636 ** a new one if necessary.
@@ -84381,12 +84786,13 @@
84381 ** index and making sure that duplicate entries do not already exist.
84382 ** Add the new records to the indices as we go.
84383 */
84384 for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){
84385 int regIdx;
 
84386 int regR;
84387
84388 if( aRegIdx[iCur]==0 ) continue; /* Skip unused indices */
84389
84390 /* Create a key for accessing the index entry */
84391 regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn+1);
84392 for(i=0; i<pIdx->nColumn; i++){
@@ -84399,10 +84805,15 @@
84399 }
84400 sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i);
84401 sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn+1, aRegIdx[iCur]);
84402 sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v, pIdx), 0);
84403 sqlite3ExprCacheAffinityChange(pParse, regIdx, pIdx->nColumn+1);
 
 
 
 
 
84404
84405 /* Find out what action to take in case there is an indexing conflict */
84406 onError = pIdx->onError;
84407 if( onError==OE_None ){
84408 sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn+1);
@@ -84473,10 +84884,11 @@
84473 break;
84474 }
84475 }
84476 sqlite3VdbeJumpHere(v, j3);
84477 sqlite3ReleaseTempReg(pParse, regR);
 
84478 }
84479
84480 if( pbMayReplace ){
84481 *pbMayReplace = seenReplace;
84482 }
@@ -86501,12 +86913,11 @@
86501 addr = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
86502 sqlite3VdbeChangeP1(v, addr, iDb);
86503 sqlite3VdbeChangeP1(v, addr+1, iDb);
86504 sqlite3VdbeChangeP1(v, addr+6, SQLITE_DEFAULT_CACHE_SIZE);
86505 }else{
86506 int size = sqlite3Atoi(zRight);
86507 if( size<0 ) size = -size;
86508 sqlite3BeginWriteOperation(pParse, 0, iDb);
86509 sqlite3VdbeAddOp2(v, OP_Integer, size, 1);
86510 sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_DEFAULT_CACHE_SIZE, 1);
86511 pDb->pSchema->cache_size = size;
86512 sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
@@ -86811,12 +87222,11 @@
86811 if( sqlite3StrICmp(zLeft,"cache_size")==0 ){
86812 if( sqlite3ReadSchema(pParse) ) goto pragma_out;
86813 if( !zRight ){
86814 returnSingleInt(pParse, "cache_size", pDb->pSchema->cache_size);
86815 }else{
86816 int size = sqlite3Atoi(zRight);
86817 if( size<0 ) size = -size;
86818 pDb->pSchema->cache_size = size;
86819 sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
86820 }
86821 }else
86822
@@ -87920,13 +88330,12 @@
87920 DbSetProperty(db, iDb, DB_Empty);
87921 }
87922 pDb->pSchema->enc = ENC(db);
87923
87924 if( pDb->pSchema->cache_size==0 ){
87925 size = meta[BTREE_DEFAULT_CACHE_SIZE-1];
87926 if( size==0 ){ size = SQLITE_DEFAULT_CACHE_SIZE; }
87927 if( size<0 ) size = -size;
87928 pDb->pSchema->cache_size = size;
87929 sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
87930 }
87931
87932 /*
@@ -93787,12 +94196,16 @@
93787 int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
93788 ExprList *pChanges, /* Columns that change in an UPDATE statement */
93789 int *pMask /* OUT: Mask of TRIGGER_BEFORE|TRIGGER_AFTER */
93790 ){
93791 int mask = 0;
93792 Trigger *pList = sqlite3TriggerList(pParse, pTab);
93793 Trigger *p;
 
 
 
 
93794 assert( pList==0 || IsVirtual(pTab)==0 );
93795 for(p=pList; p; p=p->pNext){
93796 if( p->op==op && checkColumnOverlap(p->pColumns, pChanges) ){
93797 mask |= p->tr_tm;
93798 }
@@ -95642,11 +96055,11 @@
95642 v = sqlite3GetVdbe(pParse);
95643 sqlite3ChangeCookie(pParse, iDb);
95644
95645 sqlite3VdbeAddOp2(v, OP_Expire, 0, 0);
95646 zWhere = sqlite3MPrintf(db, "name='%q' AND type='table'", pTab->zName);
95647 sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 1, 0, zWhere, P4_DYNAMIC);
95648 sqlite3VdbeAddOp4(v, OP_VCreate, iDb, 0, 0,
95649 pTab->zName, sqlite3Strlen30(pTab->zName) + 1);
95650 }
95651
95652 /* If we are rereading the sqlite_master table create the in-memory
@@ -98732,11 +99145,12 @@
98732 /*
98733 ** Estimate the number of rows that will be returned based on
98734 ** an equality constraint x=VALUE and where that VALUE occurs in
98735 ** the histogram data. This only works when x is the left-most
98736 ** column of an index and sqlite_stat2 histogram data is available
98737 ** for that index.
 
98738 **
98739 ** Write the estimated row count into *pnRow and return SQLITE_OK.
98740 ** If unable to make an estimate, leave *pnRow unchanged and return
98741 ** non-zero.
98742 **
@@ -98757,12 +99171,16 @@
98757 int rc; /* Subfunction return code */
98758 double nRowEst; /* New estimate of the number of rows */
98759
98760 assert( p->aSample!=0 );
98761 aff = p->pTable->aCol[p->aiColumn[0]].affinity;
98762 rc = valueFromExpr(pParse, pExpr, aff, &pRhs);
98763 if( rc ) goto whereEqualScanEst_cancel;
 
 
 
 
98764 if( pRhs==0 ) return SQLITE_NOTFOUND;
98765 rc = whereRangeRegion(pParse, p, pRhs, 0, &iLower);
98766 if( rc ) goto whereEqualScanEst_cancel;
98767 rc = whereRangeRegion(pParse, p, pRhs, 1, &iUpper);
98768 if( rc ) goto whereEqualScanEst_cancel;
@@ -99147,11 +99565,13 @@
99147 ** data is available for column x, then it might be possible
99148 ** to get a better estimate on the number of rows based on
99149 ** VALUE and how common that value is according to the histogram.
99150 */
99151 if( nRow>(double)1 && nEq==1 && pFirstTerm!=0 ){
99152 if( pFirstTerm->eOperator==WO_EQ ){
 
 
99153 whereEqualScanEst(pParse, pProbe, pFirstTerm->pExpr->pRight, &nRow);
99154 }else if( pFirstTerm->eOperator==WO_IN && bInEst==0 ){
99155 whereInScanEst(pParse, pProbe, pFirstTerm->pExpr->x.pList, &nRow);
99156 }
99157 }
@@ -100213,11 +100633,17 @@
100213 }
100214
100215 /* Record the instruction used to terminate the loop. Disable
100216 ** WHERE clause terms made redundant by the index range scan.
100217 */
100218 pLevel->op = bRev ? OP_Prev : OP_Next;
 
 
 
 
 
 
100219 pLevel->p1 = iIdxCur;
100220 }else
100221
100222 #ifndef SQLITE_OMIT_OR_OPTIMIZATION
100223 if( pLevel->plan.wsFlags & WHERE_MULTI_OR ){
@@ -106160,10 +106586,17 @@
106160 case SQLITE_CONFIG_HEAP: {
106161 /* Designate a buffer for heap memory space */
106162 sqlite3GlobalConfig.pHeap = va_arg(ap, void*);
106163 sqlite3GlobalConfig.nHeap = va_arg(ap, int);
106164 sqlite3GlobalConfig.mnReq = va_arg(ap, int);
 
 
 
 
 
 
 
106165
106166 if( sqlite3GlobalConfig.pHeap==0 ){
106167 /* If the heap pointer is NULL, then restore the malloc implementation
106168 ** back to NULL pointers too. This will cause the malloc to go
106169 ** back to its default implementation when sqlite3_initialize() is
@@ -106301,11 +106734,39 @@
106301 int cnt = va_arg(ap, int); /* IMP: R-04460-53386 */
106302 rc = setupLookaside(db, pBuf, sz, cnt);
106303 break;
106304 }
106305 default: {
 
 
 
 
 
 
 
 
106306 rc = SQLITE_ERROR; /* IMP: R-42790-23372 */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106307 break;
106308 }
106309 }
106310 va_end(ap);
106311 return rc;
@@ -107474,12 +107935,12 @@
107474 # error SQLITE_MAX_VDBE_OP must be at least 40
107475 #endif
107476 #if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>1000
107477 # error SQLITE_MAX_FUNCTION_ARG must be between 0 and 1000
107478 #endif
107479 #if SQLITE_MAX_ATTACHED<0 || SQLITE_MAX_ATTACHED>30
107480 # error SQLITE_MAX_ATTACHED must be between 0 and 30
107481 #endif
107482 #if SQLITE_MAX_LIKE_PATTERN_LENGTH<1
107483 # error SQLITE_MAX_LIKE_PATTERN_LENGTH must be at least 1
107484 #endif
107485 #if SQLITE_MAX_COLUMN>32767
@@ -107634,11 +108095,11 @@
107634 assert( sizeof(db->aLimit)==sizeof(aHardLimit) );
107635 memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit));
107636 db->autoCommit = 1;
107637 db->nextAutovac = -1;
107638 db->nextPagesize = 0;
107639 db->flags |= SQLITE_ShortColNames | SQLITE_AutoIndex
107640 #if SQLITE_DEFAULT_FILE_FORMAT<4
107641 | SQLITE_LegacyFileFmt
107642 #endif
107643 #ifdef SQLITE_ENABLE_LOAD_EXTENSION
107644 | SQLITE_LoadExtension
@@ -119847,17 +120308,17 @@
119847 Fts3Expr *pExpr, /* Phrase expression node */
119848 int iPhrase, /* Phrase number */
119849 void *pCtx /* Pointer to MatchInfo structure */
119850 ){
119851 MatchInfo *p = (MatchInfo *)pCtx;
 
 
 
 
119852
119853 if( pExpr->aDoclist ){
119854 char *pCsr;
119855 int iStart = iPhrase * p->nCol * 3;
119856 int i;
119857
119858 for(i=0; i<p->nCol; i++) p->aMatchinfo[iStart+i*3] = 0;
119859
119860 pCsr = sqlite3Fts3FindPositions(pExpr, p->pCursor->iPrevId, -1);
119861 if( pCsr ){
119862 fts3LoadColumnlistCounts(&pCsr, &p->aMatchinfo[iStart], 0);
119863 }
@@ -121944,19 +122405,19 @@
121944 ** to which the constraint applies. The leftmost coordinate column
121945 ** is 'a', the second from the left 'b' etc.
121946 */
121947 static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
121948 int rc = SQLITE_OK;
121949 int ii, cCol;
121950
121951 int iIdx = 0;
121952 char zIdxStr[RTREE_MAX_DIMENSIONS*8+1];
121953 memset(zIdxStr, 0, sizeof(zIdxStr));
121954 UNUSED_PARAMETER(tab);
121955
121956 assert( pIdxInfo->idxStr==0 );
121957 for(ii=0; ii<pIdxInfo->nConstraint; ii++){
121958 struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii];
121959
121960 if( p->usable && p->iColumn==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){
121961 /* We have an equality constraint on the rowid. Use strategy 1. */
121962 int jj;
@@ -121976,13 +122437,11 @@
121976 pIdxInfo->estimatedCost = 10.0;
121977 return SQLITE_OK;
121978 }
121979
121980 if( p->usable && (p->iColumn>0 || p->op==SQLITE_INDEX_CONSTRAINT_MATCH) ){
121981 int j, opmsk;
121982 static const unsigned char compatible[] = { 0, 0, 1, 1, 2, 2 };
121983 u8 op = 0;
121984 switch( p->op ){
121985 case SQLITE_INDEX_CONSTRAINT_EQ: op = RTREE_EQ; break;
121986 case SQLITE_INDEX_CONSTRAINT_GT: op = RTREE_GT; break;
121987 case SQLITE_INDEX_CONSTRAINT_LE: op = RTREE_LE; break;
121988 case SQLITE_INDEX_CONSTRAINT_LT: op = RTREE_LT; break;
@@ -121990,41 +122449,14 @@
121990 default:
121991 assert( p->op==SQLITE_INDEX_CONSTRAINT_MATCH );
121992 op = RTREE_MATCH;
121993 break;
121994 }
121995 assert( op!=0 );
121996
121997 /* Make sure this particular constraint has not been used before.
121998 ** If it has been used before, ignore it.
121999 **
122000 ** A <= or < can be used if there is a prior >= or >.
122001 ** A >= or > can be used if there is a prior < or <=.
122002 ** A <= or < is disqualified if there is a prior <=, <, or ==.
122003 ** A >= or > is disqualified if there is a prior >=, >, or ==.
122004 ** A == is disqualifed if there is any prior constraint.
122005 */
122006 assert( compatible[RTREE_EQ & 7]==0 );
122007 assert( compatible[RTREE_LT & 7]==1 );
122008 assert( compatible[RTREE_LE & 7]==1 );
122009 assert( compatible[RTREE_GT & 7]==2 );
122010 assert( compatible[RTREE_GE & 7]==2 );
122011 cCol = p->iColumn - 1 + 'a';
122012 opmsk = compatible[op & 7];
122013 for(j=0; j<iIdx; j+=2){
122014 if( zIdxStr[j+1]==cCol && (compatible[zIdxStr[j] & 7] & opmsk)!=0 ){
122015 op = 0;
122016 break;
122017 }
122018 }
122019 if( op ){
122020 assert( iIdx<sizeof(zIdxStr)-1 );
122021 zIdxStr[iIdx++] = op;
122022 zIdxStr[iIdx++] = cCol;
122023 pIdxInfo->aConstraintUsage[ii].argvIndex = (iIdx/2);
122024 pIdxInfo->aConstraintUsage[ii].omit = 1;
122025 }
122026 }
122027 }
122028
122029 pIdxInfo->idxNum = 2;
122030 pIdxInfo->needToFreeIdxStr = 1;
122031
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -650,11 +650,11 @@
650 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
651 ** [sqlite_version()] and [sqlite_source_id()].
652 */
653 #define SQLITE_VERSION "3.7.6"
654 #define SQLITE_VERSION_NUMBER 3007006
655 #define SQLITE_SOURCE_ID "2011-03-24 01:34:03 b6e268fce12829f058f1dfa223731ec8479493f8"
656
657 /*
658 ** CAPI3REF: Run-Time Library Version Numbers
659 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
660 **
@@ -1439,14 +1439,27 @@
1439 ** a 24-hour day).
1440 ** ^SQLite will use the xCurrentTimeInt64() method to get the current
1441 ** date and time if that method is available (if iVersion is 2 or
1442 ** greater and the function pointer is not NULL) and will fall back
1443 ** to xCurrentTime() if xCurrentTimeInt64() is unavailable.
1444 **
1445 ** ^The xSetSystemCall(), xGetSystemCall(), and xNestSystemCall() interfaces
1446 ** are not used by the SQLite core. These optional interfaces are provided
1447 ** by some VFSes to facilitate testing of the VFS code. By overriding
1448 ** system calls with functions under its control, a test program can
1449 ** simulate faults and error conditions that would otherwise be difficult
1450 ** or impossible to induce. The set of system calls that can be overridden
1451 ** varies from one VFS to another, and from one version of the same VFS to the
1452 ** next. Applications that use these interfaces must be prepared for any
1453 ** or all of these interfaces to be NULL or for their behavior to change
1454 ** from one release to the next. Applications must not attempt to access
1455 ** any of these methods if the iVersion of the VFS is less than 3.
1456 */
1457 typedef struct sqlite3_vfs sqlite3_vfs;
1458 typedef void (*sqlite3_syscall_ptr)(void);
1459 struct sqlite3_vfs {
1460 int iVersion; /* Structure version number (currently 3) */
1461 int szOsFile; /* Size of subclassed sqlite3_file */
1462 int mxPathname; /* Maximum file pathname length */
1463 sqlite3_vfs *pNext; /* Next registered VFS */
1464 const char *zName; /* Name of this virtual file system */
1465 void *pAppData; /* Pointer to application-specific data */
@@ -1468,10 +1481,17 @@
1481 ** definition. Those that follow are added in version 2 or later
1482 */
1483 int (*xCurrentTimeInt64)(sqlite3_vfs*, sqlite3_int64*);
1484 /*
1485 ** The methods above are in versions 1 and 2 of the sqlite_vfs object.
1486 ** Those below are for version 3 and greater.
1487 */
1488 int (*xSetSystemCall)(sqlite3_vfs*, const char *zName, sqlite3_syscall_ptr);
1489 sqlite3_syscall_ptr (*xGetSystemCall)(sqlite3_vfs*, const char *zName);
1490 const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName);
1491 /*
1492 ** The methods above are in versions 1 through 3 of the sqlite_vfs object.
1493 ** New fields may be appended in figure versions. The iVersion
1494 ** value will increment whenever this happens.
1495 */
1496 };
1497
@@ -1652,21 +1672,16 @@
1672 ** CAPI3REF: Configure database connections
1673 **
1674 ** The sqlite3_db_config() interface is used to make configuration
1675 ** changes to a [database connection]. The interface is similar to
1676 ** [sqlite3_config()] except that the changes apply to a single
1677 ** [database connection] (specified in the first argument).
 
 
 
1678 **
1679 ** The second argument to sqlite3_db_config(D,V,...) is the
1680 ** [SQLITE_DBCONIG_LOOKASIDE | configuration verb] - an integer code
1681 ** that indicates what aspect of the [database connection] is being configured.
1682 ** Subsequent arguments vary depending on the configuration verb.
 
 
1683 **
1684 ** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if
1685 ** the call is considered successful.
1686 */
1687 SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
@@ -1887,11 +1902,13 @@
1902 ** undoing any prior invocation of [SQLITE_CONFIG_MALLOC]. ^If the
1903 ** memory pointer is not NULL and either [SQLITE_ENABLE_MEMSYS3] or
1904 ** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory
1905 ** allocator is engaged to handle all of SQLites memory allocation needs.
1906 ** The first pointer (the memory pointer) must be aligned to an 8-byte
1907 ** boundary or subsequent behavior of SQLite will be undefined.
1908 ** The minimum allocation size is capped at 2^12. Reasonable values
1909 ** for the minimum allocation size are 2^5 through 2^8.</dd>
1910 **
1911 ** <dt>SQLITE_CONFIG_MUTEX</dt>
1912 ** <dd> ^(This option takes a single argument which is a pointer to an
1913 ** instance of the [sqlite3_mutex_methods] structure. The argument specifies
1914 ** alternative low-level mutex routines to be used in place
@@ -2008,13 +2025,35 @@
2025 ** [sqlite3_db_status](D,[SQLITE_CONFIG_LOOKASIDE],...) is zero.
2026 ** Any attempt to change the lookaside memory configuration when lookaside
2027 ** memory is in use leaves the configuration unchanged and returns
2028 ** [SQLITE_BUSY].)^</dd>
2029 **
2030 ** <dt>SQLITE_DBCONFIG_ENABLE_FKEY</dt>
2031 ** <dd> ^This option is used to enable or disable the enforcement of
2032 ** [foreign key constraints]. There should be two additional arguments.
2033 ** The first argument is an integer which is 0 to disable FK enforcement,
2034 ** positive to enable FK enforcement or negative to leave FK enforcement
2035 ** unchanged. The second parameter is a pointer to an integer into which
2036 ** is written 0 or 1 to indicate whether FK enforcement is off or on
2037 ** following this call. The second parameter may be a NULL pointer, in
2038 ** which case the FK enforcement setting is not reported back. </dd>
2039 **
2040 ** <dt>SQLITE_DBCONFIG_ENABLE_TRIGGER</dt>
2041 ** <dd> ^This option is used to enable or disable [CREATE TRIGGER | triggers].
2042 ** There should be two additional arguments.
2043 ** The first argument is an integer which is 0 to disable triggers,
2044 ** positive to enable trigers or negative to leave the setting unchanged.
2045 ** The second parameter is a pointer to an integer into which
2046 ** is written 0 or 1 to indicate whether triggers are disabled or enabled
2047 ** following this call. The second parameter may be a NULL pointer, in
2048 ** which case the trigger setting is not reported back. </dd>
2049 **
2050 ** </dl>
2051 */
2052 #define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */
2053 #define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */
2054 #define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */
2055
2056
2057 /*
2058 ** CAPI3REF: Enable Or Disable Extended Result Codes
2059 **
@@ -8974,10 +9013,11 @@
9013 /*
9014 ** An instance of the following structure stores a database schema.
9015 */
9016 struct Schema {
9017 int schema_cookie; /* Database schema version number for this file */
9018 int iGeneration; /* Generation counter. Incremented with each change */
9019 Hash tblHash; /* All tables indexed by name */
9020 Hash idxHash; /* All (named) indices indexed by name */
9021 Hash trigHash; /* All triggers indexed by name */
9022 Hash fkeyHash; /* All foreign keys by referenced table name */
9023 Table *pSeqTab; /* The sqlite_sequence table used by AUTOINCREMENT */
@@ -9227,10 +9267,11 @@
9267 #define SQLITE_RecTriggers 0x02000000 /* Enable recursive triggers */
9268 #define SQLITE_ForeignKeys 0x04000000 /* Enforce foreign key constraints */
9269 #define SQLITE_AutoIndex 0x08000000 /* Enable automatic indexes */
9270 #define SQLITE_PreferBuiltin 0x10000000 /* Preference to built-in funcs */
9271 #define SQLITE_LoadExtension 0x20000000 /* Enable load_extension */
9272 #define SQLITE_EnableTrigger 0x40000000 /* True to enable triggers */
9273
9274 /*
9275 ** Bits of the sqlite3.flags field that are used by the
9276 ** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface.
9277 ** These must be the low-order bits of the flags field.
@@ -9926,11 +9967,11 @@
9967 u8 op; /* Operation performed by this node */
9968 char affinity; /* The affinity of the column or 0 if not a column */
9969 u16 flags; /* Various flags. EP_* See below */
9970 union {
9971 char *zToken; /* Token value. Zero terminated and dequoted */
9972 int iValue; /* Non-negative integer value if EP_IntValue */
9973 } u;
9974
9975 /* If the EP_TokenOnly flag is set in the Expr.flags mask, then no
9976 ** space is allocated for the fields below this point. An attempt to
9977 ** access them will result in a segfault or malfunction.
@@ -10426,10 +10467,17 @@
10467 SubProgram *pProgram; /* Program implementing pTrigger/orconf */
10468 u32 aColmask[2]; /* Masks of old.*, new.* columns accessed */
10469 TriggerPrg *pNext; /* Next entry in Parse.pTriggerPrg list */
10470 };
10471
10472 /* Datatype for the bitmask of all attached databases */
10473 #if SQLITE_MAX_ATTACHED>30
10474 typedef sqlite3_uint64 tAttachMask;
10475 #else
10476 typedef unsigned int tAttachMask;
10477 #endif
10478
10479 /*
10480 ** An SQL parser context. A copy of this structure is passed through
10481 ** the parser and down into all the parser action routine in order to
10482 ** carry around information that is global to the entire parse.
10483 **
@@ -10474,12 +10522,12 @@
10522 u8 tempReg; /* iReg is a temp register that needs to be freed */
10523 int iLevel; /* Nesting level */
10524 int iReg; /* Reg with value of this column. 0 means none. */
10525 int lru; /* Least recently used entry has the smallest value */
10526 } aColCache[SQLITE_N_COLCACHE]; /* One for each column cache entry */
10527 tAttachMask writeMask; /* Start a write transaction on these databases */
10528 tAttachMask cookieMask; /* Bitmask of schema verified databases */
10529 u8 isMultiWrite; /* True if statement may affect/insert multiple rows */
10530 u8 mayAbort; /* True if statement may throw an ABORT exception */
10531 int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */
10532 int cookieValue[SQLITE_MAX_ATTACHED+2]; /* Values of cookies to verify */
10533 #ifndef SQLITE_OMIT_SHARED_CACHE
@@ -11209,10 +11257,11 @@
11257 SQLITE_PRIVATE int sqlite3CheckObjectName(Parse *, const char *);
11258 SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *, int);
11259 SQLITE_PRIVATE int sqlite3AddInt64(i64*,i64);
11260 SQLITE_PRIVATE int sqlite3SubInt64(i64*,i64);
11261 SQLITE_PRIVATE int sqlite3MulInt64(i64*,i64);
11262 SQLITE_PRIVATE int sqlite3AbsInt32(int);
11263
11264 SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value*, u8);
11265 SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value*, u8);
11266 SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8,
11267 void(*)(void*));
@@ -12023,10 +12072,13 @@
12072 "OMIT_TRIGGER",
12073 #endif
12074 #ifdef SQLITE_OMIT_TRUNCATE_OPTIMIZATION
12075 "OMIT_TRUNCATE_OPTIMIZATION",
12076 #endif
12077 #ifdef SQLITE_OMIT_UNIQUE_ENFORCEMENT
12078 "OMIT_UNIQUE_ENFORCEMENT",
12079 #endif
12080 #ifdef SQLITE_OMIT_UTF16
12081 "OMIT_UTF16",
12082 #endif
12083 #ifdef SQLITE_OMIT_VACUUM
12084 "OMIT_VACUUM",
@@ -12436,11 +12488,11 @@
12488 u8 inVtabMethod; /* See comments above */
12489 u8 usesStmtJournal; /* True if uses a statement journal */
12490 u8 readOnly; /* True for read-only statements */
12491 u8 isPrepareV2; /* True if prepared with prepare_v2() */
12492 int nChange; /* Number of db changes made since last reset */
12493 tAttachMask btreeMask; /* Bitmask of db->aDb[] entries referenced */
12494 int iStatement; /* Statement number (or 0 if has not opened stmt) */
12495 int aCounter[3]; /* Counters used by sqlite3_stmt_status() */
12496 BtreeMutexArray aMutex; /* An array of Btree used here and needing locks */
12497 #ifndef SQLITE_OMIT_TRACE
12498 i64 startTime; /* Time when query started - used for profiling */
@@ -16155,11 +16207,11 @@
16207 ** memsys5Log(8) -> 3
16208 ** memsys5Log(9) -> 4
16209 */
16210 static int memsys5Log(int iValue){
16211 int iLog;
16212 for(iLog=0; (iLog<((sizeof(int)*8)-1)) && (1<<iLog)<iValue; iLog++);
16213 return iLog;
16214 }
16215
16216 /*
16217 ** Initialize the memory allocator.
@@ -16186,10 +16238,11 @@
16238
16239 nByte = sqlite3GlobalConfig.nHeap;
16240 zByte = (u8*)sqlite3GlobalConfig.pHeap;
16241 assert( zByte!=0 ); /* sqlite3_config() does not allow otherwise */
16242
16243 /* boundaries on sqlite3GlobalConfig.mnReq are enforced in sqlite3_config() */
16244 nMinLog = memsys5Log(sqlite3GlobalConfig.mnReq);
16245 mem5.szAtom = (1<<nMinLog);
16246 while( (int)sizeof(Mem5Link)>mem5.szAtom ){
16247 mem5.szAtom = mem5.szAtom << 1;
16248 }
@@ -16689,15 +16742,20 @@
16742 ** Each recursive mutex is an instance of the following structure.
16743 */
16744 struct sqlite3_mutex {
16745 HMTX mutex; /* Mutex controlling the lock */
16746 int id; /* Mutex type */
16747 #ifdef SQLITE_DEBUG
16748 int trace; /* True to trace changes */
16749 #endif
16750 };
16751
16752 #ifdef SQLITE_DEBUG
16753 #define SQLITE3_MUTEX_INITIALIZER { 0, 0, 0 }
16754 #else
16755 #define SQLITE3_MUTEX_INITIALIZER { 0, 0 }
16756 #endif
16757
16758 /*
16759 ** Initialize and deinitialize the mutex subsystem.
16760 */
16761 static int os2MutexInit(void){ return SQLITE_OK; }
@@ -16709,15 +16767,18 @@
16767 ** that means that a mutex could not be allocated.
16768 ** SQLite will unwind its stack and return an error. The argument
16769 ** to sqlite3_mutex_alloc() is one of these integer constants:
16770 **
16771 ** <ul>
16772 ** <li> SQLITE_MUTEX_FAST
16773 ** <li> SQLITE_MUTEX_RECURSIVE
16774 ** <li> SQLITE_MUTEX_STATIC_MASTER
16775 ** <li> SQLITE_MUTEX_STATIC_MEM
16776 ** <li> SQLITE_MUTEX_STATIC_MEM2
16777 ** <li> SQLITE_MUTEX_STATIC_PRNG
16778 ** <li> SQLITE_MUTEX_STATIC_LRU
16779 ** <li> SQLITE_MUTEX_STATIC_LRU2
16780 ** </ul>
16781 **
16782 ** The first two constants cause sqlite3_mutex_alloc() to create
16783 ** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
16784 ** is used but not necessarily so when SQLITE_MUTEX_FAST is used.
@@ -16727,11 +16788,11 @@
16788 ** cases where it really needs one. If a faster non-recursive mutex
16789 ** implementation is available on the host platform, the mutex subsystem
16790 ** might return such a mutex in response to SQLITE_MUTEX_FAST.
16791 **
16792 ** The other allowed parameters to sqlite3_mutex_alloc() each return
16793 ** a pointer to a static preexisting mutex. Six static mutexes are
16794 ** used by the current version of SQLite. Future versions of SQLite
16795 ** may add additional static mutexes. Static mutexes are for internal
16796 ** use by SQLite only. Applications that use SQLite mutexes should
16797 ** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or
16798 ** SQLITE_MUTEX_RECURSIVE.
@@ -16757,17 +16818,17 @@
16818 }
16819 break;
16820 }
16821 default: {
16822 static volatile int isInit = 0;
16823 static sqlite3_mutex staticMutexes[6] = {
16824 SQLITE3_MUTEX_INITIALIZER,
16825 SQLITE3_MUTEX_INITIALIZER,
16826 SQLITE3_MUTEX_INITIALIZER,
16827 SQLITE3_MUTEX_INITIALIZER,
16828 SQLITE3_MUTEX_INITIALIZER,
16829 SQLITE3_MUTEX_INITIALIZER,
16830 };
16831 if ( !isInit ){
16832 APIRET rc;
16833 PTIB ptib;
16834 PPIB ppib;
@@ -16809,13 +16870,18 @@
16870 /*
16871 ** This routine deallocates a previously allocated mutex.
16872 ** SQLite is careful to deallocate every mutex that it allocates.
16873 */
16874 static void os2MutexFree(sqlite3_mutex *p){
16875 #ifdef SQLITE_DEBUG
16876 TID tid;
16877 PID pid;
16878 ULONG ulCount;
16879 DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount);
16880 assert( ulCount==0 );
16881 assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
16882 #endif
16883 DosCloseMutexSem( p->mutex );
16884 sqlite3_free( p );
16885 }
16886
16887 #ifdef SQLITE_DEBUG
@@ -16826,30 +16892,33 @@
16892 static int os2MutexHeld(sqlite3_mutex *p){
16893 TID tid;
16894 PID pid;
16895 ULONG ulCount;
16896 PTIB ptib;
16897 DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount);
16898 if( ulCount==0 || ( ulCount>1 && p->id!=SQLITE_MUTEX_RECURSIVE ) )
16899 return 0;
16900 DosGetInfoBlocks(&ptib, NULL);
16901 return tid==ptib->tib_ptib2->tib2_ultid;
 
 
16902 }
16903 static int os2MutexNotheld(sqlite3_mutex *p){
16904 TID tid;
16905 PID pid;
16906 ULONG ulCount;
16907 PTIB ptib;
16908 DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount);
16909 if( ulCount==0 )
16910 return 1;
16911 DosGetInfoBlocks(&ptib, NULL);
16912 return tid!=ptib->tib_ptib2->tib2_ultid;
16913 }
16914 static void os2MutexTrace(sqlite3_mutex *p, char *pAction){
16915 TID tid;
16916 PID pid;
16917 ULONG ulCount;
16918 DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount);
16919 printf("%s mutex %p (%d) with nRef=%ld\n", pAction, (void*)p, p->trace, ulCount);
16920 }
16921 #endif
16922
16923 /*
16924 ** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
@@ -16861,36 +16930,25 @@
16930 ** mutex must be exited an equal number of times before another thread
16931 ** can enter. If the same thread tries to enter any other kind of mutex
16932 ** more than once, the behavior is undefined.
16933 */
16934 static void os2MutexEnter(sqlite3_mutex *p){
 
 
 
 
16935 assert( p->id==SQLITE_MUTEX_RECURSIVE || os2MutexNotheld(p) );
16936 DosRequestMutexSem(p->mutex, SEM_INDEFINITE_WAIT);
16937 #ifdef SQLITE_DEBUG
16938 if( p->trace ) os2MutexTrace(p, "enter");
16939 #endif
16940 }
16941 static int os2MutexTry(sqlite3_mutex *p){
16942 int rc = SQLITE_BUSY;
 
 
 
 
16943 assert( p->id==SQLITE_MUTEX_RECURSIVE || os2MutexNotheld(p) );
16944 if( DosRequestMutexSem(p->mutex, SEM_IMMEDIATE_RETURN) == NO_ERROR ) {
 
 
 
16945 rc = SQLITE_OK;
16946 #ifdef SQLITE_DEBUG
16947 if( p->trace ) os2MutexTrace(p, "try");
16948 #endif
16949 }
 
16950 return rc;
16951 }
16952
16953 /*
16954 ** The sqlite3_mutex_leave() routine exits a mutex that was
@@ -16897,23 +16955,18 @@
16955 ** previously entered by the same thread. The behavior
16956 ** is undefined if the mutex is not currently entered or
16957 ** is not currently allocated. SQLite will never do either.
16958 */
16959 static void os2MutexLeave(sqlite3_mutex *p){
16960 assert( os2MutexHeld(p) );
 
 
 
 
 
 
 
 
16961 DosReleaseMutexSem(p->mutex);
16962 #ifdef SQLITE_DEBUG
16963 if( p->trace ) os2MutexTrace(p, "leave");
16964 #endif
16965 }
16966
16967 SQLITE_PRIVATE SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
16968 static const sqlite3_mutex_methods sMutex = {
16969 os2MutexInit,
16970 os2MutexEnd,
16971 os2MutexAlloc,
16972 os2MutexFree,
@@ -16921,10 +16974,13 @@
16974 os2MutexTry,
16975 os2MutexLeave,
16976 #ifdef SQLITE_DEBUG
16977 os2MutexHeld,
16978 os2MutexNotheld
16979 #else
16980 0,
16981 0
16982 #endif
16983 };
16984
16985 return &sMutex;
16986 }
@@ -17564,11 +17620,11 @@
17620 #else
17621 UNUSED_PARAMETER(p);
17622 #endif
17623 #ifdef SQLITE_DEBUG
17624 if( rc==SQLITE_OK && p->trace ){
17625 printf("try mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
17626 }
17627 #endif
17628 return rc;
17629 }
17630
@@ -21270,10 +21326,20 @@
21326 r *= TWOPOWER32;
21327 if( sqlite3AddInt64(&r, iA0*iB0) ) return 1;
21328 *pA = r;
21329 return 0;
21330 }
21331
21332 /*
21333 ** Compute the absolute value of a 32-bit signed integer, of possible. Or
21334 ** if the integer has a value of -2147483648, return +2147483647
21335 */
21336 SQLITE_PRIVATE int sqlite3AbsInt32(int x){
21337 if( x>=0 ) return x;
21338 if( x==(int)0x80000000 ) return 0x7fffffff;
21339 return -x;
21340 }
21341
21342 /************** End of util.c ************************************************/
21343 /************** Begin file hash.c ********************************************/
21344 /*
21345 ** 2001 September 22
@@ -22560,23 +22626,27 @@
22626 /*
22627 ** This vector defines all the methods that can operate on an
22628 ** sqlite3_file for os2.
22629 */
22630 static const sqlite3_io_methods os2IoMethod = {
22631 1, /* iVersion */
22632 os2Close, /* xClose */
22633 os2Read, /* xRead */
22634 os2Write, /* xWrite */
22635 os2Truncate, /* xTruncate */
22636 os2Sync, /* xSync */
22637 os2FileSize, /* xFileSize */
22638 os2Lock, /* xLock */
22639 os2Unlock, /* xUnlock */
22640 os2CheckReservedLock, /* xCheckReservedLock */
22641 os2FileControl, /* xFileControl */
22642 os2SectorSize, /* xSectorSize */
22643 os2DeviceCharacteristics, /* xDeviceCharacteristics */
22644 0, /* xShmMap */
22645 0, /* xShmLock */
22646 0, /* xShmBarrier */
22647 0 /* xShmUnmap */
22648 };
22649
22650 /***************************************************************************
22651 ** Here ends the I/O methods that form the sqlite3_io_methods object.
22652 **
@@ -22664,115 +22734,151 @@
22734 /*
22735 ** Open a file.
22736 */
22737 static int os2Open(
22738 sqlite3_vfs *pVfs, /* Not used */
22739 const char *zName, /* Name of the file (UTF-8) */
22740 sqlite3_file *id, /* Write the SQLite file handle here */
22741 int flags, /* Open mode flags */
22742 int *pOutFlags /* Status return flags */
22743 ){
22744 HFILE h;
 
22745 ULONG ulOpenFlags = 0;
22746 ULONG ulOpenMode = 0;
22747 ULONG ulAction = 0;
22748 ULONG rc;
22749 os2File *pFile = (os2File*)id;
22750 const char *zUtf8Name = zName;
 
22751 char *zNameCp;
22752 char zTmpname[CCHMAXPATH];
22753
22754 int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE);
22755 int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE);
22756 int isCreate = (flags & SQLITE_OPEN_CREATE);
22757 int isReadWrite = (flags & SQLITE_OPEN_READWRITE);
22758 #ifndef NDEBUG
22759 int isReadonly = (flags & SQLITE_OPEN_READONLY);
22760 int eType = (flags & 0xFFFFFF00);
22761 int isOpenJournal = (isCreate && (
22762 eType==SQLITE_OPEN_MASTER_JOURNAL
22763 || eType==SQLITE_OPEN_MAIN_JOURNAL
22764 || eType==SQLITE_OPEN_WAL
22765 ));
22766 #endif
22767
22768 UNUSED_PARAMETER(pVfs);
22769 assert( id!=0 );
22770
22771 /* Check the following statements are true:
22772 **
22773 ** (a) Exactly one of the READWRITE and READONLY flags must be set, and
22774 ** (b) if CREATE is set, then READWRITE must also be set, and
22775 ** (c) if EXCLUSIVE is set, then CREATE must also be set.
22776 ** (d) if DELETEONCLOSE is set, then CREATE must also be set.
22777 */
22778 assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly));
22779 assert(isCreate==0 || isReadWrite);
22780 assert(isExclusive==0 || isCreate);
22781 assert(isDelete==0 || isCreate);
22782
22783 /* The main DB, main journal, WAL file and master journal are never
22784 ** automatically deleted. Nor are they ever temporary files. */
22785 assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB );
22786 assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL );
22787 assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL );
22788 assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL );
22789
22790 /* Assert that the upper layer has set one of the "file-type" flags. */
22791 assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB
22792 || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
22793 || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL
22794 || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
22795 );
22796
22797 memset( pFile, 0, sizeof(*pFile) );
22798 pFile->pMethod = &os2IoMethod;
22799
22800 /* If the second argument to this function is NULL, generate a
22801 ** temporary file name to use
22802 */
22803 if( !zUtf8Name ){
22804 assert(isDelete && !isOpenJournal);
22805 rc = getTempname(CCHMAXPATH, zTmpname);
22806 if( rc!=SQLITE_OK ){
22807 return rc;
22808 }
22809 zUtf8Name = zTmpname;
22810 }
22811
22812 if( isReadWrite ){
 
 
 
 
 
22813 ulOpenMode |= OPEN_ACCESS_READWRITE;
 
22814 }else{
22815 ulOpenMode |= OPEN_ACCESS_READONLY;
22816 }
22817
22818 /* Open in random access mode for possibly better speed. Allow full
22819 ** sharing because file locks will provide exclusive access when needed.
22820 */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22821 ulOpenMode |= OPEN_FLAGS_RANDOM;
22822 ulOpenMode |= OPEN_FLAGS_FAIL_ON_ERROR;
22823 ulOpenMode |= OPEN_FLAGS_NOINHERIT;
22824 ulOpenMode |= OPEN_SHARE_DENYNONE;
22825
22826 /* SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is
22827 ** created. SQLite doesn't use it to indicate "exclusive access"
22828 ** as it is usually understood.
22829 */
22830 if( isExclusive ){
22831 /* Creates a new file, only if it does not already exist. */
22832 /* If the file exists, it fails. */
22833 ulOpenFlags |= OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_FAIL_IF_EXISTS;
22834 }else if( isCreate ){
22835 /* Open existing file, or create if it doesn't exist */
22836 ulOpenFlags |= OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
22837 }else{
22838 /* Opens a file, only if it exists. */
22839 ulOpenFlags |= OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
22840 }
22841
22842 /* For DELETEONCLOSE, save a pointer to the converted filename */
22843 if( isDelete ){
22844 char pathUtf8[CCHMAXPATH];
22845 os2FullPathname( pVfs, zUtf8Name, CCHMAXPATH, pathUtf8 );
22846 pFile->pathToDel = convertUtf8PathToCp( pathUtf8 );
22847 }
22848
22849 zNameCp = convertUtf8PathToCp( zUtf8Name );
22850 rc = DosOpen( (PSZ)zNameCp,
22851 &h,
22852 &ulAction,
22853 0L,
22854 FILE_NORMAL,
22855 ulOpenFlags,
22856 ulOpenMode,
22857 (PEAOP2)NULL );
22858 free( zNameCp );
22859
22860 if( rc != NO_ERROR ){
22861 OSTRACE(( "OPEN Invalid handle rc=%d: zName=%s, ulAction=%#lx, ulFlags=%#lx, ulMode=%#lx\n",
22862 rc, zUtf8Name, ulAction, ulOpenFlags, ulOpenMode ));
22863 if( pFile->pathToDel )
22864 free( pFile->pathToDel );
22865 pFile->pathToDel = NULL;
22866
22867 if( isReadWrite ){
 
22868 return os2Open( pVfs, zName, id,
22869 ((flags|SQLITE_OPEN_READONLY)&~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)),
22870 pOutFlags );
22871 }else{
22872 return SQLITE_CANTOPEN;
22873 }
22874 }
22875
22876 if( pOutFlags ){
22877 *pOutFlags = isReadWrite ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY;
22878 }
22879
 
22880 pFile->h = h;
22881 OpenCounter(+1);
22882 OSTRACE(( "OPEN %d pOutFlags=%d\n", pFile->h, pOutFlags ));
22883 return SQLITE_OK;
22884 }
@@ -22783,17 +22889,20 @@
22889 static int os2Delete(
22890 sqlite3_vfs *pVfs, /* Not used on os2 */
22891 const char *zFilename, /* Name of file to delete */
22892 int syncDir /* Not used on os2 */
22893 ){
22894 APIRET rc;
22895 char *zFilenameCp;
22896 SimulateIOError( return SQLITE_IOERR_DELETE );
22897 zFilenameCp = convertUtf8PathToCp( zFilename );
22898 rc = DosDelete( (PSZ)zFilenameCp );
22899 free( zFilenameCp );
22900 OSTRACE(( "DELETE \"%s\"\n", zFilename ));
22901 return (rc == NO_ERROR ||
22902 rc == ERROR_FILE_NOT_FOUND ||
22903 rc == ERROR_PATH_NOT_FOUND ) ? SQLITE_OK : SQLITE_IOERR_DELETE;
22904 }
22905
22906 /*
22907 ** Check the existance and status of a file.
22908 */
@@ -22854,11 +22963,11 @@
22963 ** os2Dlopen returns zero if DosLoadModule is not successful.
22964 */
22965 static void os2DlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
22966 /* no-op */
22967 }
22968 static void (*os2DlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol))(void){
22969 PFN pfn;
22970 APIRET rc;
22971 rc = DosQueryProcAddr((HMODULE)pHandle, 0L, zSymbol, &pfn);
22972 if( rc != NO_ERROR ){
22973 /* if the symbol itself was not found, search again for the same
@@ -22866,11 +22975,11 @@
22975 * on the calling convention */
22976 char _zSymbol[256] = "_";
22977 strncat(_zSymbol, zSymbol, 255);
22978 rc = DosQueryProcAddr((HMODULE)pHandle, 0L, _zSymbol, &pfn);
22979 }
22980 return rc != NO_ERROR ? 0 : (void(*)(void))pfn;
22981 }
22982 static void os2DlClose(sqlite3_vfs *pVfs, void *pHandle){
22983 DosFreeModule((HMODULE)pHandle);
22984 }
22985 #else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */
@@ -22970,14 +23079,15 @@
23079 ** return 0. Return 1 if the time and date cannot be found.
23080 */
23081 int os2CurrentTime( sqlite3_vfs *pVfs, double *prNow ){
23082 double now;
23083 SHORT minute; /* needs to be able to cope with negative timezone offset */
23084 USHORT hundredths, second, hour,
23085 day, month, year;
23086 DATETIME dt;
23087 DosGetDateTime( &dt );
23088 hundredths = (USHORT)dt.hundredths;
23089 second = (USHORT)dt.seconds;
23090 minute = (SHORT)dt.minutes + dt.timezone;
23091 hour = (USHORT)dt.hours;
23092 day = (USHORT)dt.day;
23093 month = (USHORT)dt.month;
@@ -22993,18 +23103,35 @@
23103
23104 /* Add the fractional hours, mins and seconds */
23105 now += (hour + 12.0)/24.0;
23106 now += minute/1440.0;
23107 now += second/86400.0;
23108 now += hundredths/8640000.0;
23109 *prNow = now;
23110 #ifdef SQLITE_TEST
23111 if( sqlite3_current_time ){
23112 *prNow = sqlite3_current_time/86400.0 + 2440587.5;
23113 }
23114 #endif
23115 return 0;
23116 }
23117
23118 /*
23119 ** Find the current time (in Universal Coordinated Time). Write into *piNow
23120 ** the current time and date as a Julian Day number times 86_400_000. In
23121 ** other words, write into *piNow the number of milliseconds since the Julian
23122 ** epoch of noon in Greenwich on November 24, 4714 B.C according to the
23123 ** proleptic Gregorian calendar.
23124 **
23125 ** On success, return 0. Return 1 if the time and date cannot be found.
23126 */
23127 static int os2CurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){
23128 double now;
23129 os2CurrentTime(pVfs, &now);
23130 *piNow = now * 86400000;
23131 return 0;
23132 }
23133
23134 static int os2GetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
23135 return 0;
23136 }
23137
@@ -23011,11 +23138,11 @@
23138 /*
23139 ** Initialize and deinitialize the operating system interface.
23140 */
23141 SQLITE_API int sqlite3_os_init(void){
23142 static sqlite3_vfs os2Vfs = {
23143 3, /* iVersion */
23144 sizeof(os2File), /* szOsFile */
23145 CCHMAXPATH, /* mxPathname */
23146 0, /* pNext */
23147 "os2", /* zName */
23148 0, /* pAppData */
@@ -23030,10 +23157,14 @@
23157 os2DlClose, /* xDlClose */
23158 os2Randomness, /* xRandomness */
23159 os2Sleep, /* xSleep */
23160 os2CurrentTime, /* xCurrentTime */
23161 os2GetLastError, /* xGetLastError */
23162 os2CurrentTimeInt64 /* xCurrentTimeInt64 */
23163 0, /* xSetSystemCall */
23164 0, /* xGetSystemCall */
23165 0, /* xNextSystemCall */
23166 };
23167 sqlite3_vfs_register(&os2Vfs, 1);
23168 initUconvObjects();
23169 return SQLITE_OK;
23170 }
@@ -23249,14 +23380,14 @@
23380 sqlite3_io_methods const *pMethod; /* Always the first entry */
23381 unixInodeInfo *pInode; /* Info about locks on this inode */
23382 int h; /* The file descriptor */
23383 int dirfd; /* File descriptor for the directory */
23384 unsigned char eFileLock; /* The type of lock held on this fd */
23385 unsigned char ctrlFlags; /* Behavioral bits. UNIXFILE_* flags */
23386 int lastErrno; /* The unix errno from last I/O error */
23387 void *lockingContext; /* Locking style specific state */
23388 UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */
 
23389 const char *zPath; /* Name of the file */
23390 unixShm *pShm; /* Shared memory segment information */
23391 int szChunk; /* Configured by FCNTL_CHUNK_SIZE */
23392 #if SQLITE_ENABLE_LOCKING_STYLE
23393 int openFlags; /* The flags specified at open() */
@@ -23287,13 +23418,14 @@
23418 char aPadding[32];
23419 #endif
23420 };
23421
23422 /*
23423 ** Allowed values for the unixFile.ctrlFlags bitmask:
23424 */
23425 #define UNIXFILE_EXCL 0x01 /* Connections from one process only */
23426 #define UNIXFILE_RDONLY 0x02 /* Connection is read only */
23427
23428 /*
23429 ** Include code that is common to all os_*.c files
23430 */
23431 /************** Include os_common.h in the middle of os_unix.c ***************/
@@ -23518,20 +23650,10 @@
23650 #endif
23651 #ifndef O_BINARY
23652 # define O_BINARY 0
23653 #endif
23654
 
 
 
 
 
 
 
 
 
 
23655 /*
23656 ** The threadid macro resolves to the thread-id or to 0. Used for
23657 ** testing and debugging only.
23658 */
23659 #if SQLITE_THREADSAFE
@@ -23538,10 +23660,197 @@
23660 #define threadid pthread_self()
23661 #else
23662 #define threadid 0
23663 #endif
23664
23665 /*
23666 ** Many system calls are accessed through pointer-to-functions so that
23667 ** they may be overridden at runtime to facilitate fault injection during
23668 ** testing and sandboxing. The following array holds the names and pointers
23669 ** to all overrideable system calls.
23670 */
23671 static struct unix_syscall {
23672 const char *zName; /* Name of the sytem call */
23673 sqlite3_syscall_ptr pCurrent; /* Current value of the system call */
23674 sqlite3_syscall_ptr pDefault; /* Default value */
23675 } aSyscall[] = {
23676 { "open", (sqlite3_syscall_ptr)open, 0 },
23677 #define osOpen ((int(*)(const char*,int,int))aSyscall[0].pCurrent)
23678
23679 { "close", (sqlite3_syscall_ptr)close, 0 },
23680 #define osClose ((int(*)(int))aSyscall[1].pCurrent)
23681
23682 { "access", (sqlite3_syscall_ptr)access, 0 },
23683 #define osAccess ((int(*)(const char*,int))aSyscall[2].pCurrent)
23684
23685 { "getcwd", (sqlite3_syscall_ptr)getcwd, 0 },
23686 #define osGetcwd ((char*(*)(char*,size_t))aSyscall[3].pCurrent)
23687
23688 { "stat", (sqlite3_syscall_ptr)stat, 0 },
23689 #define osStat ((int(*)(const char*,struct stat*))aSyscall[4].pCurrent)
23690
23691 /*
23692 ** The DJGPP compiler environment looks mostly like Unix, but it
23693 ** lacks the fcntl() system call. So redefine fcntl() to be something
23694 ** that always succeeds. This means that locking does not occur under
23695 ** DJGPP. But it is DOS - what did you expect?
23696 */
23697 #ifdef __DJGPP__
23698 { "fstat", 0, 0 },
23699 #define osFstat(a,b,c) 0
23700 #else
23701 { "fstat", (sqlite3_syscall_ptr)fstat, 0 },
23702 #define osFstat ((int(*)(int,struct stat*))aSyscall[5].pCurrent)
23703 #endif
23704
23705 { "ftruncate", (sqlite3_syscall_ptr)ftruncate, 0 },
23706 #define osFtruncate ((int(*)(int,off_t))aSyscall[6].pCurrent)
23707
23708 { "fcntl", (sqlite3_syscall_ptr)fcntl, 0 },
23709 #define osFcntl ((int(*)(int,int,...))aSyscall[7].pCurrent)
23710
23711 { "read", (sqlite3_syscall_ptr)read, 0 },
23712 #define osRead ((ssize_t(*)(int,void*,size_t))aSyscall[8].pCurrent)
23713
23714 #if defined(USE_PREAD) || defined(SQLITE_ENABLE_LOCKING_STYLE)
23715 { "pread", (sqlite3_syscall_ptr)pread, 0 },
23716 #else
23717 { "pread", (sqlite3_syscall_ptr)0, 0 },
23718 #endif
23719 #define osPread ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[9].pCurrent)
23720
23721 #if defined(USE_PREAD64)
23722 { "pread64", (sqlite3_syscall_ptr)pread64, 0 },
23723 #else
23724 { "pread64", (sqlite3_syscall_ptr)0, 0 },
23725 #endif
23726 #define osPread64 ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].pCurrent)
23727
23728 { "write", (sqlite3_syscall_ptr)write, 0 },
23729 #define osWrite ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent)
23730
23731 #if defined(USE_PREAD) || defined(SQLITE_ENABLE_LOCKING_STYLE)
23732 { "pwrite", (sqlite3_syscall_ptr)pwrite, 0 },
23733 #else
23734 { "pwrite", (sqlite3_syscall_ptr)0, 0 },
23735 #endif
23736 #define osPwrite ((ssize_t(*)(int,const void*,size_t,off_t))\
23737 aSyscall[12].pCurrent)
23738
23739 #if defined(USE_PREAD64)
23740 { "pwrite64", (sqlite3_syscall_ptr)pwrite64, 0 },
23741 #else
23742 { "pwrite64", (sqlite3_syscall_ptr)0, 0 },
23743 #endif
23744 #define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\
23745 aSyscall[13].pCurrent)
23746
23747 { "fchmod", (sqlite3_syscall_ptr)fchmod, 0 },
23748 #define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent)
23749
23750 #if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
23751 { "fallocate", (sqlite3_syscall_ptr)posix_fallocate, 0 },
23752 #else
23753 { "fallocate", (sqlite3_syscall_ptr)0, 0 },
23754 #endif
23755 #define osFallocate ((int(*)(int,off_t,off_t)aSyscall[15].pCurrent)
23756
23757 }; /* End of the overrideable system calls */
23758
23759 /*
23760 ** This is the xSetSystemCall() method of sqlite3_vfs for all of the
23761 ** "unix" VFSes. Return SQLITE_OK opon successfully updating the
23762 ** system call pointer, or SQLITE_NOTFOUND if there is no configurable
23763 ** system call named zName.
23764 */
23765 static int unixSetSystemCall(
23766 sqlite3_vfs *pNotUsed, /* The VFS pointer. Not used */
23767 const char *zName, /* Name of system call to override */
23768 sqlite3_syscall_ptr pNewFunc /* Pointer to new system call value */
23769 ){
23770 unsigned int i;
23771 int rc = SQLITE_NOTFOUND;
23772
23773 UNUSED_PARAMETER(pNotUsed);
23774 if( zName==0 ){
23775 /* If no zName is given, restore all system calls to their default
23776 ** settings and return NULL
23777 */
23778 for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
23779 if( aSyscall[i].pDefault ){
23780 aSyscall[i].pCurrent = aSyscall[i].pDefault;
23781 rc = SQLITE_OK;
23782 }
23783 }
23784 }else{
23785 /* If zName is specified, operate on only the one system call
23786 ** specified.
23787 */
23788 for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
23789 if( strcmp(zName, aSyscall[i].zName)==0 ){
23790 if( aSyscall[i].pDefault==0 ){
23791 aSyscall[i].pDefault = aSyscall[i].pCurrent;
23792 }
23793 rc = SQLITE_OK;
23794 if( pNewFunc==0 ) pNewFunc = aSyscall[i].pDefault;
23795 aSyscall[i].pCurrent = pNewFunc;
23796 break;
23797 }
23798 }
23799 }
23800 return rc;
23801 }
23802
23803 /*
23804 ** Return the value of a system call. Return NULL if zName is not a
23805 ** recognized system call name. NULL is also returned if the system call
23806 ** is currently undefined.
23807 */
23808 static sqlite3_syscall_ptr unixGetSystemCall(
23809 sqlite3_vfs *pNotUsed,
23810 const char *zName
23811 ){
23812 unsigned int i;
23813
23814 UNUSED_PARAMETER(pNotUsed);
23815 for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
23816 if( strcmp(zName, aSyscall[i].zName)==0 ) return aSyscall[i].pCurrent;
23817 }
23818 return 0;
23819 }
23820
23821 /*
23822 ** Return the name of the first system call after zName. If zName==NULL
23823 ** then return the name of the first system call. Return NULL if zName
23824 ** is the last system call or if zName is not the name of a valid
23825 ** system call.
23826 */
23827 static const char *unixNextSystemCall(sqlite3_vfs *p, const char *zName){
23828 unsigned int i;
23829
23830 UNUSED_PARAMETER(p);
23831 if( zName==0 ){
23832 i = -1;
23833 }else{
23834 for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0])-1; i++){
23835 if( strcmp(zName, aSyscall[0].zName)==0 ) break;
23836 }
23837 }
23838 for(i++; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
23839 if( aSyscall[0].pCurrent!=0 ) return aSyscall[0].zName;
23840 }
23841 return 0;
23842 }
23843
23844 /*
23845 ** Retry open() calls that fail due to EINTR
23846 */
23847 static int robust_open(const char *z, int f, int m){
23848 int rc;
23849 do{ rc = osOpen(z,f,m); }while( rc<0 && errno==EINTR );
23850 return rc;
23851 }
23852
23853 /*
23854 ** Helper functions to obtain and relinquish the global mutex. The
23855 ** global mutex is used to protect the unixInodeInfo and
23856 ** vxworksFileId objects used by this file, all of which may be
@@ -23602,11 +23911,11 @@
23911 if( op==F_GETLK ){
23912 zOpName = "GETLK";
23913 }else if( op==F_SETLK ){
23914 zOpName = "SETLK";
23915 }else{
23916 s = osFcntl(fd, op, p);
23917 sqlite3DebugPrintf("fcntl unknown %d %d %d\n", fd, op, s);
23918 return s;
23919 }
23920 if( p->l_type==F_RDLCK ){
23921 zType = "RDLCK";
@@ -23616,19 +23925,19 @@
23925 zType = "UNLCK";
23926 }else{
23927 assert( 0 );
23928 }
23929 assert( p->l_whence==SEEK_SET );
23930 s = osFcntl(fd, op, p);
23931 savedErrno = errno;
23932 sqlite3DebugPrintf("fcntl %d %d %s %s %d %d %d %d\n",
23933 threadid, fd, zOpName, zType, (int)p->l_start, (int)p->l_len,
23934 (int)p->l_pid, s);
23935 if( s==(-1) && op==F_SETLK && (p->l_type==F_RDLCK || p->l_type==F_WRLCK) ){
23936 struct flock l2;
23937 l2 = *p;
23938 osFcntl(fd, F_GETLK, &l2);
23939 if( l2.l_type==F_RDLCK ){
23940 zType = "RDLCK";
23941 }else if( l2.l_type==F_WRLCK ){
23942 zType = "WRLCK";
23943 }else if( l2.l_type==F_UNLCK ){
@@ -23640,27 +23949,22 @@
23949 zType, (int)l2.l_start, (int)l2.l_len, (int)l2.l_pid);
23950 }
23951 errno = savedErrno;
23952 return s;
23953 }
23954 #undef osFcntl
23955 #define osFcntl lockTrace
23956 #endif /* SQLITE_LOCK_TRACE */
 
23957
23958 /*
23959 ** Retry ftruncate() calls that fail due to EINTR
23960 */
 
23961 static int robust_ftruncate(int h, sqlite3_int64 sz){
23962 int rc;
23963 do{ rc = osFtruncate(h,sz); }while( rc<0 && errno==EINTR );
23964 return rc;
23965 }
 
 
 
 
23966
23967 /*
23968 ** This routine translates a standard POSIX errno code into something
23969 ** useful to the clients of the sqlite3 functions. Specifically, it is
23970 ** intended to translate a variety of "try again" errors into SQLITE_BUSY
@@ -23978,11 +24282,12 @@
24282 ** object keeps a count of the number of unixFile pointing to it.
24283 */
24284 struct unixInodeInfo {
24285 struct unixFileId fileId; /* The lookup key */
24286 int nShared; /* Number of SHARED locks held */
24287 unsigned char eFileLock; /* One of SHARED_LOCK, RESERVED_LOCK etc. */
24288 unsigned char bProcessLock; /* An exclusive process lock is held */
24289 int nRef; /* Number of pointers to this structure */
24290 unixShmNode *pShmNode; /* Shared memory associated with this inode */
24291 int nLock; /* Number of outstanding file locks */
24292 UnixUnusedFd *pUnused; /* Unused file descriptors to close */
24293 unixInodeInfo *pNext; /* List of all unixInodeInfo objects */
@@ -24083,11 +24388,11 @@
24388 ** file descriptor might have already been reused by another thread.
24389 ** So we don't even try to recover from an EINTR. Just log the error
24390 ** and move on.
24391 */
24392 static void robust_close(unixFile *pFile, int h, int lineno){
24393 if( osClose(h) ){
24394 unixLogErrorAtLine(SQLITE_IOERR_CLOSE, "close",
24395 pFile ? pFile->zPath : 0, lineno);
24396 }
24397 }
24398
@@ -24160,11 +24465,11 @@
24465
24466 /* Get low-level information about the file that we can used to
24467 ** create a unique name for the file.
24468 */
24469 fd = pFile->h;
24470 rc = osFstat(fd, &statbuf);
24471 if( rc!=0 ){
24472 pFile->lastErrno = errno;
24473 #ifdef EOVERFLOW
24474 if( pFile->lastErrno==EOVERFLOW ) return SQLITE_NOLFS;
24475 #endif
@@ -24181,16 +24486,16 @@
24486 ** in the header of every SQLite database. In this way, if there
24487 ** is a race condition such that another thread has already populated
24488 ** the first page of the database, no damage is done.
24489 */
24490 if( statbuf.st_size==0 && (pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS)!=0 ){
24491 do{ rc = osWrite(fd, "S", 1); }while( rc<0 && errno==EINTR );
24492 if( rc!=1 ){
24493 pFile->lastErrno = errno;
24494 return SQLITE_IOERR;
24495 }
24496 rc = osFstat(fd, &statbuf);
24497 if( rc!=0 ){
24498 pFile->lastErrno = errno;
24499 return SQLITE_IOERR;
24500 }
24501 }
@@ -24249,17 +24554,17 @@
24554 }
24555
24556 /* Otherwise see if some other process holds it.
24557 */
24558 #ifndef __DJGPP__
24559 if( !reserved && !pFile->pInode->bProcessLock ){
24560 struct flock lock;
24561 lock.l_whence = SEEK_SET;
24562 lock.l_start = RESERVED_BYTE;
24563 lock.l_len = 1;
24564 lock.l_type = F_WRLCK;
24565 if (-1 == osFcntl(pFile->h, F_GETLK, &lock)) {
24566 int tErrno = errno;
24567 rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_CHECKRESERVEDLOCK);
24568 pFile->lastErrno = tErrno;
24569 } else if( lock.l_type!=F_UNLCK ){
24570 reserved = 1;
@@ -24271,10 +24576,54 @@
24576 OSTRACE(("TEST WR-LOCK %d %d %d (unix)\n", pFile->h, rc, reserved));
24577
24578 *pResOut = reserved;
24579 return rc;
24580 }
24581
24582 /*
24583 ** Attempt to set a system-lock on the file pFile. The lock is
24584 ** described by pLock.
24585 **
24586 ** If the pFile was opened read/write from unix-excl, then the only lock
24587 ** ever obtained is an exclusive lock, and it is obtained exactly once
24588 ** the first time any lock is attempted. All subsequent system locking
24589 ** operations become no-ops. Locking operations still happen internally,
24590 ** in order to coordinate access between separate database connections
24591 ** within this process, but all of that is handled in memory and the
24592 ** operating system does not participate.
24593 **
24594 ** This function is a pass-through to fcntl(F_SETLK) if pFile is using
24595 ** any VFS other than "unix-excl" or if pFile is opened on "unix-excl"
24596 ** and is read-only.
24597 */
24598 static int unixFileLock(unixFile *pFile, struct flock *pLock){
24599 int rc;
24600 unixInodeInfo *pInode = pFile->pInode;
24601 assert( unixMutexHeld() );
24602 assert( pInode!=0 );
24603 if( ((pFile->ctrlFlags & UNIXFILE_EXCL)!=0 || pInode->bProcessLock)
24604 && ((pFile->ctrlFlags & UNIXFILE_RDONLY)==0)
24605 ){
24606 if( pInode->bProcessLock==0 ){
24607 struct flock lock;
24608 assert( pInode->nLock==0 );
24609 lock.l_whence = SEEK_SET;
24610 lock.l_start = SHARED_FIRST;
24611 lock.l_len = SHARED_SIZE;
24612 lock.l_type = F_WRLCK;
24613 rc = osFcntl(pFile->h, F_SETLK, &lock);
24614 if( rc<0 ) return rc;
24615 pInode->bProcessLock = 1;
24616 pInode->nLock++;
24617 }else{
24618 rc = 0;
24619 }
24620 }else{
24621 rc = osFcntl(pFile->h, F_SETLK, pLock);
24622 }
24623 return rc;
24624 }
24625
24626 /*
24627 ** Lock the file with the lock specified by parameter eFileLock - one
24628 ** of the following:
24629 **
@@ -24408,11 +24757,11 @@
24757 if( eFileLock==SHARED_LOCK
24758 || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock<PENDING_LOCK)
24759 ){
24760 lock.l_type = (eFileLock==SHARED_LOCK?F_RDLCK:F_WRLCK);
24761 lock.l_start = PENDING_BYTE;
24762 s = unixFileLock(pFile, &lock);
24763 if( s==(-1) ){
24764 tErrno = errno;
24765 rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
24766 if( IS_LOCK_ERROR(rc) ){
24767 pFile->lastErrno = tErrno;
@@ -24430,18 +24779,18 @@
24779 assert( pInode->eFileLock==0 );
24780
24781 /* Now get the read-lock */
24782 lock.l_start = SHARED_FIRST;
24783 lock.l_len = SHARED_SIZE;
24784 if( (s = unixFileLock(pFile, &lock))==(-1) ){
24785 tErrno = errno;
24786 }
24787 /* Drop the temporary PENDING lock */
24788 lock.l_start = PENDING_BYTE;
24789 lock.l_len = 1L;
24790 lock.l_type = F_UNLCK;
24791 if( unixFileLock(pFile, &lock)!=0 ){
24792 if( s != -1 ){
24793 /* This could happen with a network mount */
24794 tErrno = errno;
24795 rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
24796 if( IS_LOCK_ERROR(rc) ){
@@ -24480,11 +24829,11 @@
24829 lock.l_len = SHARED_SIZE;
24830 break;
24831 default:
24832 assert(0);
24833 }
24834 s = unixFileLock(pFile, &lock);
24835 if( s==(-1) ){
24836 tErrno = errno;
24837 rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
24838 if( IS_LOCK_ERROR(rc) ){
24839 pFile->lastErrno = tErrno;
@@ -24549,11 +24898,11 @@
24898 ** the byte range is divided into 2 parts and the first part is unlocked then
24899 ** set to a read lock, then the other part is simply unlocked. This works
24900 ** around a bug in BSD NFS lockd (also seen on MacOSX 10.3+) that fails to
24901 ** remove the write lock on a region when a read lock is set.
24902 */
24903 static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
24904 unixFile *pFile = (unixFile*)id;
24905 unixInodeInfo *pInode;
24906 struct flock lock;
24907 int rc = SQLITE_OK;
24908 int h;
@@ -24605,10 +24954,11 @@
24954 ** 4: [RRRR.]
24955 */
24956 if( eFileLock==SHARED_LOCK ){
24957
24958 #if !defined(__APPLE__) || !SQLITE_ENABLE_LOCKING_STYLE
24959 (void)handleNFSUnlock;
24960 assert( handleNFSUnlock==0 );
24961 #endif
24962 #if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
24963 if( handleNFSUnlock ){
24964 off_t divSize = SHARED_SIZE - 1;
@@ -24615,11 +24965,11 @@
24965
24966 lock.l_type = F_UNLCK;
24967 lock.l_whence = SEEK_SET;
24968 lock.l_start = SHARED_FIRST;
24969 lock.l_len = divSize;
24970 if( unixFileLock(pFile,, &lock)==(-1) ){
24971 tErrno = errno;
24972 rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
24973 if( IS_LOCK_ERROR(rc) ){
24974 pFile->lastErrno = tErrno;
24975 }
@@ -24627,11 +24977,11 @@
24977 }
24978 lock.l_type = F_RDLCK;
24979 lock.l_whence = SEEK_SET;
24980 lock.l_start = SHARED_FIRST;
24981 lock.l_len = divSize;
24982 if( unixFileLock(pFile, &lock)==(-1) ){
24983 tErrno = errno;
24984 rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);
24985 if( IS_LOCK_ERROR(rc) ){
24986 pFile->lastErrno = tErrno;
24987 }
@@ -24639,11 +24989,11 @@
24989 }
24990 lock.l_type = F_UNLCK;
24991 lock.l_whence = SEEK_SET;
24992 lock.l_start = SHARED_FIRST+divSize;
24993 lock.l_len = SHARED_SIZE-divSize;
24994 if( unixFileLock(pFile, &lock)==(-1) ){
24995 tErrno = errno;
24996 rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
24997 if( IS_LOCK_ERROR(rc) ){
24998 pFile->lastErrno = tErrno;
24999 }
@@ -24654,11 +25004,11 @@
25004 {
25005 lock.l_type = F_RDLCK;
25006 lock.l_whence = SEEK_SET;
25007 lock.l_start = SHARED_FIRST;
25008 lock.l_len = SHARED_SIZE;
25009 if( unixFileLock(pFile, &lock)==(-1) ){
25010 tErrno = errno;
25011 rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);
25012 if( IS_LOCK_ERROR(rc) ){
25013 pFile->lastErrno = tErrno;
25014 }
@@ -24668,11 +25018,11 @@
25018 }
25019 lock.l_type = F_UNLCK;
25020 lock.l_whence = SEEK_SET;
25021 lock.l_start = PENDING_BYTE;
25022 lock.l_len = 2L; assert( PENDING_BYTE+1==RESERVED_BYTE );
25023 if( unixFileLock(pFile, &lock)!=(-1) ){
25024 pInode->eFileLock = SHARED_LOCK;
25025 }else{
25026 tErrno = errno;
25027 rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
25028 if( IS_LOCK_ERROR(rc) ){
@@ -24692,11 +25042,11 @@
25042 lock.l_whence = SEEK_SET;
25043 lock.l_start = lock.l_len = 0L;
25044 SimulateIOErrorBenign(1);
25045 SimulateIOError( h=(-1) )
25046 SimulateIOErrorBenign(0);
25047 if( unixFileLock(pFile, &lock)!=(-1) ){
25048 pInode->eFileLock = NO_LOCK;
25049 }else{
25050 tErrno = errno;
25051 rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
25052 if( IS_LOCK_ERROR(rc) ){
@@ -24730,11 +25080,11 @@
25080 **
25081 ** If the locking level of the file descriptor is already at or below
25082 ** the requested locking level, this routine is a no-op.
25083 */
25084 static int unixUnlock(sqlite3_file *id, int eFileLock){
25085 return posixUnlock(id, eFileLock, 0);
25086 }
25087
25088 /*
25089 ** This function performs the parts of the "close file" operation
25090 ** common to all locking schemes. It closes the directory and file
@@ -24780,10 +25130,12 @@
25130 int rc = SQLITE_OK;
25131 if( id ){
25132 unixFile *pFile = (unixFile *)id;
25133 unixUnlock(id, NO_LOCK);
25134 unixEnterMutex();
25135 assert( pFile->pInode==0 || pFile->pInode->nLock>0
25136 || pFile->pInode->bProcessLock==0 );
25137 if( pFile->pInode && pFile->pInode->nLock ){
25138 /* If there are outstanding locks, do not actually close the file just
25139 ** yet because that would clear those locks. Instead, add the file
25140 ** descriptor to pInode->pUnused list. It will be automatically closed
25141 ** when the last lock is cleared.
@@ -24894,11 +25246,11 @@
25246 ** holds a lock on the file. No need to check further. */
25247 reserved = 1;
25248 }else{
25249 /* The lock is held if and only if the lockfile exists */
25250 const char *zLockFile = (const char*)pFile->lockingContext;
25251 reserved = osAccess(zLockFile, 0)==0;
25252 }
25253 OSTRACE(("TEST WR-LOCK %d %d %d (dotlock)\n", pFile->h, rc, reserved));
25254 *pResOut = reserved;
25255 return rc;
25256 }
@@ -24948,11 +25300,11 @@
25300 #endif
25301 return SQLITE_OK;
25302 }
25303
25304 /* grab an exclusive lock */
25305 fd = robust_open(zLockFile,O_RDONLY|O_CREAT|O_EXCL,0600);
25306 if( fd<0 ){
25307 /* failed to open/create the file, someone else may have stolen the lock */
25308 int tErrno = errno;
25309 if( EEXIST == tErrno ){
25310 rc = SQLITE_BUSY;
@@ -25911,11 +26263,11 @@
26263 **
26264 ** If the locking level of the file descriptor is already at or below
26265 ** the requested locking level, this routine is a no-op.
26266 */
26267 static int nfsUnlock(sqlite3_file *id, int eFileLock){
26268 return posixUnlock(id, eFileLock, 1);
26269 }
26270
26271 #endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
26272 /*
26273 ** The code above is the NFS lock implementation. The code is specific
@@ -25953,14 +26305,14 @@
26305 #if (!defined(USE_PREAD) && !defined(USE_PREAD64))
26306 i64 newOffset;
26307 #endif
26308 TIMER_START;
26309 #if defined(USE_PREAD)
26310 do{ got = osPread(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR );
26311 SimulateIOError( got = -1 );
26312 #elif defined(USE_PREAD64)
26313 do{ got = osPread64(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR);
26314 SimulateIOError( got = -1 );
26315 #else
26316 newOffset = lseek(id->h, offset, SEEK_SET);
26317 SimulateIOError( newOffset-- );
26318 if( newOffset!=offset ){
@@ -25969,11 +26321,11 @@
26321 }else{
26322 ((unixFile*)id)->lastErrno = 0;
26323 }
26324 return -1;
26325 }
26326 do{ got = osRead(id->h, pBuf, cnt); }while( got<0 && errno==EINTR );
26327 #endif
26328 TIMER_END;
26329 if( got<0 ){
26330 ((unixFile*)id)->lastErrno = errno;
26331 }
@@ -26031,13 +26383,13 @@
26383 #if (!defined(USE_PREAD) && !defined(USE_PREAD64))
26384 i64 newOffset;
26385 #endif
26386 TIMER_START;
26387 #if defined(USE_PREAD)
26388 do{ got = osPwrite(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR );
26389 #elif defined(USE_PREAD64)
26390 do{ got = osPwrite64(id->h, pBuf, cnt, offset);}while( got<0 && errno==EINTR);
26391 #else
26392 newOffset = lseek(id->h, offset, SEEK_SET);
26393 if( newOffset!=offset ){
26394 if( newOffset == -1 ){
26395 ((unixFile*)id)->lastErrno = errno;
@@ -26044,11 +26396,11 @@
26396 }else{
26397 ((unixFile*)id)->lastErrno = 0;
26398 }
26399 return -1;
26400 }
26401 do{ got = osWrite(id->h, pBuf, cnt); }while( got<0 && errno==EINTR );
26402 #endif
26403 TIMER_END;
26404 if( got<0 ){
26405 ((unixFile*)id)->lastErrno = errno;
26406 }
@@ -26212,11 +26564,11 @@
26564 */
26565 #ifdef SQLITE_NO_SYNC
26566 rc = SQLITE_OK;
26567 #elif HAVE_FULLFSYNC
26568 if( fullSync ){
26569 rc = osFcntl(fd, F_FULLFSYNC, 0);
26570 }else{
26571 rc = 1;
26572 }
26573 /* If the FULLFSYNC failed, fall back to attempting an fsync().
26574 ** It shouldn't be possible for fullfsync to fail on the local
@@ -26359,11 +26711,11 @@
26711 */
26712 static int unixFileSize(sqlite3_file *id, i64 *pSize){
26713 int rc;
26714 struct stat buf;
26715 assert( id );
26716 rc = osFstat(((unixFile*)id)->h, &buf);
26717 SimulateIOError( rc=1 );
26718 if( rc!=0 ){
26719 ((unixFile*)id)->lastErrno = errno;
26720 return SQLITE_IOERR_FSTAT;
26721 }
@@ -26400,18 +26752,18 @@
26752 static int fcntlSizeHint(unixFile *pFile, i64 nByte){
26753 if( pFile->szChunk ){
26754 i64 nSize; /* Required file size */
26755 struct stat buf; /* Used to hold return values of fstat() */
26756
26757 if( osFstat(pFile->h, &buf) ) return SQLITE_IOERR_FSTAT;
26758
26759 nSize = ((nByte+pFile->szChunk-1) / pFile->szChunk) * pFile->szChunk;
26760 if( nSize>(i64)buf.st_size ){
26761 #if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
26762 int rc;
26763 do{
26764 rc = osFallocate(pFile->.h, buf.st_size, nSize-buf.st_size;
26765 }while( rc<0 && errno=EINTR );
26766 if( rc ) return SQLITE_IOERR_WRITE;
26767 #else
26768 /* If the OS does not have posix_fallocate(), fake it. First use
26769 ** ftruncate() to set the file size, then write a single byte to
@@ -26608,19 +26960,21 @@
26960 assert( n==1 || lockType!=F_RDLCK );
26961
26962 /* Locks are within range */
26963 assert( n>=1 && n<SQLITE_SHM_NLOCK );
26964
26965 if( pShmNode->h>=0 ){
26966 /* Initialize the locking parameters */
26967 memset(&f, 0, sizeof(f));
26968 f.l_type = lockType;
26969 f.l_whence = SEEK_SET;
26970 f.l_start = ofst;
26971 f.l_len = n;
26972
26973 rc = osFcntl(pShmNode->h, F_SETLK, &f);
26974 rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY;
26975 }
26976
26977 /* Update the global lock state and do debug tracing */
26978 #ifdef SQLITE_DEBUG
26979 { u16 mask;
26980 OSTRACE(("SHM-LOCK "));
@@ -26671,11 +27025,15 @@
27025 if( p && p->nRef==0 ){
27026 int i;
27027 assert( p->pInode==pFd->pInode );
27028 if( p->mutex ) sqlite3_mutex_free(p->mutex);
27029 for(i=0; i<p->nRegion; i++){
27030 if( p->h>=0 ){
27031 munmap(p->apRegion[i], p->szRegion);
27032 }else{
27033 sqlite3_free(p->apRegion[i]);
27034 }
27035 }
27036 sqlite3_free(p->apRegion);
27037 if( p->h>=0 ){
27038 robust_close(pFd, p->h, __LINE__);
27039 p->h = -1;
@@ -26711,10 +27069,16 @@
27069 ** "unsupported" and may go away in a future SQLite release.
27070 **
27071 ** When opening a new shared-memory file, if no other instances of that
27072 ** file are currently open, in this process or in other processes, then
27073 ** the file must be truncated to zero length or have its header cleared.
27074 **
27075 ** If the original database file (pDbFd) is using the "unix-excl" VFS
27076 ** that means that an exclusive lock is held on the database file and
27077 ** that no other processes are able to read or write the database. In
27078 ** that case, we do not really need shared memory. No shared memory
27079 ** file is created. The shared memory will be simulated with heap memory.
27080 */
27081 static int unixOpenSharedMemory(unixFile *pDbFd){
27082 struct unixShm *p = 0; /* The connection to be opened */
27083 struct unixShmNode *pShmNode; /* The underlying mmapped file */
27084 int rc; /* Result code */
@@ -26740,11 +27104,11 @@
27104 /* Call fstat() to figure out the permissions on the database file. If
27105 ** a new *-shm file is created, an attempt will be made to create it
27106 ** with the same permissions. The actual permissions the file is created
27107 ** with are subject to the current umask setting.
27108 */
27109 if( osFstat(pDbFd->h, &sStat) && pInode->bProcessLock==0 ){
27110 rc = SQLITE_IOERR_FSTAT;
27111 goto shm_open_err;
27112 }
27113
27114 #ifdef SQLITE_SHM_DIRECTORY
@@ -26773,29 +27137,32 @@
27137 if( pShmNode->mutex==0 ){
27138 rc = SQLITE_NOMEM;
27139 goto shm_open_err;
27140 }
27141
27142 if( pInode->bProcessLock==0 ){
27143 pShmNode->h = robust_open(zShmFilename, O_RDWR|O_CREAT,
27144 (sStat.st_mode & 0777));
27145 if( pShmNode->h<0 ){
27146 rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename);
27147 goto shm_open_err;
27148 }
27149
27150 /* Check to see if another process is holding the dead-man switch.
27151 ** If not, truncate the file to zero length.
27152 */
27153 rc = SQLITE_OK;
27154 if( unixShmSystemLock(pShmNode, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){
27155 if( robust_ftruncate(pShmNode->h, 0) ){
27156 rc = unixLogError(SQLITE_IOERR_SHMOPEN, "ftruncate", zShmFilename);
27157 }
27158 }
27159 if( rc==SQLITE_OK ){
27160 rc = unixShmSystemLock(pShmNode, F_RDLCK, UNIX_SHM_DMS, 1);
27161 }
27162 if( rc ) goto shm_open_err;
27163 }
27164 }
27165
27166 /* Make the new connection a child of the unixShmNode */
27167 p->pShmNode = pShmNode;
27168 #ifdef SQLITE_DEBUG
@@ -26865,38 +27232,44 @@
27232
27233 p = pDbFd->pShm;
27234 pShmNode = p->pShmNode;
27235 sqlite3_mutex_enter(pShmNode->mutex);
27236 assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
27237 assert( pShmNode->pInode==pDbFd->pInode );
27238 assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 );
27239 assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 );
27240
27241 if( pShmNode->nRegion<=iRegion ){
27242 char **apNew; /* New apRegion[] array */
27243 int nByte = (iRegion+1)*szRegion; /* Minimum required file size */
27244 struct stat sStat; /* Used by fstat() */
27245
27246 pShmNode->szRegion = szRegion;
27247
27248 if( pShmNode->h>=0 ){
27249 /* The requested region is not mapped into this processes address space.
27250 ** Check to see if it has been allocated (i.e. if the wal-index file is
27251 ** large enough to contain the requested region).
27252 */
27253 if( osFstat(pShmNode->h, &sStat) ){
27254 rc = SQLITE_IOERR_SHMSIZE;
27255 goto shmpage_out;
27256 }
27257
27258 if( sStat.st_size<nByte ){
27259 /* The requested memory region does not exist. If bExtend is set to
27260 ** false, exit early. *pp will be set to NULL and SQLITE_OK returned.
27261 **
27262 ** Alternatively, if bExtend is true, use ftruncate() to allocate
27263 ** the requested memory region.
27264 */
27265 if( !bExtend ) goto shmpage_out;
27266 if( robust_ftruncate(pShmNode->h, nByte) ){
27267 rc = unixLogError(SQLITE_IOERR_SHMSIZE, "ftruncate",
27268 pShmNode->zFilename);
27269 goto shmpage_out;
27270 }
27271 }
27272 }
27273
27274 /* Map the requested memory region into this processes address space. */
27275 apNew = (char **)sqlite3_realloc(
@@ -26906,16 +27279,26 @@
27279 rc = SQLITE_IOERR_NOMEM;
27280 goto shmpage_out;
27281 }
27282 pShmNode->apRegion = apNew;
27283 while(pShmNode->nRegion<=iRegion){
27284 void *pMem;
27285 if( pShmNode->h>=0 ){
27286 pMem = mmap(0, szRegion, PROT_READ|PROT_WRITE,
27287 MAP_SHARED, pShmNode->h, pShmNode->nRegion*szRegion
27288 );
27289 if( pMem==MAP_FAILED ){
27290 rc = SQLITE_IOERR;
27291 goto shmpage_out;
27292 }
27293 }else{
27294 pMem = sqlite3_malloc(szRegion);
27295 if( pMem==0 ){
27296 rc = SQLITE_NOMEM;
27297 goto shmpage_out;
27298 }
27299 memset(pMem, 0, szRegion);
27300 }
27301 pShmNode->apRegion[pShmNode->nRegion] = pMem;
27302 pShmNode->nRegion++;
27303 }
27304 }
@@ -26958,10 +27341,12 @@
27341 assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED)
27342 || flags==(SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE)
27343 || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED)
27344 || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
27345 assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
27346 assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 );
27347 assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 );
27348
27349 mask = (1<<(ofst+n)) - (1<<ofst);
27350 assert( n>1 || mask==(1<<ofst) );
27351 sqlite3_mutex_enter(pShmNode->mutex);
27352 if( flags & SQLITE_SHM_UNLOCK ){
@@ -27095,11 +27480,11 @@
27480 ** shared-memory file, too */
27481 unixEnterMutex();
27482 assert( pShmNode->nRef>0 );
27483 pShmNode->nRef--;
27484 if( pShmNode->nRef==0 ){
27485 if( deleteFlag && pShmNode->h>=0 ) unlink(pShmNode->zFilename);
27486 unixShmPurge(pDbFd);
27487 }
27488 unixLeaveMutex();
27489
27490 return SQLITE_OK;
@@ -27336,11 +27721,11 @@
27721 */
27722 lockInfo.l_len = 1;
27723 lockInfo.l_start = 0;
27724 lockInfo.l_whence = SEEK_SET;
27725 lockInfo.l_type = F_RDLCK;
27726 if( osFcntl(pNew->h, F_GETLK, &lockInfo)!=-1 ) {
27727 if( strcmp(fsInfo.f_fstypename, "nfs")==0 ){
27728 return &nfsIoMethods;
27729 } else {
27730 return &posixIoMethods;
27731 }
@@ -27378,11 +27763,11 @@
27763 */
27764 lockInfo.l_len = 1;
27765 lockInfo.l_start = 0;
27766 lockInfo.l_whence = SEEK_SET;
27767 lockInfo.l_type = F_RDLCK;
27768 if( osFcntl(pNew->h, F_GETLK, &lockInfo)!=-1 ) {
27769 return &posixIoMethods;
27770 }else{
27771 return &semIoMethods;
27772 }
27773 }
@@ -27412,11 +27797,12 @@
27797 int h, /* Open file descriptor of file being opened */
27798 int dirfd, /* Directory file descriptor */
27799 sqlite3_file *pId, /* Write to the unixFile structure here */
27800 const char *zFilename, /* Name of the file being opened */
27801 int noLock, /* Omit locking if true */
27802 int isDelete, /* Delete on close if true */
27803 int isReadOnly /* True if the file is opened read-only */
27804 ){
27805 const sqlite3_io_methods *pLockingStyle;
27806 unixFile *pNew = (unixFile *)pId;
27807 int rc = SQLITE_OK;
27808
@@ -27439,12 +27825,19 @@
27825 #endif
27826
27827 OSTRACE(("OPEN %-3d %s\n", h, zFilename));
27828 pNew->h = h;
27829 pNew->dirfd = dirfd;
 
27830 pNew->zPath = zFilename;
27831 if( memcmp(pVfs->zName,"unix-excl",10)==0 ){
27832 pNew->ctrlFlags = UNIXFILE_EXCL;
27833 }else{
27834 pNew->ctrlFlags = 0;
27835 }
27836 if( isReadOnly ){
27837 pNew->ctrlFlags |= UNIXFILE_RDONLY;
27838 }
27839
27840 #if OS_VXWORKS
27841 pNew->pId = vxworksFindFileId(zFilename);
27842 if( pNew->pId==0 ){
27843 noLock = 1;
@@ -27601,14 +27994,14 @@
27994
27995 sqlite3_snprintf(MAX_PATHNAME, zDirname, "%s", zFilename);
27996 for(ii=(int)strlen(zDirname); ii>1 && zDirname[ii]!='/'; ii--);
27997 if( ii>0 ){
27998 zDirname[ii] = '\0';
27999 fd = robust_open(zDirname, O_RDONLY|O_BINARY, 0);
28000 if( fd>=0 ){
28001 #ifdef FD_CLOEXEC
28002 osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
28003 #endif
28004 OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname));
28005 }
28006 }
28007 *pFd = fd;
@@ -27634,13 +28027,13 @@
28027
28028 azDirs[0] = sqlite3_temp_directory;
28029 if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR");
28030 for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); zDir=azDirs[i++]){
28031 if( zDir==0 ) continue;
28032 if( osStat(zDir, &buf) ) continue;
28033 if( !S_ISDIR(buf.st_mode) ) continue;
28034 if( osAccess(zDir, 07) ) continue;
28035 break;
28036 }
28037 return zDir;
28038 }
28039
@@ -27679,11 +28072,11 @@
28072 sqlite3_randomness(15, &zBuf[j]);
28073 for(i=0; i<15; i++, j++){
28074 zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
28075 }
28076 zBuf[j] = 0;
28077 }while( osAccess(zBuf,0)==0 );
28078 return SQLITE_OK;
28079 }
28080
28081 #if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
28082 /*
@@ -27940,19 +28333,20 @@
28333 if( rc!=SQLITE_OK ){
28334 assert( !p->pUnused );
28335 assert( eType==SQLITE_OPEN_WAL || eType==SQLITE_OPEN_MAIN_JOURNAL );
28336 return rc;
28337 }
28338 fd = robust_open(zName, openFlags, openMode);
28339 OSTRACE(("OPENX %-3d %s 0%o\n", fd, zName, openFlags));
28340 if( fd<0 && errno!=EISDIR && isReadWrite && !isExclusive ){
28341 /* Failed to open the file for read/write access. Try read-only. */
28342 flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
28343 openFlags &= ~(O_RDWR|O_CREAT);
28344 flags |= SQLITE_OPEN_READONLY;
28345 openFlags |= O_RDONLY;
28346 isReadonly = 1;
28347 fd = robust_open(zName, openFlags, openMode);
28348 }
28349 if( fd<0 ){
28350 rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
28351 goto open_finished;
28352 }
@@ -27992,11 +28386,11 @@
28386 goto open_finished;
28387 }
28388 }
28389
28390 #ifdef FD_CLOEXEC
28391 osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
28392 #endif
28393
28394 noLock = eType!=SQLITE_OPEN_MAIN_DB;
28395
28396
@@ -28044,11 +28438,12 @@
28438 goto open_finished;
28439 }
28440 useProxy = !(fsInfo.f_flags&MNT_LOCAL);
28441 }
28442 if( useProxy ){
28443 rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock,
28444 isDelete, isReadonly);
28445 if( rc==SQLITE_OK ){
28446 rc = proxyTransformUnixFile((unixFile*)pFile, ":auto:");
28447 if( rc!=SQLITE_OK ){
28448 /* Use unixClose to clean up the resources added in fillInUnixFile
28449 ** and clear all the structure's references. Specifically,
@@ -28061,11 +28456,12 @@
28456 goto open_finished;
28457 }
28458 }
28459 #endif
28460
28461 rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock,
28462 isDelete, isReadonly);
28463 open_finished:
28464 if( rc!=SQLITE_OK ){
28465 sqlite3_free(p->pUnused);
28466 }
28467 return rc;
@@ -28138,11 +28534,11 @@
28534 break;
28535
28536 default:
28537 assert(!"Invalid flags argument");
28538 }
28539 *pResOut = (osAccess(zPath, amode)==0);
28540 if( flags==SQLITE_ACCESS_EXISTS && *pResOut ){
28541 struct stat buf;
28542 if( 0==stat(zPath, &buf) && buf.st_size==0 ){
28543 *pResOut = 0;
28544 }
@@ -28180,11 +28576,11 @@
28576 zOut[nOut-1] = '\0';
28577 if( zPath[0]=='/' ){
28578 sqlite3_snprintf(nOut, zOut, "%s", zPath);
28579 }else{
28580 int nCwd;
28581 if( osGetcwd(zOut, nOut-1)==0 ){
28582 return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath);
28583 }
28584 nCwd = (int)strlen(zOut);
28585 sqlite3_snprintf(nOut-nCwd, &zOut[nCwd], "/%s", zPath);
28586 }
@@ -28275,21 +28671,21 @@
28671 */
28672 memset(zBuf, 0, nBuf);
28673 #if !defined(SQLITE_TEST)
28674 {
28675 int pid, fd;
28676 fd = robust_open("/dev/urandom", O_RDONLY, 0);
28677 if( fd<0 ){
28678 time_t t;
28679 time(&t);
28680 memcpy(zBuf, &t, sizeof(t));
28681 pid = getpid();
28682 memcpy(&zBuf[sizeof(t)], &pid, sizeof(pid));
28683 assert( sizeof(t)+sizeof(pid)<=(size_t)nBuf );
28684 nBuf = sizeof(t) + sizeof(pid);
28685 }else{
28686 do{ nBuf = osRead(fd, zBuf, nBuf); }while( nBuf<0 && errno==EINTR );
28687 robust_close(0, fd, __LINE__);
28688 }
28689 }
28690 #endif
28691 return nBuf;
@@ -28684,21 +29080,21 @@
29080 if( !pUnused ){
29081 return SQLITE_NOMEM;
29082 }
29083 }
29084 if( fd<0 ){
29085 fd = robust_open(path, openFlags, SQLITE_DEFAULT_FILE_PERMISSIONS);
29086 terrno = errno;
29087 if( fd<0 && errno==ENOENT && islockfile ){
29088 if( proxyCreateLockPath(path) == SQLITE_OK ){
29089 fd = robust_open(path, openFlags, SQLITE_DEFAULT_FILE_PERMISSIONS);
29090 }
29091 }
29092 }
29093 if( fd<0 ){
29094 openFlags = O_RDONLY;
29095 fd = robust_open(path, openFlags, SQLITE_DEFAULT_FILE_PERMISSIONS);
29096 terrno = errno;
29097 }
29098 if( fd<0 ){
29099 if( islockfile ){
29100 return SQLITE_BUSY;
@@ -28723,11 +29119,11 @@
29119 dummyVfs.pAppData = (void*)&autolockIoFinder;
29120 pUnused->fd = fd;
29121 pUnused->flags = openFlags;
29122 pNew->pUnused = pUnused;
29123
29124 rc = fillInUnixFile(&dummyVfs, fd, dirfd, (sqlite3_file*)pNew, path, 0, 0, 0);
29125 if( rc==SQLITE_OK ){
29126 *ppFile = pNew;
29127 return SQLITE_OK;
29128 }
29129 end_create_proxy:
@@ -28808,22 +29204,23 @@
29204 (strlcpy(&tPath[pathLen-5], "break", 6) != 5) ){
29205 sqlite3_snprintf(sizeof(errmsg),errmsg,"path error (len %d)",(int)pathLen);
29206 goto end_breaklock;
29207 }
29208 /* read the conch content */
29209 readLen = osPread(conchFile->h, buf, PROXY_MAXCONCHLEN, 0);
29210 if( readLen<PROXY_PATHINDEX ){
29211 sqlite3_snprintf(sizeof(errmsg),errmsg,"read error (len %d)",(int)readLen);
29212 goto end_breaklock;
29213 }
29214 /* write it out to the temporary break file */
29215 fd = robust_open(tPath, (O_RDWR|O_CREAT|O_EXCL),
29216 SQLITE_DEFAULT_FILE_PERMISSIONS);
29217 if( fd<0 ){
29218 sqlite3_snprintf(sizeof(errmsg), errmsg, "create failed (%d)", errno);
29219 goto end_breaklock;
29220 }
29221 if( osPwrite(fd, buf, readLen, 0) != (ssize_t)readLen ){
29222 sqlite3_snprintf(sizeof(errmsg), errmsg, "write failed (%d)", errno);
29223 goto end_breaklock;
29224 }
29225 if( rename(tPath, cPath) ){
29226 sqlite3_snprintf(sizeof(errmsg), errmsg, "rename failed (%d)", errno);
@@ -28865,11 +29262,11 @@
29262 * 2nd try: fail if the mod time changed or host id is different, wait
29263 * 10 sec and try again
29264 * 3rd try: break the lock unless the mod time has changed.
29265 */
29266 struct stat buf;
29267 if( osFstat(conchFile->h, &buf) ){
29268 pFile->lastErrno = errno;
29269 return SQLITE_IOERR_LOCK;
29270 }
29271
29272 if( nTries==1 ){
@@ -28884,11 +29281,11 @@
29281 return SQLITE_BUSY;
29282 }
29283
29284 if( nTries==2 ){
29285 char tBuf[PROXY_MAXCONCHLEN];
29286 int len = osPread(conchFile->h, tBuf, PROXY_MAXCONCHLEN, 0);
29287 if( len<0 ){
29288 pFile->lastErrno = errno;
29289 return SQLITE_IOERR_LOCK;
29290 }
29291 if( len>PROXY_PATHINDEX && tBuf[0]==(char)PROXY_CONCHVERSION){
@@ -29054,20 +29451,20 @@
29451 /* If we created a new conch file (not just updated the contents of a
29452 ** valid conch file), try to match the permissions of the database
29453 */
29454 if( rc==SQLITE_OK && createConch ){
29455 struct stat buf;
29456 int err = osFstat(pFile->h, &buf);
29457 if( err==0 ){
29458 mode_t cmode = buf.st_mode&(S_IRUSR|S_IWUSR | S_IRGRP|S_IWGRP |
29459 S_IROTH|S_IWOTH);
29460 /* try to match the database file R/W permissions, ignore failure */
29461 #ifndef SQLITE_PROXY_DEBUG
29462 osFchmod(conchFile->h, cmode);
29463 #else
29464 do{
29465 rc = osFchmod(conchFile->h, cmode);
29466 }while( rc==(-1) && errno==EINTR );
29467 if( rc!=0 ){
29468 int code = errno;
29469 fprintf(stderr, "fchmod %o FAILED with %d %s\n",
29470 cmode, code, strerror(code));
@@ -29089,11 +29486,11 @@
29486 if( rc==SQLITE_OK && pFile->openFlags ){
29487 if( pFile->h>=0 ){
29488 robust_close(pFile, pFile->h, __LINE__);
29489 }
29490 pFile->h = -1;
29491 int fd = robust_open(pCtx->dbPath, pFile->openFlags,
29492 SQLITE_DEFAULT_FILE_PERMISSIONS);
29493 OSTRACE(("TRANSPROXY: OPEN %d\n", fd));
29494 if( fd>=0 ){
29495 pFile->h = fd;
29496 }else{
@@ -29315,11 +29712,11 @@
29712 */
29713 struct statfs fsInfo;
29714 struct stat conchInfo;
29715 int goLockless = 0;
29716
29717 if( osStat(pCtx->conchFilePath, &conchInfo) == -1 ) {
29718 int err = errno;
29719 if( (err==ENOENT) && (statfs(dbPath, &fsInfo) != -1) ){
29720 goLockless = (fsInfo.f_flags&MNT_RDONLY) == MNT_RDONLY;
29721 }
29722 }
@@ -29600,11 +29997,11 @@
29997 ** more than that; it looks at the filesystem type that hosts the
29998 ** database file and tries to choose an locking method appropriate for
29999 ** that filesystem time.
30000 */
30001 #define UNIXVFS(VFSNAME, FINDER) { \
30002 3, /* iVersion */ \
30003 sizeof(unixFile), /* szOsFile */ \
30004 MAX_PATHNAME, /* mxPathname */ \
30005 0, /* pNext */ \
30006 VFSNAME, /* zName */ \
30007 (void*)&FINDER, /* pAppData */ \
@@ -29619,10 +30016,13 @@
30016 unixRandomness, /* xRandomness */ \
30017 unixSleep, /* xSleep */ \
30018 unixCurrentTime, /* xCurrentTime */ \
30019 unixGetLastError, /* xGetLastError */ \
30020 unixCurrentTimeInt64, /* xCurrentTimeInt64 */ \
30021 unixSetSystemCall, /* xSetSystemCall */ \
30022 unixGetSystemCall, /* xGetSystemCall */ \
30023 unixNextSystemCall, /* xNextSystemCall */ \
30024 }
30025
30026 /*
30027 ** All default VFSes for unix are contained in the following array.
30028 **
@@ -29636,10 +30036,11 @@
30036 #else
30037 UNIXVFS("unix", posixIoFinder ),
30038 #endif
30039 UNIXVFS("unix-none", nolockIoFinder ),
30040 UNIXVFS("unix-dotfile", dotlockIoFinder ),
30041 UNIXVFS("unix-excl", posixIoFinder ),
30042 #if OS_VXWORKS
30043 UNIXVFS("unix-namedsem", semIoFinder ),
30044 #endif
30045 #if SQLITE_ENABLE_LOCKING_STYLE
30046 UNIXVFS("unix-posix", posixIoFinder ),
@@ -32626,11 +33027,11 @@
33027 /*
33028 ** Initialize and deinitialize the operating system interface.
33029 */
33030 SQLITE_API int sqlite3_os_init(void){
33031 static sqlite3_vfs winVfs = {
33032 3, /* iVersion */
33033 sizeof(winFile), /* szOsFile */
33034 MAX_PATH, /* mxPathname */
33035 0, /* pNext */
33036 "win32", /* zName */
33037 0, /* pAppData */
@@ -32645,10 +33046,13 @@
33046 winRandomness, /* xRandomness */
33047 winSleep, /* xSleep */
33048 winCurrentTime, /* xCurrentTime */
33049 winGetLastError, /* xGetLastError */
33050 winCurrentTimeInt64, /* xCurrentTimeInt64 */
33051 0, /* xSetSystemCall */
33052 0, /* xGetSystemCall */
33053 0, /* xNextSystemCall */
33054 };
33055
33056 #ifndef SQLITE_OMIT_WAL
33057 /* get memory map allocation granularity */
33058 memset(&winSysInfo, 0, sizeof(SYSTEM_INFO));
@@ -50782,15 +51186,13 @@
51186 }
51187 if( nearby>0 ){
51188 u32 i;
51189 int dist;
51190 closest = 0;
51191 dist = sqlite3AbsInt32(get4byte(&aData[8]) - nearby);
 
51192 for(i=1; i<k; i++){
51193 int d2 = sqlite3AbsInt32(get4byte(&aData[8+i*4]) - nearby);
 
51194 if( d2<dist ){
51195 closest = i;
51196 dist = d2;
51197 }
51198 }
@@ -55777,13 +56179,18 @@
56179 }
56180 }else if( op==TK_UMINUS ) {
56181 /* This branch happens for multiple negative signs. Ex: -(-5) */
56182 if( SQLITE_OK==sqlite3ValueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal) ){
56183 sqlite3VdbeMemNumerify(pVal);
56184 if( pVal->u.i==SMALLEST_INT64 ){
56185 pVal->flags &= MEM_Int;
56186 pVal->flags |= MEM_Real;
56187 pVal->r = (double)LARGEST_INT64;
56188 }else{
56189 pVal->u.i = -pVal->u.i;
56190 }
56191 pVal->r = -pVal->r;
56192 sqlite3ValueApplyAffinity(pVal, affinity, enc);
56193 }
56194 }else if( op==TK_NULL ){
56195 pVal = sqlite3ValueNew(db);
56196 if( pVal==0 ) goto no_mem;
@@ -56805,12 +57212,12 @@
57212 ** will be used so that it can acquire mutexes on them all in sorted
57213 ** order (via sqlite3VdbeMutexArrayEnter(). Mutexes are acquired
57214 ** in order (and released in reverse order) to avoid deadlocks.
57215 */
57216 SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe *p, int i){
57217 tAttachMask mask;
57218 assert( i>=0 && i<p->db->nDb && i<sizeof(tAttachMask)*8 );
57219 assert( i<(int)sizeof(p->btreeMask)*8 );
57220 mask = ((u32)1)<<i;
57221 if( (p->btreeMask & mask)==0 ){
57222 p->btreeMask |= mask;
57223 sqlite3BtreeMutexArrayInsert(&p->aMutex, p->db->aDb[i].pBt);
@@ -61309,10 +61716,11 @@
61716 struct OP_SetCookie_stack_vars {
61717 Db *pDb;
61718 } au;
61719 struct OP_VerifyCookie_stack_vars {
61720 int iMeta;
61721 int iGen;
61722 Btree *pBt;
61723 } av;
61724 struct OP_OpenWrite_stack_vars {
61725 int nField;
61726 KeyInfo *pKeyInfo;
@@ -63931,14 +64339,16 @@
64339 p->expired = 0;
64340 }
64341 break;
64342 }
64343
64344 /* Opcode: VerifyCookie P1 P2 P3 * *
64345 **
64346 ** Check the value of global database parameter number 0 (the
64347 ** schema version) and make sure it is equal to P2 and that the
64348 ** generation counter on the local schema parse equals P3.
64349 **
64350 ** P1 is the database number which is 0 for the main database file
64351 ** and 1 for the file holding temporary tables and some higher number
64352 ** for auxiliary databases.
64353 **
64354 ** The cookie changes its value whenever the database schema changes.
@@ -63950,21 +64360,24 @@
64360 ** invoked.
64361 */
64362 case OP_VerifyCookie: {
64363 #if 0 /* local variables moved into u.av */
64364 int iMeta;
64365 int iGen;
64366 Btree *pBt;
64367 #endif /* local variables moved into u.av */
64368
64369 assert( pOp->p1>=0 && pOp->p1<db->nDb );
64370 assert( (p->btreeMask & (1<<pOp->p1))!=0 );
64371 u.av.pBt = db->aDb[pOp->p1].pBt;
64372 if( u.av.pBt ){
64373 sqlite3BtreeGetMeta(u.av.pBt, BTREE_SCHEMA_VERSION, (u32 *)&u.av.iMeta);
64374 u.av.iGen = db->aDb[pOp->p1].pSchema->iGeneration;
64375 }else{
64376 u.av.iMeta = 0;
64377 }
64378 if( u.av.iMeta!=pOp->p2 || u.av.iGen!=pOp->p3 ){
64379 sqlite3DbFree(db, p->zErrMsg);
64380 p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed");
64381 /* If the schema-cookie from the database file matches the cookie
64382 ** stored with the in-memory representation of the schema, do
64383 ** not reload the schema from the database file.
@@ -65694,18 +66107,14 @@
66107 rc = sqlite3BtreeCreateTable(u.bt.pDb->pBt, &u.bt.pgno, u.bt.flags);
66108 pOut->u.i = u.bt.pgno;
66109 break;
66110 }
66111
66112 /* Opcode: ParseSchema P1 * * P4 *
66113 **
66114 ** Read and parse all entries from the SQLITE_MASTER table of database P1
66115 ** that match the WHERE clause P4.
 
 
 
 
66116 **
66117 ** This opcode invokes the parser to create a new virtual machine,
66118 ** then runs the new virtual machine. It is thus a re-entrant opcode.
66119 */
66120 case OP_ParseSchema: {
@@ -65717,18 +66126,11 @@
66126 #endif /* local variables moved into u.bu */
66127
66128 u.bu.iDb = pOp->p1;
66129 assert( u.bu.iDb>=0 && u.bu.iDb<db->nDb );
66130
66131 /* Although the mutex on the BtShared object that corresponds to
 
 
 
 
 
 
 
66132 ** database u.bu.iDb (the database containing the sqlite_master table
66133 ** read by this instruction) is currently held, it is necessary to
66134 ** obtain the mutexes on all attached databases before checking if
66135 ** the schema of u.bu.iDb is loaded. This is because, at the start of
66136 ** the sqlite3_exec() call below, SQLite will invoke
@@ -65740,11 +66142,11 @@
66142 ** can result in a "no such table: sqlite_master" or "malformed
66143 ** database schema" error being returned to the user.
66144 */
66145 assert( sqlite3BtreeHoldsMutex(db->aDb[u.bu.iDb].pBt) );
66146 sqlite3BtreeEnterAll(db);
66147 if( ALWAYS(DbHasProperty(db, u.bu.iDb, DB_SchemaLoaded)) ){
66148 u.bu.zMaster = SCHEMA_TABLE(u.bu.iDb);
66149 u.bu.initData.db = db;
66150 u.bu.initData.iDb = pOp->p1;
66151 u.bu.initData.pzErrMsg = &p->zErrMsg;
66152 u.bu.zSql = sqlite3MPrintf(db,
@@ -67395,10 +67797,11 @@
67797 sqlite3VdbeChangeP2(v, 0, flags);
67798
67799 /* Configure the OP_VerifyCookie */
67800 sqlite3VdbeChangeP1(v, 1, iDb);
67801 sqlite3VdbeChangeP2(v, 1, pTab->pSchema->schema_cookie);
67802 sqlite3VdbeChangeP3(v, 1, pTab->pSchema->iGeneration);
67803
67804 /* Make sure a mutex is held on the table to be accessed */
67805 sqlite3VdbeUsesBtree(v, iDb);
67806
67807 /* Configure the OP_TableLock instruction */
@@ -69826,10 +70229,11 @@
70229
70230 if( pToken ){
70231 if( op!=TK_INTEGER || pToken->z==0
70232 || sqlite3GetInt32(pToken->z, &iValue)==0 ){
70233 nExtra = pToken->n+1;
70234 assert( iValue>=0 );
70235 }
70236 }
70237 pNew = sqlite3DbMallocZero(db, sizeof(Expr)+nExtra);
70238 if( pNew ){
70239 pNew->op = (u8)op;
@@ -70051,10 +70455,12 @@
70455 /*
70456 ** Recursively delete an expression tree.
70457 */
70458 SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3 *db, Expr *p){
70459 if( p==0 ) return;
70460 /* Sanity check: Assert that the IntValue is non-negative if it exists */
70461 assert( !ExprHasProperty(p, EP_IntValue) || p->u.iValue>=0 );
70462 if( !ExprHasAnyProperty(p, EP_TokenOnly) ){
70463 sqlite3ExprDelete(db, p->pLeft);
70464 sqlite3ExprDelete(db, p->pRight);
70465 if( !ExprHasProperty(p, EP_Reduced) && (p->flags2 & EP2_MallocedToken)!=0 ){
70466 sqlite3DbFree(db, p->u.zToken);
@@ -70660,17 +71066,10 @@
71066 }
71067 break;
71068 }
71069 default: break;
71070 }
 
 
 
 
 
 
 
71071 return rc;
71072 }
71073
71074 /*
71075 ** Return FALSE if there is no chance that the expression can be NULL.
@@ -71391,10 +71790,11 @@
71790 */
71791 static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
71792 Vdbe *v = pParse->pVdbe;
71793 if( pExpr->flags & EP_IntValue ){
71794 int i = pExpr->u.iValue;
71795 assert( i>=0 );
71796 if( negFlag ) i = -i;
71797 sqlite3VdbeAddOp2(v, OP_Integer, i, iMem);
71798 }else{
71799 int c;
71800 i64 value;
@@ -75655,19 +76055,21 @@
76055 ** set for each database that is used. Generate code to start a
76056 ** transaction on each used database and to verify the schema cookie
76057 ** on each used database.
76058 */
76059 if( pParse->cookieGoto>0 ){
76060 tAttachMask mask;
76061 int iDb;
76062 sqlite3VdbeJumpHere(v, pParse->cookieGoto-1);
76063 for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){
76064 if( (mask & pParse->cookieMask)==0 ) continue;
76065 sqlite3VdbeUsesBtree(v, iDb);
76066 sqlite3VdbeAddOp2(v,OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
76067 if( db->init.busy==0 ){
76068 sqlite3VdbeAddOp3(v, OP_VerifyCookie,
76069 iDb, pParse->cookieValue[iDb],
76070 db->aDb[iDb].pSchema->iGeneration);
76071 }
76072 }
76073 #ifndef SQLITE_OMIT_VIRTUALTABLE
76074 {
76075 int i;
@@ -75873,11 +76275,11 @@
76275 int len;
76276 Hash *pHash = &db->aDb[iDb].pSchema->idxHash;
76277
76278 len = sqlite3Strlen30(zIdxName);
76279 pIndex = sqlite3HashInsert(pHash, zIdxName, len, 0);
76280 if( ALWAYS(pIndex) ){
76281 if( pIndex->pTable->pIndex==pIndex ){
76282 pIndex->pTable->pIndex = pIndex->pNext;
76283 }else{
76284 Index *p;
76285 /* Justification of ALWAYS(); The index must be on the list of
@@ -78949,16 +79351,16 @@
79351 if( v==0 ) return; /* This only happens if there was a prior error */
79352 pToplevel->cookieGoto = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0)+1;
79353 }
79354 if( iDb>=0 ){
79355 sqlite3 *db = pToplevel->db;
79356 tAttachMask mask;
79357
79358 assert( iDb<db->nDb );
79359 assert( db->aDb[iDb].pBt!=0 || iDb==1 );
79360 assert( iDb<SQLITE_MAX_ATTACHED+2 );
79361 mask = ((tAttachMask)1)<<iDb;
79362 if( (pToplevel->cookieMask & mask)==0 ){
79363 pToplevel->cookieMask |= mask;
79364 pToplevel->cookieValue[iDb] = db->aDb[iDb].pSchema->schema_cookie;
79365 if( !OMIT_TEMPDB && iDb==1 ){
79366 sqlite3OpenTempDatabase(pToplevel);
@@ -78981,11 +79383,11 @@
79383 ** necessary to undo a write and the checkpoint should not be set.
79384 */
79385 SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){
79386 Parse *pToplevel = sqlite3ParseToplevel(pParse);
79387 sqlite3CodeVerifySchema(pParse, iDb);
79388 pToplevel->writeMask |= ((tAttachMask)1)<<iDb;
79389 pToplevel->isMultiWrite |= setStatement;
79390 }
79391
79392 /*
79393 ** Indicate that the statement currently under construction might write
@@ -79626,11 +80028,14 @@
80028 sqlite3DeleteTable(0, pTab);
80029 }
80030 sqlite3HashClear(&temp1);
80031 sqlite3HashClear(&pSchema->fkeyHash);
80032 pSchema->pSeqTab = 0;
80033 if( pSchema->flags & DB_SchemaLoaded ){
80034 pSchema->iGeneration++;
80035 pSchema->flags &= ~DB_SchemaLoaded;
80036 }
80037 }
80038
80039 /*
80040 ** Find and return the schema associated with a BTree. Create
80041 ** a new one if necessary.
@@ -84381,12 +84786,13 @@
84786 ** index and making sure that duplicate entries do not already exist.
84787 ** Add the new records to the indices as we go.
84788 */
84789 for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){
84790 int regIdx;
84791 #ifndef SQLITE_OMIT_UNIQUE_ENFORCEMENT
84792 int regR;
84793 #endif
84794 if( aRegIdx[iCur]==0 ) continue; /* Skip unused indices */
84795
84796 /* Create a key for accessing the index entry */
84797 regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn+1);
84798 for(i=0; i<pIdx->nColumn; i++){
@@ -84399,10 +84805,15 @@
84805 }
84806 sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i);
84807 sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn+1, aRegIdx[iCur]);
84808 sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v, pIdx), 0);
84809 sqlite3ExprCacheAffinityChange(pParse, regIdx, pIdx->nColumn+1);
84810
84811 #ifdef SQLITE_OMIT_UNIQUE_ENFORCEMENT
84812 sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn+1);
84813 continue; /* Treat pIdx as if it is not a UNIQUE index */
84814 #else
84815
84816 /* Find out what action to take in case there is an indexing conflict */
84817 onError = pIdx->onError;
84818 if( onError==OE_None ){
84819 sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn+1);
@@ -84473,10 +84884,11 @@
84884 break;
84885 }
84886 }
84887 sqlite3VdbeJumpHere(v, j3);
84888 sqlite3ReleaseTempReg(pParse, regR);
84889 #endif
84890 }
84891
84892 if( pbMayReplace ){
84893 *pbMayReplace = seenReplace;
84894 }
@@ -86501,12 +86913,11 @@
86913 addr = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
86914 sqlite3VdbeChangeP1(v, addr, iDb);
86915 sqlite3VdbeChangeP1(v, addr+1, iDb);
86916 sqlite3VdbeChangeP1(v, addr+6, SQLITE_DEFAULT_CACHE_SIZE);
86917 }else{
86918 int size = sqlite3AbsInt32(sqlite3Atoi(zRight));
 
86919 sqlite3BeginWriteOperation(pParse, 0, iDb);
86920 sqlite3VdbeAddOp2(v, OP_Integer, size, 1);
86921 sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_DEFAULT_CACHE_SIZE, 1);
86922 pDb->pSchema->cache_size = size;
86923 sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
@@ -86811,12 +87222,11 @@
87222 if( sqlite3StrICmp(zLeft,"cache_size")==0 ){
87223 if( sqlite3ReadSchema(pParse) ) goto pragma_out;
87224 if( !zRight ){
87225 returnSingleInt(pParse, "cache_size", pDb->pSchema->cache_size);
87226 }else{
87227 int size = sqlite3AbsInt32(sqlite3Atoi(zRight));
 
87228 pDb->pSchema->cache_size = size;
87229 sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
87230 }
87231 }else
87232
@@ -87920,13 +88330,12 @@
88330 DbSetProperty(db, iDb, DB_Empty);
88331 }
88332 pDb->pSchema->enc = ENC(db);
88333
88334 if( pDb->pSchema->cache_size==0 ){
88335 size = sqlite3AbsInt32(meta[BTREE_DEFAULT_CACHE_SIZE-1]);
88336 if( size==0 ){ size = SQLITE_DEFAULT_CACHE_SIZE; }
 
88337 pDb->pSchema->cache_size = size;
88338 sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
88339 }
88340
88341 /*
@@ -93787,12 +94196,16 @@
94196 int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
94197 ExprList *pChanges, /* Columns that change in an UPDATE statement */
94198 int *pMask /* OUT: Mask of TRIGGER_BEFORE|TRIGGER_AFTER */
94199 ){
94200 int mask = 0;
94201 Trigger *pList = 0;
94202 Trigger *p;
94203
94204 if( (pParse->db->flags & SQLITE_EnableTrigger)!=0 ){
94205 pList = sqlite3TriggerList(pParse, pTab);
94206 }
94207 assert( pList==0 || IsVirtual(pTab)==0 );
94208 for(p=pList; p; p=p->pNext){
94209 if( p->op==op && checkColumnOverlap(p->pColumns, pChanges) ){
94210 mask |= p->tr_tm;
94211 }
@@ -95642,11 +96055,11 @@
96055 v = sqlite3GetVdbe(pParse);
96056 sqlite3ChangeCookie(pParse, iDb);
96057
96058 sqlite3VdbeAddOp2(v, OP_Expire, 0, 0);
96059 zWhere = sqlite3MPrintf(db, "name='%q' AND type='table'", pTab->zName);
96060 sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC);
96061 sqlite3VdbeAddOp4(v, OP_VCreate, iDb, 0, 0,
96062 pTab->zName, sqlite3Strlen30(pTab->zName) + 1);
96063 }
96064
96065 /* If we are rereading the sqlite_master table create the in-memory
@@ -98732,11 +99145,12 @@
99145 /*
99146 ** Estimate the number of rows that will be returned based on
99147 ** an equality constraint x=VALUE and where that VALUE occurs in
99148 ** the histogram data. This only works when x is the left-most
99149 ** column of an index and sqlite_stat2 histogram data is available
99150 ** for that index. When pExpr==NULL that means the constraint is
99151 ** "x IS NULL" instead of "x=VALUE".
99152 **
99153 ** Write the estimated row count into *pnRow and return SQLITE_OK.
99154 ** If unable to make an estimate, leave *pnRow unchanged and return
99155 ** non-zero.
99156 **
@@ -98757,12 +99171,16 @@
99171 int rc; /* Subfunction return code */
99172 double nRowEst; /* New estimate of the number of rows */
99173
99174 assert( p->aSample!=0 );
99175 aff = p->pTable->aCol[p->aiColumn[0]].affinity;
99176 if( pExpr ){
99177 rc = valueFromExpr(pParse, pExpr, aff, &pRhs);
99178 if( rc ) goto whereEqualScanEst_cancel;
99179 }else{
99180 pRhs = sqlite3ValueNew(pParse->db);
99181 }
99182 if( pRhs==0 ) return SQLITE_NOTFOUND;
99183 rc = whereRangeRegion(pParse, p, pRhs, 0, &iLower);
99184 if( rc ) goto whereEqualScanEst_cancel;
99185 rc = whereRangeRegion(pParse, p, pRhs, 1, &iUpper);
99186 if( rc ) goto whereEqualScanEst_cancel;
@@ -99147,11 +99565,13 @@
99565 ** data is available for column x, then it might be possible
99566 ** to get a better estimate on the number of rows based on
99567 ** VALUE and how common that value is according to the histogram.
99568 */
99569 if( nRow>(double)1 && nEq==1 && pFirstTerm!=0 ){
99570 if( pFirstTerm->eOperator & (WO_EQ|WO_ISNULL) ){
99571 testcase( pFirstTerm->eOperator==WO_EQ );
99572 testcase( pFirstTerm->pOperator==WO_ISNULL );
99573 whereEqualScanEst(pParse, pProbe, pFirstTerm->pExpr->pRight, &nRow);
99574 }else if( pFirstTerm->eOperator==WO_IN && bInEst==0 ){
99575 whereInScanEst(pParse, pProbe, pFirstTerm->pExpr->x.pList, &nRow);
99576 }
99577 }
@@ -100213,11 +100633,17 @@
100633 }
100634
100635 /* Record the instruction used to terminate the loop. Disable
100636 ** WHERE clause terms made redundant by the index range scan.
100637 */
100638 if( pLevel->plan.wsFlags & WHERE_UNIQUE ){
100639 pLevel->op = OP_Noop;
100640 }else if( bRev ){
100641 pLevel->op = OP_Prev;
100642 }else{
100643 pLevel->op = OP_Next;
100644 }
100645 pLevel->p1 = iIdxCur;
100646 }else
100647
100648 #ifndef SQLITE_OMIT_OR_OPTIMIZATION
100649 if( pLevel->plan.wsFlags & WHERE_MULTI_OR ){
@@ -106160,10 +106586,17 @@
106586 case SQLITE_CONFIG_HEAP: {
106587 /* Designate a buffer for heap memory space */
106588 sqlite3GlobalConfig.pHeap = va_arg(ap, void*);
106589 sqlite3GlobalConfig.nHeap = va_arg(ap, int);
106590 sqlite3GlobalConfig.mnReq = va_arg(ap, int);
106591
106592 if( sqlite3GlobalConfig.mnReq<1 ){
106593 sqlite3GlobalConfig.mnReq = 1;
106594 }else if( sqlite3GlobalConfig.mnReq>(1<<12) ){
106595 /* cap min request size at 2^12 */
106596 sqlite3GlobalConfig.mnReq = (1<<12);
106597 }
106598
106599 if( sqlite3GlobalConfig.pHeap==0 ){
106600 /* If the heap pointer is NULL, then restore the malloc implementation
106601 ** back to NULL pointers too. This will cause the malloc to go
106602 ** back to its default implementation when sqlite3_initialize() is
@@ -106301,11 +106734,39 @@
106734 int cnt = va_arg(ap, int); /* IMP: R-04460-53386 */
106735 rc = setupLookaside(db, pBuf, sz, cnt);
106736 break;
106737 }
106738 default: {
106739 static const struct {
106740 int op; /* The opcode */
106741 u32 mask; /* Mask of the bit in sqlite3.flags to set/clear */
106742 } aFlagOp[] = {
106743 { SQLITE_DBCONFIG_ENABLE_FKEY, SQLITE_ForeignKeys },
106744 { SQLITE_DBCONFIG_ENABLE_TRIGGER, SQLITE_EnableTrigger },
106745 };
106746 unsigned int i;
106747 rc = SQLITE_ERROR; /* IMP: R-42790-23372 */
106748 for(i=0; i<ArraySize(aFlagOp); i++){
106749 if( aFlagOp[i].op==op ){
106750 int onoff = va_arg(ap, int);
106751 int *pRes = va_arg(ap, int*);
106752 int oldFlags = db->flags;
106753 if( onoff>0 ){
106754 db->flags |= aFlagOp[i].mask;
106755 }else if( onoff==0 ){
106756 db->flags &= ~aFlagOp[i].mask;
106757 }
106758 if( oldFlags!=db->flags ){
106759 sqlite3ExpirePreparedStatements(db);
106760 }
106761 if( pRes ){
106762 *pRes = (db->flags & aFlagOp[i].mask)!=0;
106763 }
106764 rc = SQLITE_OK;
106765 break;
106766 }
106767 }
106768 break;
106769 }
106770 }
106771 va_end(ap);
106772 return rc;
@@ -107474,12 +107935,12 @@
107935 # error SQLITE_MAX_VDBE_OP must be at least 40
107936 #endif
107937 #if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>1000
107938 # error SQLITE_MAX_FUNCTION_ARG must be between 0 and 1000
107939 #endif
107940 #if SQLITE_MAX_ATTACHED<0 || SQLITE_MAX_ATTACHED>62
107941 # error SQLITE_MAX_ATTACHED must be between 0 and 62
107942 #endif
107943 #if SQLITE_MAX_LIKE_PATTERN_LENGTH<1
107944 # error SQLITE_MAX_LIKE_PATTERN_LENGTH must be at least 1
107945 #endif
107946 #if SQLITE_MAX_COLUMN>32767
@@ -107634,11 +108095,11 @@
108095 assert( sizeof(db->aLimit)==sizeof(aHardLimit) );
108096 memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit));
108097 db->autoCommit = 1;
108098 db->nextAutovac = -1;
108099 db->nextPagesize = 0;
108100 db->flags |= SQLITE_ShortColNames | SQLITE_AutoIndex | SQLITE_EnableTrigger
108101 #if SQLITE_DEFAULT_FILE_FORMAT<4
108102 | SQLITE_LegacyFileFmt
108103 #endif
108104 #ifdef SQLITE_ENABLE_LOAD_EXTENSION
108105 | SQLITE_LoadExtension
@@ -119847,17 +120308,17 @@
120308 Fts3Expr *pExpr, /* Phrase expression node */
120309 int iPhrase, /* Phrase number */
120310 void *pCtx /* Pointer to MatchInfo structure */
120311 ){
120312 MatchInfo *p = (MatchInfo *)pCtx;
120313 int iStart = iPhrase * p->nCol * 3;
120314 int i;
120315
120316 for(i=0; i<p->nCol; i++) p->aMatchinfo[iStart+i*3] = 0;
120317
120318 if( pExpr->aDoclist ){
120319 char *pCsr;
 
 
 
 
120320
120321 pCsr = sqlite3Fts3FindPositions(pExpr, p->pCursor->iPrevId, -1);
120322 if( pCsr ){
120323 fts3LoadColumnlistCounts(&pCsr, &p->aMatchinfo[iStart], 0);
120324 }
@@ -121944,19 +122405,19 @@
122405 ** to which the constraint applies. The leftmost coordinate column
122406 ** is 'a', the second from the left 'b' etc.
122407 */
122408 static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
122409 int rc = SQLITE_OK;
122410 int ii;
122411
122412 int iIdx = 0;
122413 char zIdxStr[RTREE_MAX_DIMENSIONS*8+1];
122414 memset(zIdxStr, 0, sizeof(zIdxStr));
122415 UNUSED_PARAMETER(tab);
122416
122417 assert( pIdxInfo->idxStr==0 );
122418 for(ii=0; ii<pIdxInfo->nConstraint && iIdx<(sizeof(zIdxStr)-1); ii++){
122419 struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii];
122420
122421 if( p->usable && p->iColumn==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){
122422 /* We have an equality constraint on the rowid. Use strategy 1. */
122423 int jj;
@@ -121976,13 +122437,11 @@
122437 pIdxInfo->estimatedCost = 10.0;
122438 return SQLITE_OK;
122439 }
122440
122441 if( p->usable && (p->iColumn>0 || p->op==SQLITE_INDEX_CONSTRAINT_MATCH) ){
122442 u8 op;
 
 
122443 switch( p->op ){
122444 case SQLITE_INDEX_CONSTRAINT_EQ: op = RTREE_EQ; break;
122445 case SQLITE_INDEX_CONSTRAINT_GT: op = RTREE_GT; break;
122446 case SQLITE_INDEX_CONSTRAINT_LE: op = RTREE_LE; break;
122447 case SQLITE_INDEX_CONSTRAINT_LT: op = RTREE_LT; break;
@@ -121990,41 +122449,14 @@
122449 default:
122450 assert( p->op==SQLITE_INDEX_CONSTRAINT_MATCH );
122451 op = RTREE_MATCH;
122452 break;
122453 }
122454 zIdxStr[iIdx++] = op;
122455 zIdxStr[iIdx++] = p->iColumn - 1 + 'a';
122456 pIdxInfo->aConstraintUsage[ii].argvIndex = (iIdx/2);
122457 pIdxInfo->aConstraintUsage[ii].omit = 1;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122458 }
122459 }
122460
122461 pIdxInfo->idxNum = 2;
122462 pIdxInfo->needToFreeIdxStr = 1;
122463
+52 -13
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -107,11 +107,11 @@
107107
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108108
** [sqlite_version()] and [sqlite_source_id()].
109109
*/
110110
#define SQLITE_VERSION "3.7.6"
111111
#define SQLITE_VERSION_NUMBER 3007006
112
-#define SQLITE_SOURCE_ID "2011-03-06 21:54:33 3bfbf026dd6a0eeef07f8f5f1ebf74c9cfebcd61"
112
+#define SQLITE_SOURCE_ID "2011-03-24 01:34:03 b6e268fce12829f058f1dfa223731ec8479493f8"
113113
114114
/*
115115
** CAPI3REF: Run-Time Library Version Numbers
116116
** KEYWORDS: sqlite3_version, sqlite3_sourceid
117117
**
@@ -896,14 +896,27 @@
896896
** a 24-hour day).
897897
** ^SQLite will use the xCurrentTimeInt64() method to get the current
898898
** date and time if that method is available (if iVersion is 2 or
899899
** greater and the function pointer is not NULL) and will fall back
900900
** to xCurrentTime() if xCurrentTimeInt64() is unavailable.
901
+**
902
+** ^The xSetSystemCall(), xGetSystemCall(), and xNestSystemCall() interfaces
903
+** are not used by the SQLite core. These optional interfaces are provided
904
+** by some VFSes to facilitate testing of the VFS code. By overriding
905
+** system calls with functions under its control, a test program can
906
+** simulate faults and error conditions that would otherwise be difficult
907
+** or impossible to induce. The set of system calls that can be overridden
908
+** varies from one VFS to another, and from one version of the same VFS to the
909
+** next. Applications that use these interfaces must be prepared for any
910
+** or all of these interfaces to be NULL or for their behavior to change
911
+** from one release to the next. Applications must not attempt to access
912
+** any of these methods if the iVersion of the VFS is less than 3.
901913
*/
902914
typedef struct sqlite3_vfs sqlite3_vfs;
915
+typedef void (*sqlite3_syscall_ptr)(void);
903916
struct sqlite3_vfs {
904
- int iVersion; /* Structure version number (currently 2) */
917
+ int iVersion; /* Structure version number (currently 3) */
905918
int szOsFile; /* Size of subclassed sqlite3_file */
906919
int mxPathname; /* Maximum file pathname length */
907920
sqlite3_vfs *pNext; /* Next registered VFS */
908921
const char *zName; /* Name of this virtual file system */
909922
void *pAppData; /* Pointer to application-specific data */
@@ -925,10 +938,17 @@
925938
** definition. Those that follow are added in version 2 or later
926939
*/
927940
int (*xCurrentTimeInt64)(sqlite3_vfs*, sqlite3_int64*);
928941
/*
929942
** The methods above are in versions 1 and 2 of the sqlite_vfs object.
943
+ ** Those below are for version 3 and greater.
944
+ */
945
+ int (*xSetSystemCall)(sqlite3_vfs*, const char *zName, sqlite3_syscall_ptr);
946
+ sqlite3_syscall_ptr (*xGetSystemCall)(sqlite3_vfs*, const char *zName);
947
+ const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName);
948
+ /*
949
+ ** The methods above are in versions 1 through 3 of the sqlite_vfs object.
930950
** New fields may be appended in figure versions. The iVersion
931951
** value will increment whenever this happens.
932952
*/
933953
};
934954
@@ -1109,21 +1129,16 @@
11091129
** CAPI3REF: Configure database connections
11101130
**
11111131
** The sqlite3_db_config() interface is used to make configuration
11121132
** changes to a [database connection]. The interface is similar to
11131133
** [sqlite3_config()] except that the changes apply to a single
1114
-** [database connection] (specified in the first argument). The
1115
-** sqlite3_db_config() interface should only be used immediately after
1116
-** the database connection is created using [sqlite3_open()],
1117
-** [sqlite3_open16()], or [sqlite3_open_v2()].
1134
+** [database connection] (specified in the first argument).
11181135
**
11191136
** The second argument to sqlite3_db_config(D,V,...) is the
1120
-** configuration verb - an integer code that indicates what
1121
-** aspect of the [database connection] is being configured.
1122
-** The only choice for this value is [SQLITE_DBCONFIG_LOOKASIDE].
1123
-** New verbs are likely to be added in future releases of SQLite.
1124
-** Additional arguments depend on the verb.
1137
+** [SQLITE_DBCONIG_LOOKASIDE | configuration verb] - an integer code
1138
+** that indicates what aspect of the [database connection] is being configured.
1139
+** Subsequent arguments vary depending on the configuration verb.
11251140
**
11261141
** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if
11271142
** the call is considered successful.
11281143
*/
11291144
SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
@@ -1344,11 +1359,13 @@
13441359
** undoing any prior invocation of [SQLITE_CONFIG_MALLOC]. ^If the
13451360
** memory pointer is not NULL and either [SQLITE_ENABLE_MEMSYS3] or
13461361
** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory
13471362
** allocator is engaged to handle all of SQLites memory allocation needs.
13481363
** The first pointer (the memory pointer) must be aligned to an 8-byte
1349
-** boundary or subsequent behavior of SQLite will be undefined.</dd>
1364
+** boundary or subsequent behavior of SQLite will be undefined.
1365
+** The minimum allocation size is capped at 2^12. Reasonable values
1366
+** for the minimum allocation size are 2^5 through 2^8.</dd>
13501367
**
13511368
** <dt>SQLITE_CONFIG_MUTEX</dt>
13521369
** <dd> ^(This option takes a single argument which is a pointer to an
13531370
** instance of the [sqlite3_mutex_methods] structure. The argument specifies
13541371
** alternative low-level mutex routines to be used in place
@@ -1465,13 +1482,35 @@
14651482
** [sqlite3_db_status](D,[SQLITE_CONFIG_LOOKASIDE],...) is zero.
14661483
** Any attempt to change the lookaside memory configuration when lookaside
14671484
** memory is in use leaves the configuration unchanged and returns
14681485
** [SQLITE_BUSY].)^</dd>
14691486
**
1487
+** <dt>SQLITE_DBCONFIG_ENABLE_FKEY</dt>
1488
+** <dd> ^This option is used to enable or disable the enforcement of
1489
+** [foreign key constraints]. There should be two additional arguments.
1490
+** The first argument is an integer which is 0 to disable FK enforcement,
1491
+** positive to enable FK enforcement or negative to leave FK enforcement
1492
+** unchanged. The second parameter is a pointer to an integer into which
1493
+** is written 0 or 1 to indicate whether FK enforcement is off or on
1494
+** following this call. The second parameter may be a NULL pointer, in
1495
+** which case the FK enforcement setting is not reported back. </dd>
1496
+**
1497
+** <dt>SQLITE_DBCONFIG_ENABLE_TRIGGER</dt>
1498
+** <dd> ^This option is used to enable or disable [CREATE TRIGGER | triggers].
1499
+** There should be two additional arguments.
1500
+** The first argument is an integer which is 0 to disable triggers,
1501
+** positive to enable trigers or negative to leave the setting unchanged.
1502
+** The second parameter is a pointer to an integer into which
1503
+** is written 0 or 1 to indicate whether triggers are disabled or enabled
1504
+** following this call. The second parameter may be a NULL pointer, in
1505
+** which case the trigger setting is not reported back. </dd>
1506
+**
14701507
** </dl>
14711508
*/
1472
-#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */
1509
+#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */
1510
+#define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */
1511
+#define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */
14731512
14741513
14751514
/*
14761515
** CAPI3REF: Enable Or Disable Extended Result Codes
14771516
**
14781517
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -107,11 +107,11 @@
107 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108 ** [sqlite_version()] and [sqlite_source_id()].
109 */
110 #define SQLITE_VERSION "3.7.6"
111 #define SQLITE_VERSION_NUMBER 3007006
112 #define SQLITE_SOURCE_ID "2011-03-06 21:54:33 3bfbf026dd6a0eeef07f8f5f1ebf74c9cfebcd61"
113
114 /*
115 ** CAPI3REF: Run-Time Library Version Numbers
116 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
117 **
@@ -896,14 +896,27 @@
896 ** a 24-hour day).
897 ** ^SQLite will use the xCurrentTimeInt64() method to get the current
898 ** date and time if that method is available (if iVersion is 2 or
899 ** greater and the function pointer is not NULL) and will fall back
900 ** to xCurrentTime() if xCurrentTimeInt64() is unavailable.
 
 
 
 
 
 
 
 
 
 
 
 
901 */
902 typedef struct sqlite3_vfs sqlite3_vfs;
 
903 struct sqlite3_vfs {
904 int iVersion; /* Structure version number (currently 2) */
905 int szOsFile; /* Size of subclassed sqlite3_file */
906 int mxPathname; /* Maximum file pathname length */
907 sqlite3_vfs *pNext; /* Next registered VFS */
908 const char *zName; /* Name of this virtual file system */
909 void *pAppData; /* Pointer to application-specific data */
@@ -925,10 +938,17 @@
925 ** definition. Those that follow are added in version 2 or later
926 */
927 int (*xCurrentTimeInt64)(sqlite3_vfs*, sqlite3_int64*);
928 /*
929 ** The methods above are in versions 1 and 2 of the sqlite_vfs object.
 
 
 
 
 
 
 
930 ** New fields may be appended in figure versions. The iVersion
931 ** value will increment whenever this happens.
932 */
933 };
934
@@ -1109,21 +1129,16 @@
1109 ** CAPI3REF: Configure database connections
1110 **
1111 ** The sqlite3_db_config() interface is used to make configuration
1112 ** changes to a [database connection]. The interface is similar to
1113 ** [sqlite3_config()] except that the changes apply to a single
1114 ** [database connection] (specified in the first argument). The
1115 ** sqlite3_db_config() interface should only be used immediately after
1116 ** the database connection is created using [sqlite3_open()],
1117 ** [sqlite3_open16()], or [sqlite3_open_v2()].
1118 **
1119 ** The second argument to sqlite3_db_config(D,V,...) is the
1120 ** configuration verb - an integer code that indicates what
1121 ** aspect of the [database connection] is being configured.
1122 ** The only choice for this value is [SQLITE_DBCONFIG_LOOKASIDE].
1123 ** New verbs are likely to be added in future releases of SQLite.
1124 ** Additional arguments depend on the verb.
1125 **
1126 ** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if
1127 ** the call is considered successful.
1128 */
1129 SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
@@ -1344,11 +1359,13 @@
1344 ** undoing any prior invocation of [SQLITE_CONFIG_MALLOC]. ^If the
1345 ** memory pointer is not NULL and either [SQLITE_ENABLE_MEMSYS3] or
1346 ** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory
1347 ** allocator is engaged to handle all of SQLites memory allocation needs.
1348 ** The first pointer (the memory pointer) must be aligned to an 8-byte
1349 ** boundary or subsequent behavior of SQLite will be undefined.</dd>
 
 
1350 **
1351 ** <dt>SQLITE_CONFIG_MUTEX</dt>
1352 ** <dd> ^(This option takes a single argument which is a pointer to an
1353 ** instance of the [sqlite3_mutex_methods] structure. The argument specifies
1354 ** alternative low-level mutex routines to be used in place
@@ -1465,13 +1482,35 @@
1465 ** [sqlite3_db_status](D,[SQLITE_CONFIG_LOOKASIDE],...) is zero.
1466 ** Any attempt to change the lookaside memory configuration when lookaside
1467 ** memory is in use leaves the configuration unchanged and returns
1468 ** [SQLITE_BUSY].)^</dd>
1469 **
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1470 ** </dl>
1471 */
1472 #define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */
 
 
1473
1474
1475 /*
1476 ** CAPI3REF: Enable Or Disable Extended Result Codes
1477 **
1478
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -107,11 +107,11 @@
107 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108 ** [sqlite_version()] and [sqlite_source_id()].
109 */
110 #define SQLITE_VERSION "3.7.6"
111 #define SQLITE_VERSION_NUMBER 3007006
112 #define SQLITE_SOURCE_ID "2011-03-24 01:34:03 b6e268fce12829f058f1dfa223731ec8479493f8"
113
114 /*
115 ** CAPI3REF: Run-Time Library Version Numbers
116 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
117 **
@@ -896,14 +896,27 @@
896 ** a 24-hour day).
897 ** ^SQLite will use the xCurrentTimeInt64() method to get the current
898 ** date and time if that method is available (if iVersion is 2 or
899 ** greater and the function pointer is not NULL) and will fall back
900 ** to xCurrentTime() if xCurrentTimeInt64() is unavailable.
901 **
902 ** ^The xSetSystemCall(), xGetSystemCall(), and xNestSystemCall() interfaces
903 ** are not used by the SQLite core. These optional interfaces are provided
904 ** by some VFSes to facilitate testing of the VFS code. By overriding
905 ** system calls with functions under its control, a test program can
906 ** simulate faults and error conditions that would otherwise be difficult
907 ** or impossible to induce. The set of system calls that can be overridden
908 ** varies from one VFS to another, and from one version of the same VFS to the
909 ** next. Applications that use these interfaces must be prepared for any
910 ** or all of these interfaces to be NULL or for their behavior to change
911 ** from one release to the next. Applications must not attempt to access
912 ** any of these methods if the iVersion of the VFS is less than 3.
913 */
914 typedef struct sqlite3_vfs sqlite3_vfs;
915 typedef void (*sqlite3_syscall_ptr)(void);
916 struct sqlite3_vfs {
917 int iVersion; /* Structure version number (currently 3) */
918 int szOsFile; /* Size of subclassed sqlite3_file */
919 int mxPathname; /* Maximum file pathname length */
920 sqlite3_vfs *pNext; /* Next registered VFS */
921 const char *zName; /* Name of this virtual file system */
922 void *pAppData; /* Pointer to application-specific data */
@@ -925,10 +938,17 @@
938 ** definition. Those that follow are added in version 2 or later
939 */
940 int (*xCurrentTimeInt64)(sqlite3_vfs*, sqlite3_int64*);
941 /*
942 ** The methods above are in versions 1 and 2 of the sqlite_vfs object.
943 ** Those below are for version 3 and greater.
944 */
945 int (*xSetSystemCall)(sqlite3_vfs*, const char *zName, sqlite3_syscall_ptr);
946 sqlite3_syscall_ptr (*xGetSystemCall)(sqlite3_vfs*, const char *zName);
947 const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName);
948 /*
949 ** The methods above are in versions 1 through 3 of the sqlite_vfs object.
950 ** New fields may be appended in figure versions. The iVersion
951 ** value will increment whenever this happens.
952 */
953 };
954
@@ -1109,21 +1129,16 @@
1129 ** CAPI3REF: Configure database connections
1130 **
1131 ** The sqlite3_db_config() interface is used to make configuration
1132 ** changes to a [database connection]. The interface is similar to
1133 ** [sqlite3_config()] except that the changes apply to a single
1134 ** [database connection] (specified in the first argument).
 
 
 
1135 **
1136 ** The second argument to sqlite3_db_config(D,V,...) is the
1137 ** [SQLITE_DBCONIG_LOOKASIDE | configuration verb] - an integer code
1138 ** that indicates what aspect of the [database connection] is being configured.
1139 ** Subsequent arguments vary depending on the configuration verb.
 
 
1140 **
1141 ** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if
1142 ** the call is considered successful.
1143 */
1144 SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
@@ -1344,11 +1359,13 @@
1359 ** undoing any prior invocation of [SQLITE_CONFIG_MALLOC]. ^If the
1360 ** memory pointer is not NULL and either [SQLITE_ENABLE_MEMSYS3] or
1361 ** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory
1362 ** allocator is engaged to handle all of SQLites memory allocation needs.
1363 ** The first pointer (the memory pointer) must be aligned to an 8-byte
1364 ** boundary or subsequent behavior of SQLite will be undefined.
1365 ** The minimum allocation size is capped at 2^12. Reasonable values
1366 ** for the minimum allocation size are 2^5 through 2^8.</dd>
1367 **
1368 ** <dt>SQLITE_CONFIG_MUTEX</dt>
1369 ** <dd> ^(This option takes a single argument which is a pointer to an
1370 ** instance of the [sqlite3_mutex_methods] structure. The argument specifies
1371 ** alternative low-level mutex routines to be used in place
@@ -1465,13 +1482,35 @@
1482 ** [sqlite3_db_status](D,[SQLITE_CONFIG_LOOKASIDE],...) is zero.
1483 ** Any attempt to change the lookaside memory configuration when lookaside
1484 ** memory is in use leaves the configuration unchanged and returns
1485 ** [SQLITE_BUSY].)^</dd>
1486 **
1487 ** <dt>SQLITE_DBCONFIG_ENABLE_FKEY</dt>
1488 ** <dd> ^This option is used to enable or disable the enforcement of
1489 ** [foreign key constraints]. There should be two additional arguments.
1490 ** The first argument is an integer which is 0 to disable FK enforcement,
1491 ** positive to enable FK enforcement or negative to leave FK enforcement
1492 ** unchanged. The second parameter is a pointer to an integer into which
1493 ** is written 0 or 1 to indicate whether FK enforcement is off or on
1494 ** following this call. The second parameter may be a NULL pointer, in
1495 ** which case the FK enforcement setting is not reported back. </dd>
1496 **
1497 ** <dt>SQLITE_DBCONFIG_ENABLE_TRIGGER</dt>
1498 ** <dd> ^This option is used to enable or disable [CREATE TRIGGER | triggers].
1499 ** There should be two additional arguments.
1500 ** The first argument is an integer which is 0 to disable triggers,
1501 ** positive to enable trigers or negative to leave the setting unchanged.
1502 ** The second parameter is a pointer to an integer into which
1503 ** is written 0 or 1 to indicate whether triggers are disabled or enabled
1504 ** following this call. The second parameter may be a NULL pointer, in
1505 ** which case the trigger setting is not reported back. </dd>
1506 **
1507 ** </dl>
1508 */
1509 #define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */
1510 #define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */
1511 #define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */
1512
1513
1514 /*
1515 ** CAPI3REF: Enable Or Disable Extended Result Codes
1516 **
1517
+2 -2
--- src/stash.c
+++ src/stash.c
@@ -333,11 +333,11 @@
333333
** This command is undoable.
334334
**
335335
** fossil stash apply ?STASHID?
336336
**
337337
** Apply the identified stash to the current working check-out.
338
-** If no STASHID is specifed, use the most recent stash. Unlike
338
+** If no STASHID is specified, use the most recent stash. Unlike
339339
** the "pop" command, the stash is retained so that it can be used
340340
** again. This command is undoable.
341341
**
342342
** fossil stash goto ?STASHID?
343343
**
@@ -379,11 +379,11 @@
379379
}
380380
nCmd = strlen(zCmd);
381381
if( memcmp(zCmd, "save", nCmd)==0 ){
382382
stashid = stash_create();
383383
undo_disable();
384
- if( g.argc>=3 ){
384
+ if( g.argc>=2 ){
385385
int nFile = db_int(0, "SELECT count(*) FROM stashfile WHERE stashid=%d",
386386
stashid);
387387
char **newArgv = fossil_malloc( sizeof(char*)*(nFile+2) );
388388
int i = 2;
389389
Stmt q;
390390
--- src/stash.c
+++ src/stash.c
@@ -333,11 +333,11 @@
333 ** This command is undoable.
334 **
335 ** fossil stash apply ?STASHID?
336 **
337 ** Apply the identified stash to the current working check-out.
338 ** If no STASHID is specifed, use the most recent stash. Unlike
339 ** the "pop" command, the stash is retained so that it can be used
340 ** again. This command is undoable.
341 **
342 ** fossil stash goto ?STASHID?
343 **
@@ -379,11 +379,11 @@
379 }
380 nCmd = strlen(zCmd);
381 if( memcmp(zCmd, "save", nCmd)==0 ){
382 stashid = stash_create();
383 undo_disable();
384 if( g.argc>=3 ){
385 int nFile = db_int(0, "SELECT count(*) FROM stashfile WHERE stashid=%d",
386 stashid);
387 char **newArgv = fossil_malloc( sizeof(char*)*(nFile+2) );
388 int i = 2;
389 Stmt q;
390
--- src/stash.c
+++ src/stash.c
@@ -333,11 +333,11 @@
333 ** This command is undoable.
334 **
335 ** fossil stash apply ?STASHID?
336 **
337 ** Apply the identified stash to the current working check-out.
338 ** If no STASHID is specified, use the most recent stash. Unlike
339 ** the "pop" command, the stash is retained so that it can be used
340 ** again. This command is undoable.
341 **
342 ** fossil stash goto ?STASHID?
343 **
@@ -379,11 +379,11 @@
379 }
380 nCmd = strlen(zCmd);
381 if( memcmp(zCmd, "save", nCmd)==0 ){
382 stashid = stash_create();
383 undo_disable();
384 if( g.argc>=2 ){
385 int nFile = db_int(0, "SELECT count(*) FROM stashfile WHERE stashid=%d",
386 stashid);
387 char **newArgv = fossil_malloc( sizeof(char*)*(nFile+2) );
388 int i = 2;
389 Stmt q;
390
+10 -1
--- src/style.c
+++ src/style.c
@@ -624,11 +624,11 @@
624624
{ "span.ueditInheritAnonymous",
625625
"color for capabilities, inherited by anonymous",
626626
@ color: blue;
627627
},
628628
{ "span.capability",
629
- "format for capabilites, mentioned on the user edit page",
629
+ "format for capabilities, mentioned on the user edit page",
630630
@ font-weight: bold;
631631
},
632632
{ "span.usertype",
633633
"format for different user types, mentioned on the user edit page",
634634
@ font-weight: bold;
@@ -735,10 +735,14 @@
735735
},
736736
{ "p.shunned",
737737
"format for artifact lines beeing shunned",
738738
@ color: blue;
739739
},
740
+ { "span.brokenlink",
741
+ "a broken hyperlink",
742
+ @ color: red;
743
+ },
740744
{ 0,
741745
0,
742746
0
743747
}
744748
};
@@ -791,14 +795,19 @@
791795
792796
/*
793797
** WEBPAGE: test_env
794798
*/
795799
void page_test_env(void){
800
+ login_check_credentials();
796801
style_header("Environment Test");
797802
#if !defined(_WIN32)
798803
@ uid=%d(getuid()), gid=%d(getgid())<br />
799804
#endif
800805
@ g.zBaseURL = %h(g.zBaseURL)<br />
801806
@ g.zTop = %h(g.zTop)<br />
802807
cgi_print_all();
808
+ if( g.okSetup ){
809
+ const char *zRedir = P("redirect");
810
+ if( zRedir ) cgi_redirect(zRedir);
811
+ }
803812
style_footer();
804813
}
805814
--- src/style.c
+++ src/style.c
@@ -624,11 +624,11 @@
624 { "span.ueditInheritAnonymous",
625 "color for capabilities, inherited by anonymous",
626 @ color: blue;
627 },
628 { "span.capability",
629 "format for capabilites, mentioned on the user edit page",
630 @ font-weight: bold;
631 },
632 { "span.usertype",
633 "format for different user types, mentioned on the user edit page",
634 @ font-weight: bold;
@@ -735,10 +735,14 @@
735 },
736 { "p.shunned",
737 "format for artifact lines beeing shunned",
738 @ color: blue;
739 },
 
 
 
 
740 { 0,
741 0,
742 0
743 }
744 };
@@ -791,14 +795,19 @@
791
792 /*
793 ** WEBPAGE: test_env
794 */
795 void page_test_env(void){
 
796 style_header("Environment Test");
797 #if !defined(_WIN32)
798 @ uid=%d(getuid()), gid=%d(getgid())<br />
799 #endif
800 @ g.zBaseURL = %h(g.zBaseURL)<br />
801 @ g.zTop = %h(g.zTop)<br />
802 cgi_print_all();
 
 
 
 
803 style_footer();
804 }
805
--- src/style.c
+++ src/style.c
@@ -624,11 +624,11 @@
624 { "span.ueditInheritAnonymous",
625 "color for capabilities, inherited by anonymous",
626 @ color: blue;
627 },
628 { "span.capability",
629 "format for capabilities, mentioned on the user edit page",
630 @ font-weight: bold;
631 },
632 { "span.usertype",
633 "format for different user types, mentioned on the user edit page",
634 @ font-weight: bold;
@@ -735,10 +735,14 @@
735 },
736 { "p.shunned",
737 "format for artifact lines beeing shunned",
738 @ color: blue;
739 },
740 { "span.brokenlink",
741 "a broken hyperlink",
742 @ color: red;
743 },
744 { 0,
745 0,
746 0
747 }
748 };
@@ -791,14 +795,19 @@
795
796 /*
797 ** WEBPAGE: test_env
798 */
799 void page_test_env(void){
800 login_check_credentials();
801 style_header("Environment Test");
802 #if !defined(_WIN32)
803 @ uid=%d(getuid()), gid=%d(getgid())<br />
804 #endif
805 @ g.zBaseURL = %h(g.zBaseURL)<br />
806 @ g.zTop = %h(g.zTop)<br />
807 cgi_print_all();
808 if( g.okSetup ){
809 const char *zRedir = P("redirect");
810 if( zRedir ) cgi_redirect(zRedir);
811 }
812 style_footer();
813 }
814
+3 -3
--- src/tag.c
+++ src/tag.c
@@ -44,11 +44,11 @@
4444
Stmt ins; /* INSERT INTO tagxref */
4545
Stmt eventupdate; /* UPDATE event */
4646
4747
assert( tagType==0 || tagType==2 );
4848
pqueue_init(&queue);
49
- pqueue_insert(&queue, pid, 0.0);
49
+ pqueue_insert(&queue, pid, 0.0, 0);
5050
5151
/* Query for children of :pid to which to propagate the tag.
5252
** Three returns: (1) rid of the child. (2) timestamp of child.
5353
** (3) True to propagate or false to block.
5454
*/
@@ -79,18 +79,18 @@
7979
if( tagid==TAG_BGCOLOR ){
8080
db_prepare(&eventupdate,
8181
"UPDATE event SET bgcolor=%Q WHERE objid=:rid", zValue
8282
);
8383
}
84
- while( (pid = pqueue_extract(&queue))!=0 ){
84
+ while( (pid = pqueue_extract(&queue, 0))!=0 ){
8585
db_bind_int(&s, ":pid", pid);
8686
while( db_step(&s)==SQLITE_ROW ){
8787
int doit = db_column_int(&s, 2);
8888
if( doit ){
8989
int cid = db_column_int(&s, 0);
9090
double mtime = db_column_double(&s, 1);
91
- pqueue_insert(&queue, cid, mtime);
91
+ pqueue_insert(&queue, cid, mtime, 0);
9292
db_bind_int(&ins, ":rid", cid);
9393
db_step(&ins);
9494
db_reset(&ins);
9595
if( tagid==TAG_BGCOLOR ){
9696
db_bind_int(&eventupdate, ":rid", cid);
9797
--- src/tag.c
+++ src/tag.c
@@ -44,11 +44,11 @@
44 Stmt ins; /* INSERT INTO tagxref */
45 Stmt eventupdate; /* UPDATE event */
46
47 assert( tagType==0 || tagType==2 );
48 pqueue_init(&queue);
49 pqueue_insert(&queue, pid, 0.0);
50
51 /* Query for children of :pid to which to propagate the tag.
52 ** Three returns: (1) rid of the child. (2) timestamp of child.
53 ** (3) True to propagate or false to block.
54 */
@@ -79,18 +79,18 @@
79 if( tagid==TAG_BGCOLOR ){
80 db_prepare(&eventupdate,
81 "UPDATE event SET bgcolor=%Q WHERE objid=:rid", zValue
82 );
83 }
84 while( (pid = pqueue_extract(&queue))!=0 ){
85 db_bind_int(&s, ":pid", pid);
86 while( db_step(&s)==SQLITE_ROW ){
87 int doit = db_column_int(&s, 2);
88 if( doit ){
89 int cid = db_column_int(&s, 0);
90 double mtime = db_column_double(&s, 1);
91 pqueue_insert(&queue, cid, mtime);
92 db_bind_int(&ins, ":rid", cid);
93 db_step(&ins);
94 db_reset(&ins);
95 if( tagid==TAG_BGCOLOR ){
96 db_bind_int(&eventupdate, ":rid", cid);
97
--- src/tag.c
+++ src/tag.c
@@ -44,11 +44,11 @@
44 Stmt ins; /* INSERT INTO tagxref */
45 Stmt eventupdate; /* UPDATE event */
46
47 assert( tagType==0 || tagType==2 );
48 pqueue_init(&queue);
49 pqueue_insert(&queue, pid, 0.0, 0);
50
51 /* Query for children of :pid to which to propagate the tag.
52 ** Three returns: (1) rid of the child. (2) timestamp of child.
53 ** (3) True to propagate or false to block.
54 */
@@ -79,18 +79,18 @@
79 if( tagid==TAG_BGCOLOR ){
80 db_prepare(&eventupdate,
81 "UPDATE event SET bgcolor=%Q WHERE objid=:rid", zValue
82 );
83 }
84 while( (pid = pqueue_extract(&queue, 0))!=0 ){
85 db_bind_int(&s, ":pid", pid);
86 while( db_step(&s)==SQLITE_ROW ){
87 int doit = db_column_int(&s, 2);
88 if( doit ){
89 int cid = db_column_int(&s, 0);
90 double mtime = db_column_double(&s, 1);
91 pqueue_insert(&queue, cid, mtime, 0);
92 db_bind_int(&ins, ":rid", cid);
93 db_step(&ins);
94 db_reset(&ins);
95 if( tagid==TAG_BGCOLOR ){
96 db_bind_int(&eventupdate, ":rid", cid);
97
+14 -4
--- src/tar.c
+++ src/tar.c
@@ -137,10 +137,12 @@
137137
** Finish constructing the tarball. Put the content of the tarball
138138
** in Blob pOut.
139139
*/
140140
static void tar_finish(Blob *pOut){
141141
db_multi_exec("DROP TABLE dir");
142
+ gzip_step(tball.zSpaces, 512);
143
+ gzip_step(tball.zSpaces, 512);
142144
gzip_finish(pOut);
143145
fossil_free(tball.aHdr);
144146
tball.aHdr = 0;
145147
}
146148
@@ -307,14 +309,22 @@
307309
if( !g.okZip ){ login_needed(); return; }
308310
zName = mprintf("%s", PD("name",""));
309311
nName = strlen(zName);
310312
zRid = mprintf("%s", PD("uuid",""));
311313
nRid = strlen(zRid);
312
- for(nName=strlen(zName)-1; nName>5; nName--){
313
- if( zName[nName]=='.' ){
314
- zName[nName] = 0;
315
- break;
314
+ if( nName>7 && strcmp(&zName[nName-7], ".tar.gz")==0 ){
315
+ /* Special case: Remove the ".tar.gz" suffix. */
316
+ nName -= 7;
317
+ zName[nName] = 0;
318
+ }else{
319
+ /* If the file suffix is not ".tar.gz" then just remove the
320
+ ** suffix up to and including the last "." */
321
+ for(nName=strlen(zName)-1; nName>5; nName--){
322
+ if( zName[nName]=='.' ){
323
+ zName[nName] = 0;
324
+ break;
325
+ }
316326
}
317327
}
318328
rid = name_to_rid(nRid?zRid:zName);
319329
if( rid==0 ){
320330
@ Not found
321331
--- src/tar.c
+++ src/tar.c
@@ -137,10 +137,12 @@
137 ** Finish constructing the tarball. Put the content of the tarball
138 ** in Blob pOut.
139 */
140 static void tar_finish(Blob *pOut){
141 db_multi_exec("DROP TABLE dir");
 
 
142 gzip_finish(pOut);
143 fossil_free(tball.aHdr);
144 tball.aHdr = 0;
145 }
146
@@ -307,14 +309,22 @@
307 if( !g.okZip ){ login_needed(); return; }
308 zName = mprintf("%s", PD("name",""));
309 nName = strlen(zName);
310 zRid = mprintf("%s", PD("uuid",""));
311 nRid = strlen(zRid);
312 for(nName=strlen(zName)-1; nName>5; nName--){
313 if( zName[nName]=='.' ){
314 zName[nName] = 0;
315 break;
 
 
 
 
 
 
 
 
316 }
317 }
318 rid = name_to_rid(nRid?zRid:zName);
319 if( rid==0 ){
320 @ Not found
321
--- src/tar.c
+++ src/tar.c
@@ -137,10 +137,12 @@
137 ** Finish constructing the tarball. Put the content of the tarball
138 ** in Blob pOut.
139 */
140 static void tar_finish(Blob *pOut){
141 db_multi_exec("DROP TABLE dir");
142 gzip_step(tball.zSpaces, 512);
143 gzip_step(tball.zSpaces, 512);
144 gzip_finish(pOut);
145 fossil_free(tball.aHdr);
146 tball.aHdr = 0;
147 }
148
@@ -307,14 +309,22 @@
309 if( !g.okZip ){ login_needed(); return; }
310 zName = mprintf("%s", PD("name",""));
311 nName = strlen(zName);
312 zRid = mprintf("%s", PD("uuid",""));
313 nRid = strlen(zRid);
314 if( nName>7 && strcmp(&zName[nName-7], ".tar.gz")==0 ){
315 /* Special case: Remove the ".tar.gz" suffix. */
316 nName -= 7;
317 zName[nName] = 0;
318 }else{
319 /* If the file suffix is not ".tar.gz" then just remove the
320 ** suffix up to and including the last "." */
321 for(nName=strlen(zName)-1; nName>5; nName--){
322 if( zName[nName]=='.' ){
323 zName[nName] = 0;
324 break;
325 }
326 }
327 }
328 rid = name_to_rid(nRid?zRid:zName);
329 if( rid==0 ){
330 @ Not found
331
+71 -50
--- src/timeline.c
+++ src/timeline.c
@@ -254,11 +254,11 @@
254254
if( db_step(&qbranch)==SQLITE_ROW ){
255255
zBr = db_column_text(&qbranch, 0);
256256
}else{
257257
zBr = "trunk";
258258
}
259
- gidx = graph_add_row(pGraph, rid, nParent, aParent, zBr, zBgClr);
259
+ gidx = graph_add_row(pGraph, rid, nParent, aParent, zBr, zBgClr, isLeaf);
260260
db_reset(&qbranch);
261261
@ <div id="m%d(gidx)"></div>
262262
}
263263
@</td>
264264
if( zBgClr && zBgClr[0] ){
@@ -362,18 +362,18 @@
362362
@ <div id="grbtm" style="width:%d(pGraph->mxRail*20+30)px;"></div>
363363
@ </td></tr>
364364
}
365365
}
366366
@ </table>
367
- timeline_output_graph_javascript(pGraph);
367
+ timeline_output_graph_javascript(pGraph, (tmFlags & TIMELINE_DISJOINT)!=0);
368368
}
369369
370370
/*
371371
** Generate all of the necessary javascript to generate a timeline
372372
** graph.
373373
*/
374
-void timeline_output_graph_javascript(GraphContext *pGraph){
374
+void timeline_output_graph_javascript(GraphContext *pGraph, int omitDescenders){
375375
if( pGraph && pGraph->nErr==0 ){
376376
GraphRow *pRow;
377377
int i;
378378
char cSep;
379379
@ <script type="text/JavaScript">
@@ -388,42 +388,48 @@
388388
** bg: The background color for this row
389389
** r: The "rail" that the node for this row sits on. The left-most
390390
** rail is 0 and the number increases to the right.
391391
** d: True if there is a "descender" - an arrow coming from the bottom
392392
** of the page straight up to this node.
393
- ** mo: "merge-out". If non-zero, this is one more than the rail on which
394
- ** a merge arrow travels upward. The merge arrow is drawn upwards
393
+ ** mo: "merge-out". If non-zero, this is one more than the x-coordinate
394
+ ** for the upward portion of a merge arrow. The merge arrow goes up
395395
** to the row identified by mu:. If this value is zero then
396396
** node has no merge children and no merge-out line is drawn.
397397
** mu: The id of the row which is the top of the merge-out arrow.
398
- ** md: A bitmask of rails on which merge-arrow descenders should be
399
- ** drawn from this row to the bottom of the page. The least
400
- ** significant bit (1) corresponds to rail 0. The 2-bit corresponds
401
- ** to rail 1. And so forth. This value is 0 if there are no
402
- ** merge-arrow descenders.
403
- ** u: Draw a think child-line out of the top of this node and up to
398
+ ** u: Draw a thick child-line out of the top of this node and up to
404399
** the node with an id equal to this value. 0 if there is no
405400
** thick-line riser.
401
+ ** f: 0x01: a leaf node.
406402
** au: An array of integers that define thick-line risers for branches.
407403
** The integers are in pairs. For each pair, the first integer is
408404
** is the rail on which the riser should run and the second integer
409405
** is the id of the node upto which the riser should run.
410
- ** mi: "merge-in". An array of integer rail numbers from which
411
- ** merge arrows should be drawn into this node.
406
+ ** mi: "merge-in". An array of integer x-coordinates from which
407
+ ** merge arrows should be drawn into this node. If the value is
408
+ ** negative, then the x-coordinate is the absolute value of mi[]
409
+ ** and a thin merge-arrow descender is drawn to the bottom of
410
+ ** the screen.
412411
*/
413412
cgi_printf("var rowinfo = [\n");
414413
for(pRow=pGraph->pFirst; pRow; pRow=pRow->pNext){
415
- cgi_printf("{id:%d,bg:\"%s\",r:%d,d:%d,mo:%d,mu:%d,md:%u,u:%d,au:",
416
- pRow->idx,
417
- pRow->zBgClr,
418
- pRow->iRail,
419
- pRow->bDescender,
420
- pRow->mergeOut+1,
421
- pRow->mergeUpto,
422
- pRow->mergeDown,
423
- pRow->aiRiser[pRow->iRail]
414
+ int mo = pRow->mergeOut;
415
+ if( mo<0 ){
416
+ mo = 0;
417
+ }else{
418
+ mo = (mo/4)*20 - 3 + 4*(mo&3);
419
+ }
420
+ cgi_printf("{id:%d,bg:\"%s\",r:%d,d:%d,mo:%d,mu:%d,u:%d,f:%d,au:",
421
+ pRow->idx, /* id */
422
+ pRow->zBgClr, /* bg */
423
+ pRow->iRail, /* r */
424
+ pRow->bDescender, /* d */
425
+ mo, /* mo */
426
+ pRow->mergeUpto, /* mu */
427
+ pRow->aiRiser[pRow->iRail], /* u */
428
+ pRow->isLeaf ? 1 : 0 /* f */
424429
);
430
+ /* u */
425431
cSep = '[';
426432
for(i=0; i<GR_MAX_RAIL; i++){
427433
if( i==pRow->iRail ) continue;
428434
if( pRow->aiRiser[i]>0 ){
429435
cgi_printf("%c%d,%d", cSep, i, pRow->aiRiser[i]);
@@ -430,14 +436,17 @@
430436
cSep = ',';
431437
}
432438
}
433439
if( cSep=='[' ) cgi_printf("[");
434440
cgi_printf("],mi:");
441
+ /* mi */
435442
cSep = '[';
436443
for(i=0; i<GR_MAX_RAIL; i++){
437
- if( pRow->mergeIn & (1<<i) ){
438
- cgi_printf("%c%d", cSep, i);
444
+ if( pRow->mergeIn[i] ){
445
+ int mi = i*20 - 8 + 4*pRow->mergeIn[i];
446
+ if( pRow->mergeDown & (1<<i) ) mi = -mi;
447
+ cgi_printf("%c%d", cSep, mi);
439448
cSep = ',';
440449
}
441450
}
442451
if( cSep=='[' ) cgi_printf("[");
443452
cgi_printf("]}%s", pRow->pNext ? ",\n" : "];\n");
@@ -508,25 +517,24 @@
508517
@ drawBox("black",x0,y0,x1,y1);
509518
@ }
510519
@ function drawNode(p, left, btm){
511520
@ drawBox("black",p.x-5,p.y-5,p.x+6,p.y+6);
512521
@ drawBox(p.bg,p.x-4,p.y-4,p.x+5,p.y+5);
513
- @ if( p.u>0 ){
514
- @ var u = rowinfo[p.u-1];
515
- @ drawUpArrow(p.x, u.y+6, p.y-5);
516
- @ }
517
- @ if( p.d ){
518
- @ drawUpArrow(p.x, p.y+6, btm);
519
- @ }
522
+ @ if( p.u>0 ) drawUpArrow(p.x, rowinfo[p.u-1].y+6, p.y-5);
523
+ if( !omitDescenders ){
524
+ @ if( p.u==0 ) drawUpArrow(p.x, 0, p.y-5);
525
+ @ if( p.f&1 ) drawBox("black",p.x-1,p.y-1,p.x+2,p.y+2);
526
+ @ if( p.d ) drawUpArrow(p.x, p.y+6, btm);
527
+ }
520528
@ if( p.mo>0 ){
521
- @ var x1 = (p.mo-1)*20 + left;
529
+ @ var x1 = p.mo + left - 1;
522530
@ var y1 = p.y-3;
523531
@ var x0 = x1>p.x ? p.x+7 : p.x-6;
524532
@ var u = rowinfo[p.mu-1];
525533
@ var y0 = u.y+5;
526
- @ if( x1==p.x ){
527
- @ y1 -= 2;
534
+ @ if( x1>=p.x-5 && x1<=p.x+5 ){
535
+ @ y1 = p.y-5;
528536
@ }else{
529537
@ drawThinLine(x0,y1,x1,y1);
530538
@ }
531539
@ drawThinLine(x1,y0,x1,y1);
532540
@ }
@@ -546,19 +554,22 @@
546554
@ drawBox("#600000",u.x-11,u.y-2,u.x-10,u.y+3);
547555
@ }
548556
@ }
549557
@ for(var j in p.mi){
550558
@ var y0 = p.y+5;
551
- @ var mx = p.mi[j]*20 + left;
559
+ @ var mx = p.mi[j];
560
+ @ if( mx<0 ){
561
+ @ mx = left-mx;
562
+ @ drawThinLine(mx,y0,mx,btm);
563
+ @ }else{
564
+ @ mx += left;
565
+ @ }
552566
@ if( mx>p.x ){
553567
@ drawThinArrow(y0,mx,p.x+6);
554568
@ }else{
555569
@ drawThinArrow(y0,mx,p.x-5);
556570
@ }
557
- @ if( (1<<p.mi[j])&p.md ){
558
- @ drawThinLine(mx,y0,mx,btm);
559
- @ }
560571
@ }
561572
@ }
562573
@ function renderGraph(){
563574
@ var canvasDiv = document.getElementById("canvas");
564575
@ while( canvasDiv.hasChildNodes() ){
@@ -763,10 +774,12 @@
763774
const char *zThisUser = 0; /* Suppress links to this user */
764775
HQuery url; /* URL for various branch links */
765776
int from_rid = name_to_rid(P("from")); /* from= for path timelines */
766777
int to_rid = name_to_rid(P("to")); /* to= for path timelines */
767778
int noMerge = P("nomerge")!=0; /* Do not follow merge links */
779
+ int me_rid = name_to_rid(P("me")); /* me= for common ancestory path */
780
+ int you_rid = name_to_rid(P("you"));/* you= for common ancst path */
768781
769782
/* To view the timeline, must have permission to read project data.
770783
*/
771784
login_check_credentials();
772785
if( !g.okRead && !g.okRdTkt && !g.okRdWiki ){ login_needed(); return; }
@@ -795,38 +808,46 @@
795808
blob_zero(&desc);
796809
blob_append(&sql, "INSERT OR IGNORE INTO timeline ", -1);
797810
blob_append(&sql, timeline_query_for_www(), -1);
798811
url_initialize(&url, "timeline");
799812
if( !useDividers ) url_add_parameter(&url, "nd", 0);
800
- if( from_rid && to_rid && g.okRead ){
813
+ if( ((from_rid && to_rid) || (me_rid && you_rid)) && g.okRead ){
801814
/* If from= and to= are present, display all nodes on a path connecting
802815
** the two */
803
- BisectNode *p;
804
- const char *z;
816
+ PathNode *p = 0;
817
+ const char *zFrom = 0;
818
+ const char *zTo = 0;
805819
806
- bisect_shortest_path(from_rid, to_rid, noMerge);
807
- p = bisect_reverse_path();
820
+ if( from_rid && to_rid ){
821
+ p = path_shortest(from_rid, to_rid, noMerge);
822
+ zFrom = P("from");
823
+ zTo = P("to");
824
+ }else{
825
+ if( path_common_ancestor(me_rid, you_rid) ){
826
+ p = path_first();
827
+ }
828
+ zFrom = P("me");
829
+ zTo = P("you");
830
+ }
808831
blob_append(&sql, " AND event.objid IN (0", -1);
809832
while( p ){
810833
blob_appendf(&sql, ",%d", p->rid);
811834
p = p->u.pTo;
812835
}
813836
blob_append(&sql, ")", -1);
814
- bisect_reset();
837
+ path_reset();
815838
blob_append(&desc, "All nodes on the path from ", -1);
816
- z = P("from");
817839
if( g.okHistory ){
818
- blob_appendf(&desc, "<a href='%s/info/%h'>[%h]</a>", g.zTop, z, z);
840
+ blob_appendf(&desc, "<a href='%s/info/%h'>[%h]</a>", g.zTop,zFrom,zFrom);
819841
}else{
820
- blob_appendf(&desc, "[%h]", z);
842
+ blob_appendf(&desc, "[%h]", zFrom);
821843
}
822844
blob_append(&desc, " and ", -1);
823
- z = P("to");
824845
if( g.okHistory ){
825
- blob_appendf(&desc, "<a href='%s/info/%h'>[%h]</a>.", g.zTop, z, z);
846
+ blob_appendf(&desc, "<a href='%s/info/%h'>[%h]</a>.", g.zTop, zTo, zTo);
826847
}else{
827
- blob_appendf(&desc, "[%h].", z);
848
+ blob_appendf(&desc, "[%h].", zTo);
828849
}
829850
tmFlags |= TIMELINE_DISJOINT;
830851
db_multi_exec("%s", blob_str(&sql));
831852
}else if( (p_rid || d_rid) && g.okRead ){
832853
/* If p= or d= is present, ignore all other parameters other than n= */
833854
--- src/timeline.c
+++ src/timeline.c
@@ -254,11 +254,11 @@
254 if( db_step(&qbranch)==SQLITE_ROW ){
255 zBr = db_column_text(&qbranch, 0);
256 }else{
257 zBr = "trunk";
258 }
259 gidx = graph_add_row(pGraph, rid, nParent, aParent, zBr, zBgClr);
260 db_reset(&qbranch);
261 @ <div id="m%d(gidx)"></div>
262 }
263 @</td>
264 if( zBgClr && zBgClr[0] ){
@@ -362,18 +362,18 @@
362 @ <div id="grbtm" style="width:%d(pGraph->mxRail*20+30)px;"></div>
363 @ </td></tr>
364 }
365 }
366 @ </table>
367 timeline_output_graph_javascript(pGraph);
368 }
369
370 /*
371 ** Generate all of the necessary javascript to generate a timeline
372 ** graph.
373 */
374 void timeline_output_graph_javascript(GraphContext *pGraph){
375 if( pGraph && pGraph->nErr==0 ){
376 GraphRow *pRow;
377 int i;
378 char cSep;
379 @ <script type="text/JavaScript">
@@ -388,42 +388,48 @@
388 ** bg: The background color for this row
389 ** r: The "rail" that the node for this row sits on. The left-most
390 ** rail is 0 and the number increases to the right.
391 ** d: True if there is a "descender" - an arrow coming from the bottom
392 ** of the page straight up to this node.
393 ** mo: "merge-out". If non-zero, this is one more than the rail on which
394 ** a merge arrow travels upward. The merge arrow is drawn upwards
395 ** to the row identified by mu:. If this value is zero then
396 ** node has no merge children and no merge-out line is drawn.
397 ** mu: The id of the row which is the top of the merge-out arrow.
398 ** md: A bitmask of rails on which merge-arrow descenders should be
399 ** drawn from this row to the bottom of the page. The least
400 ** significant bit (1) corresponds to rail 0. The 2-bit corresponds
401 ** to rail 1. And so forth. This value is 0 if there are no
402 ** merge-arrow descenders.
403 ** u: Draw a think child-line out of the top of this node and up to
404 ** the node with an id equal to this value. 0 if there is no
405 ** thick-line riser.
 
406 ** au: An array of integers that define thick-line risers for branches.
407 ** The integers are in pairs. For each pair, the first integer is
408 ** is the rail on which the riser should run and the second integer
409 ** is the id of the node upto which the riser should run.
410 ** mi: "merge-in". An array of integer rail numbers from which
411 ** merge arrows should be drawn into this node.
 
 
 
412 */
413 cgi_printf("var rowinfo = [\n");
414 for(pRow=pGraph->pFirst; pRow; pRow=pRow->pNext){
415 cgi_printf("{id:%d,bg:\"%s\",r:%d,d:%d,mo:%d,mu:%d,md:%u,u:%d,au:",
416 pRow->idx,
417 pRow->zBgClr,
418 pRow->iRail,
419 pRow->bDescender,
420 pRow->mergeOut+1,
421 pRow->mergeUpto,
422 pRow->mergeDown,
423 pRow->aiRiser[pRow->iRail]
 
 
 
 
 
 
424 );
 
425 cSep = '[';
426 for(i=0; i<GR_MAX_RAIL; i++){
427 if( i==pRow->iRail ) continue;
428 if( pRow->aiRiser[i]>0 ){
429 cgi_printf("%c%d,%d", cSep, i, pRow->aiRiser[i]);
@@ -430,14 +436,17 @@
430 cSep = ',';
431 }
432 }
433 if( cSep=='[' ) cgi_printf("[");
434 cgi_printf("],mi:");
 
435 cSep = '[';
436 for(i=0; i<GR_MAX_RAIL; i++){
437 if( pRow->mergeIn & (1<<i) ){
438 cgi_printf("%c%d", cSep, i);
 
 
439 cSep = ',';
440 }
441 }
442 if( cSep=='[' ) cgi_printf("[");
443 cgi_printf("]}%s", pRow->pNext ? ",\n" : "];\n");
@@ -508,25 +517,24 @@
508 @ drawBox("black",x0,y0,x1,y1);
509 @ }
510 @ function drawNode(p, left, btm){
511 @ drawBox("black",p.x-5,p.y-5,p.x+6,p.y+6);
512 @ drawBox(p.bg,p.x-4,p.y-4,p.x+5,p.y+5);
513 @ if( p.u>0 ){
514 @ var u = rowinfo[p.u-1];
515 @ drawUpArrow(p.x, u.y+6, p.y-5);
516 @ }
517 @ if( p.d ){
518 @ drawUpArrow(p.x, p.y+6, btm);
519 @ }
520 @ if( p.mo>0 ){
521 @ var x1 = (p.mo-1)*20 + left;
522 @ var y1 = p.y-3;
523 @ var x0 = x1>p.x ? p.x+7 : p.x-6;
524 @ var u = rowinfo[p.mu-1];
525 @ var y0 = u.y+5;
526 @ if( x1==p.x ){
527 @ y1 -= 2;
528 @ }else{
529 @ drawThinLine(x0,y1,x1,y1);
530 @ }
531 @ drawThinLine(x1,y0,x1,y1);
532 @ }
@@ -546,19 +554,22 @@
546 @ drawBox("#600000",u.x-11,u.y-2,u.x-10,u.y+3);
547 @ }
548 @ }
549 @ for(var j in p.mi){
550 @ var y0 = p.y+5;
551 @ var mx = p.mi[j]*20 + left;
 
 
 
 
 
 
552 @ if( mx>p.x ){
553 @ drawThinArrow(y0,mx,p.x+6);
554 @ }else{
555 @ drawThinArrow(y0,mx,p.x-5);
556 @ }
557 @ if( (1<<p.mi[j])&p.md ){
558 @ drawThinLine(mx,y0,mx,btm);
559 @ }
560 @ }
561 @ }
562 @ function renderGraph(){
563 @ var canvasDiv = document.getElementById("canvas");
564 @ while( canvasDiv.hasChildNodes() ){
@@ -763,10 +774,12 @@
763 const char *zThisUser = 0; /* Suppress links to this user */
764 HQuery url; /* URL for various branch links */
765 int from_rid = name_to_rid(P("from")); /* from= for path timelines */
766 int to_rid = name_to_rid(P("to")); /* to= for path timelines */
767 int noMerge = P("nomerge")!=0; /* Do not follow merge links */
 
 
768
769 /* To view the timeline, must have permission to read project data.
770 */
771 login_check_credentials();
772 if( !g.okRead && !g.okRdTkt && !g.okRdWiki ){ login_needed(); return; }
@@ -795,38 +808,46 @@
795 blob_zero(&desc);
796 blob_append(&sql, "INSERT OR IGNORE INTO timeline ", -1);
797 blob_append(&sql, timeline_query_for_www(), -1);
798 url_initialize(&url, "timeline");
799 if( !useDividers ) url_add_parameter(&url, "nd", 0);
800 if( from_rid && to_rid && g.okRead ){
801 /* If from= and to= are present, display all nodes on a path connecting
802 ** the two */
803 BisectNode *p;
804 const char *z;
 
805
806 bisect_shortest_path(from_rid, to_rid, noMerge);
807 p = bisect_reverse_path();
 
 
 
 
 
 
 
 
 
808 blob_append(&sql, " AND event.objid IN (0", -1);
809 while( p ){
810 blob_appendf(&sql, ",%d", p->rid);
811 p = p->u.pTo;
812 }
813 blob_append(&sql, ")", -1);
814 bisect_reset();
815 blob_append(&desc, "All nodes on the path from ", -1);
816 z = P("from");
817 if( g.okHistory ){
818 blob_appendf(&desc, "<a href='%s/info/%h'>[%h]</a>", g.zTop, z, z);
819 }else{
820 blob_appendf(&desc, "[%h]", z);
821 }
822 blob_append(&desc, " and ", -1);
823 z = P("to");
824 if( g.okHistory ){
825 blob_appendf(&desc, "<a href='%s/info/%h'>[%h]</a>.", g.zTop, z, z);
826 }else{
827 blob_appendf(&desc, "[%h].", z);
828 }
829 tmFlags |= TIMELINE_DISJOINT;
830 db_multi_exec("%s", blob_str(&sql));
831 }else if( (p_rid || d_rid) && g.okRead ){
832 /* If p= or d= is present, ignore all other parameters other than n= */
833
--- src/timeline.c
+++ src/timeline.c
@@ -254,11 +254,11 @@
254 if( db_step(&qbranch)==SQLITE_ROW ){
255 zBr = db_column_text(&qbranch, 0);
256 }else{
257 zBr = "trunk";
258 }
259 gidx = graph_add_row(pGraph, rid, nParent, aParent, zBr, zBgClr, isLeaf);
260 db_reset(&qbranch);
261 @ <div id="m%d(gidx)"></div>
262 }
263 @</td>
264 if( zBgClr && zBgClr[0] ){
@@ -362,18 +362,18 @@
362 @ <div id="grbtm" style="width:%d(pGraph->mxRail*20+30)px;"></div>
363 @ </td></tr>
364 }
365 }
366 @ </table>
367 timeline_output_graph_javascript(pGraph, (tmFlags & TIMELINE_DISJOINT)!=0);
368 }
369
370 /*
371 ** Generate all of the necessary javascript to generate a timeline
372 ** graph.
373 */
374 void timeline_output_graph_javascript(GraphContext *pGraph, int omitDescenders){
375 if( pGraph && pGraph->nErr==0 ){
376 GraphRow *pRow;
377 int i;
378 char cSep;
379 @ <script type="text/JavaScript">
@@ -388,42 +388,48 @@
388 ** bg: The background color for this row
389 ** r: The "rail" that the node for this row sits on. The left-most
390 ** rail is 0 and the number increases to the right.
391 ** d: True if there is a "descender" - an arrow coming from the bottom
392 ** of the page straight up to this node.
393 ** mo: "merge-out". If non-zero, this is one more than the x-coordinate
394 ** for the upward portion of a merge arrow. The merge arrow goes up
395 ** to the row identified by mu:. If this value is zero then
396 ** node has no merge children and no merge-out line is drawn.
397 ** mu: The id of the row which is the top of the merge-out arrow.
398 ** u: Draw a thick child-line out of the top of this node and up to
 
 
 
 
 
399 ** the node with an id equal to this value. 0 if there is no
400 ** thick-line riser.
401 ** f: 0x01: a leaf node.
402 ** au: An array of integers that define thick-line risers for branches.
403 ** The integers are in pairs. For each pair, the first integer is
404 ** is the rail on which the riser should run and the second integer
405 ** is the id of the node upto which the riser should run.
406 ** mi: "merge-in". An array of integer x-coordinates from which
407 ** merge arrows should be drawn into this node. If the value is
408 ** negative, then the x-coordinate is the absolute value of mi[]
409 ** and a thin merge-arrow descender is drawn to the bottom of
410 ** the screen.
411 */
412 cgi_printf("var rowinfo = [\n");
413 for(pRow=pGraph->pFirst; pRow; pRow=pRow->pNext){
414 int mo = pRow->mergeOut;
415 if( mo<0 ){
416 mo = 0;
417 }else{
418 mo = (mo/4)*20 - 3 + 4*(mo&3);
419 }
420 cgi_printf("{id:%d,bg:\"%s\",r:%d,d:%d,mo:%d,mu:%d,u:%d,f:%d,au:",
421 pRow->idx, /* id */
422 pRow->zBgClr, /* bg */
423 pRow->iRail, /* r */
424 pRow->bDescender, /* d */
425 mo, /* mo */
426 pRow->mergeUpto, /* mu */
427 pRow->aiRiser[pRow->iRail], /* u */
428 pRow->isLeaf ? 1 : 0 /* f */
429 );
430 /* u */
431 cSep = '[';
432 for(i=0; i<GR_MAX_RAIL; i++){
433 if( i==pRow->iRail ) continue;
434 if( pRow->aiRiser[i]>0 ){
435 cgi_printf("%c%d,%d", cSep, i, pRow->aiRiser[i]);
@@ -430,14 +436,17 @@
436 cSep = ',';
437 }
438 }
439 if( cSep=='[' ) cgi_printf("[");
440 cgi_printf("],mi:");
441 /* mi */
442 cSep = '[';
443 for(i=0; i<GR_MAX_RAIL; i++){
444 if( pRow->mergeIn[i] ){
445 int mi = i*20 - 8 + 4*pRow->mergeIn[i];
446 if( pRow->mergeDown & (1<<i) ) mi = -mi;
447 cgi_printf("%c%d", cSep, mi);
448 cSep = ',';
449 }
450 }
451 if( cSep=='[' ) cgi_printf("[");
452 cgi_printf("]}%s", pRow->pNext ? ",\n" : "];\n");
@@ -508,25 +517,24 @@
517 @ drawBox("black",x0,y0,x1,y1);
518 @ }
519 @ function drawNode(p, left, btm){
520 @ drawBox("black",p.x-5,p.y-5,p.x+6,p.y+6);
521 @ drawBox(p.bg,p.x-4,p.y-4,p.x+5,p.y+5);
522 @ if( p.u>0 ) drawUpArrow(p.x, rowinfo[p.u-1].y+6, p.y-5);
523 if( !omitDescenders ){
524 @ if( p.u==0 ) drawUpArrow(p.x, 0, p.y-5);
525 @ if( p.f&1 ) drawBox("black",p.x-1,p.y-1,p.x+2,p.y+2);
526 @ if( p.d ) drawUpArrow(p.x, p.y+6, btm);
527 }
 
528 @ if( p.mo>0 ){
529 @ var x1 = p.mo + left - 1;
530 @ var y1 = p.y-3;
531 @ var x0 = x1>p.x ? p.x+7 : p.x-6;
532 @ var u = rowinfo[p.mu-1];
533 @ var y0 = u.y+5;
534 @ if( x1>=p.x-5 && x1<=p.x+5 ){
535 @ y1 = p.y-5;
536 @ }else{
537 @ drawThinLine(x0,y1,x1,y1);
538 @ }
539 @ drawThinLine(x1,y0,x1,y1);
540 @ }
@@ -546,19 +554,22 @@
554 @ drawBox("#600000",u.x-11,u.y-2,u.x-10,u.y+3);
555 @ }
556 @ }
557 @ for(var j in p.mi){
558 @ var y0 = p.y+5;
559 @ var mx = p.mi[j];
560 @ if( mx<0 ){
561 @ mx = left-mx;
562 @ drawThinLine(mx,y0,mx,btm);
563 @ }else{
564 @ mx += left;
565 @ }
566 @ if( mx>p.x ){
567 @ drawThinArrow(y0,mx,p.x+6);
568 @ }else{
569 @ drawThinArrow(y0,mx,p.x-5);
570 @ }
 
 
 
571 @ }
572 @ }
573 @ function renderGraph(){
574 @ var canvasDiv = document.getElementById("canvas");
575 @ while( canvasDiv.hasChildNodes() ){
@@ -763,10 +774,12 @@
774 const char *zThisUser = 0; /* Suppress links to this user */
775 HQuery url; /* URL for various branch links */
776 int from_rid = name_to_rid(P("from")); /* from= for path timelines */
777 int to_rid = name_to_rid(P("to")); /* to= for path timelines */
778 int noMerge = P("nomerge")!=0; /* Do not follow merge links */
779 int me_rid = name_to_rid(P("me")); /* me= for common ancestory path */
780 int you_rid = name_to_rid(P("you"));/* you= for common ancst path */
781
782 /* To view the timeline, must have permission to read project data.
783 */
784 login_check_credentials();
785 if( !g.okRead && !g.okRdTkt && !g.okRdWiki ){ login_needed(); return; }
@@ -795,38 +808,46 @@
808 blob_zero(&desc);
809 blob_append(&sql, "INSERT OR IGNORE INTO timeline ", -1);
810 blob_append(&sql, timeline_query_for_www(), -1);
811 url_initialize(&url, "timeline");
812 if( !useDividers ) url_add_parameter(&url, "nd", 0);
813 if( ((from_rid && to_rid) || (me_rid && you_rid)) && g.okRead ){
814 /* If from= and to= are present, display all nodes on a path connecting
815 ** the two */
816 PathNode *p = 0;
817 const char *zFrom = 0;
818 const char *zTo = 0;
819
820 if( from_rid && to_rid ){
821 p = path_shortest(from_rid, to_rid, noMerge);
822 zFrom = P("from");
823 zTo = P("to");
824 }else{
825 if( path_common_ancestor(me_rid, you_rid) ){
826 p = path_first();
827 }
828 zFrom = P("me");
829 zTo = P("you");
830 }
831 blob_append(&sql, " AND event.objid IN (0", -1);
832 while( p ){
833 blob_appendf(&sql, ",%d", p->rid);
834 p = p->u.pTo;
835 }
836 blob_append(&sql, ")", -1);
837 path_reset();
838 blob_append(&desc, "All nodes on the path from ", -1);
 
839 if( g.okHistory ){
840 blob_appendf(&desc, "<a href='%s/info/%h'>[%h]</a>", g.zTop,zFrom,zFrom);
841 }else{
842 blob_appendf(&desc, "[%h]", zFrom);
843 }
844 blob_append(&desc, " and ", -1);
 
845 if( g.okHistory ){
846 blob_appendf(&desc, "<a href='%s/info/%h'>[%h]</a>.", g.zTop, zTo, zTo);
847 }else{
848 blob_appendf(&desc, "[%h].", zTo);
849 }
850 tmFlags |= TIMELINE_DISJOINT;
851 db_multi_exec("%s", blob_str(&sql));
852 }else if( (p_rid || d_rid) && g.okRead ){
853 /* If p= or d= is present, ignore all other parameters other than n= */
854
+1 -1
--- src/tkt.c
+++ src/tkt.c
@@ -852,11 +852,11 @@
852852
** ?-q|--quote?
853853
** ?-R|--repository FILE?
854854
**
855855
** Run the ticket report, identified by the report format title
856856
** used in the gui. The data is written as flat file on stdout,
857
-** using "," as separator. The seperator "," can be changed using
857
+** using "," as separator. The separator "," can be changed using
858858
** the -l or --limit option.
859859
** If TICKETFILTER is given on the commandline, the query is
860860
** limited with a new WHERE-condition.
861861
** example: Report lists a column # with the uuid
862862
** TICKETFILTER may be [#]='uuuuuuuuu'
863863
--- src/tkt.c
+++ src/tkt.c
@@ -852,11 +852,11 @@
852 ** ?-q|--quote?
853 ** ?-R|--repository FILE?
854 **
855 ** Run the ticket report, identified by the report format title
856 ** used in the gui. The data is written as flat file on stdout,
857 ** using "," as separator. The seperator "," can be changed using
858 ** the -l or --limit option.
859 ** If TICKETFILTER is given on the commandline, the query is
860 ** limited with a new WHERE-condition.
861 ** example: Report lists a column # with the uuid
862 ** TICKETFILTER may be [#]='uuuuuuuuu'
863
--- src/tkt.c
+++ src/tkt.c
@@ -852,11 +852,11 @@
852 ** ?-q|--quote?
853 ** ?-R|--repository FILE?
854 **
855 ** Run the ticket report, identified by the report format title
856 ** used in the gui. The data is written as flat file on stdout,
857 ** using "," as separator. The separator "," can be changed using
858 ** the -l or --limit option.
859 ** If TICKETFILTER is given on the commandline, the query is
860 ** limited with a new WHERE-condition.
861 ** example: Report lists a column # with the uuid
862 ** TICKETFILTER may be [#]='uuuuuuuuu'
863
+3 -2
--- src/user.c
+++ src/user.c
@@ -115,11 +115,11 @@
115115
blob_zero(&secondTry);
116116
while(1){
117117
prompt_for_passphrase(zPrompt, pPassphrase);
118118
if( verify==0 ) break;
119119
if( verify==1 && blob_size(pPassphrase)==0 ) break;
120
- prompt_for_passphrase("Again: ", &secondTry);
120
+ prompt_for_passphrase("Retype new password: ", &secondTry);
121121
if( blob_compare(pPassphrase, &secondTry) ){
122122
printf("Passphrases do not match. Try again...\n");
123123
}else{
124124
break;
125125
}
@@ -242,11 +242,11 @@
242242
fossil_fatal("no such user: %s", g.argv[3]);
243243
}
244244
if( g.argc==5 ){
245245
blob_init(&pw, g.argv[4], -1);
246246
}else{
247
- zPrompt = mprintf("new passwd for %s: ", g.argv[3]);
247
+ zPrompt = mprintf("New password for %s: ", g.argv[3]);
248248
prompt_for_password(zPrompt, &pw, 1);
249249
}
250250
if( blob_size(&pw)==0 ){
251251
printf("password unchanged\n");
252252
}else{
@@ -404,10 +404,11 @@
404404
int cnt = 0;
405405
int rc;
406406
407407
login_check_credentials();
408408
if( !g.okAdmin ){ login_needed(); return; }
409
+ create_accesslog_table();
409410
410411
if( P("delall") && P("delallbtn") ){
411412
db_multi_exec("DELETE FROM accesslog");
412413
cgi_redirectf("%s/access_log?y=%d&n=%d&o=%o", g.zTop, y, n, skip);
413414
return;
414415
--- src/user.c
+++ src/user.c
@@ -115,11 +115,11 @@
115 blob_zero(&secondTry);
116 while(1){
117 prompt_for_passphrase(zPrompt, pPassphrase);
118 if( verify==0 ) break;
119 if( verify==1 && blob_size(pPassphrase)==0 ) break;
120 prompt_for_passphrase("Again: ", &secondTry);
121 if( blob_compare(pPassphrase, &secondTry) ){
122 printf("Passphrases do not match. Try again...\n");
123 }else{
124 break;
125 }
@@ -242,11 +242,11 @@
242 fossil_fatal("no such user: %s", g.argv[3]);
243 }
244 if( g.argc==5 ){
245 blob_init(&pw, g.argv[4], -1);
246 }else{
247 zPrompt = mprintf("new passwd for %s: ", g.argv[3]);
248 prompt_for_password(zPrompt, &pw, 1);
249 }
250 if( blob_size(&pw)==0 ){
251 printf("password unchanged\n");
252 }else{
@@ -404,10 +404,11 @@
404 int cnt = 0;
405 int rc;
406
407 login_check_credentials();
408 if( !g.okAdmin ){ login_needed(); return; }
 
409
410 if( P("delall") && P("delallbtn") ){
411 db_multi_exec("DELETE FROM accesslog");
412 cgi_redirectf("%s/access_log?y=%d&n=%d&o=%o", g.zTop, y, n, skip);
413 return;
414
--- src/user.c
+++ src/user.c
@@ -115,11 +115,11 @@
115 blob_zero(&secondTry);
116 while(1){
117 prompt_for_passphrase(zPrompt, pPassphrase);
118 if( verify==0 ) break;
119 if( verify==1 && blob_size(pPassphrase)==0 ) break;
120 prompt_for_passphrase("Retype new password: ", &secondTry);
121 if( blob_compare(pPassphrase, &secondTry) ){
122 printf("Passphrases do not match. Try again...\n");
123 }else{
124 break;
125 }
@@ -242,11 +242,11 @@
242 fossil_fatal("no such user: %s", g.argv[3]);
243 }
244 if( g.argc==5 ){
245 blob_init(&pw, g.argv[4], -1);
246 }else{
247 zPrompt = mprintf("New password for %s: ", g.argv[3]);
248 prompt_for_password(zPrompt, &pw, 1);
249 }
250 if( blob_size(&pw)==0 ){
251 printf("password unchanged\n");
252 }else{
@@ -404,10 +404,11 @@
404 int cnt = 0;
405 int rc;
406
407 login_check_credentials();
408 if( !g.okAdmin ){ login_needed(); return; }
409 create_accesslog_table();
410
411 if( P("delall") && P("delallbtn") ){
412 db_multi_exec("DELETE FROM accesslog");
413 cgi_redirectf("%s/access_log?y=%d&n=%d&o=%o", g.zTop, y, n, skip);
414 return;
415
-1
--- src/wiki.c
+++ src/wiki.c
@@ -823,11 +823,10 @@
823823
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
824824
manifest_crosslink(nrid,&wiki);
825825
assert( blob_is_reset(&wiki) );
826826
content_deltify(rid,nrid,0);
827827
db_end_transaction(0);
828
- autosync(AUTOSYNC_PUSH);
829828
return 1;
830829
}
831830
832831
/*
833832
** COMMAND: wiki
834833
--- src/wiki.c
+++ src/wiki.c
@@ -823,11 +823,10 @@
823 db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
824 manifest_crosslink(nrid,&wiki);
825 assert( blob_is_reset(&wiki) );
826 content_deltify(rid,nrid,0);
827 db_end_transaction(0);
828 autosync(AUTOSYNC_PUSH);
829 return 1;
830 }
831
832 /*
833 ** COMMAND: wiki
834
--- src/wiki.c
+++ src/wiki.c
@@ -823,11 +823,10 @@
823 db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
824 manifest_crosslink(nrid,&wiki);
825 assert( blob_is_reset(&wiki) );
826 content_deltify(rid,nrid,0);
827 db_end_transaction(0);
 
828 return 1;
829 }
830
831 /*
832 ** COMMAND: wiki
833
+30 -8
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -939,10 +939,26 @@
939939
int n = strlen(z);
940940
if( n<4 || n>UUID_SIZE ) return 0;
941941
if( !validate16(z, n) ) return 0;
942942
return 1;
943943
}
944
+
945
+/*
946
+** Return TRUE if a UUID corresponds to an artifact in this
947
+** repository.
948
+*/
949
+static int in_this_repo(const char *zUuid){
950
+ static Stmt q;
951
+ int rc;
952
+ db_static_prepare(&q,
953
+ "SELECT 1 FROM blob WHERE uuid>=:u AND +uuid GLOB (:u || '*')"
954
+ );
955
+ db_bind_text(&q, ":u", zUuid);
956
+ rc = db_step(&q);
957
+ db_reset(&q);
958
+ return rc==SQLITE_ROW;
959
+}
944960
945961
/*
946962
** zTarget is guaranteed to be a UUID. It might be the UUID of a ticket.
947963
** If it is, store in *pClosed a true or false depending on whether or not
948964
** the ticket is closed and return true. If zTarget
@@ -1047,29 +1063,35 @@
10471063
** as crossed out if the ticket is closed.
10481064
*/
10491065
if( isClosed ){
10501066
if( g.okHistory ){
10511067
blob_appendf(p->pOut,
1052
- "<a href=\"%s/info/%s\"><span class=\"wikiTagCancelled\">",
1068
+ "<a href=\"%s/info/%s\"><span class=\"wikiTagCancelled\">[",
10531069
g.zTop, zTarget
10541070
);
1055
- zTerm = "</span></a>";
1071
+ zTerm = "]</span></a>";
10561072
}else{
1057
- blob_appendf(p->pOut,"<span class=\"wikiTagCancelled\">");
1058
- zTerm = "</span>";
1073
+ blob_appendf(p->pOut,"<span class=\"wikiTagCancelled\">[");
1074
+ zTerm = "]</span>";
10591075
}
10601076
}else{
10611077
if( g.okHistory ){
1062
- blob_appendf(p->pOut,"<a href=\"%s/info/%s\">",
1078
+ blob_appendf(p->pOut,"<a href=\"%s/info/%s\">[",
10631079
g.zTop, zTarget
10641080
);
1081
+ zTerm = "]</a>";
10651082
}else{
1066
- zTerm = "";
1083
+ blob_appendf(p->pOut, "[");
1084
+ zTerm = "]";
10671085
}
10681086
}
1087
+ }else if( !in_this_repo(zTarget) ){
1088
+ blob_appendf(p->pOut, "<span class=\"brokenlink\">[", zTarget);
1089
+ zTerm = "]</span>";
10691090
}else if( g.okHistory ){
1070
- blob_appendf(p->pOut, "<a href=\"%s/info/%s\">", g.zTop, zTarget);
1091
+ blob_appendf(p->pOut, "<a href=\"%s/info/%s\">[", g.zTop, zTarget);
1092
+ zTerm = "]</a>";
10711093
}
10721094
}else if( strlen(zTarget)>=10 && fossil_isdigit(zTarget[0]) && zTarget[4]=='-'
10731095
&& db_int(0, "SELECT datetime(%Q) NOT NULL", zTarget) ){
10741096
blob_appendf(p->pOut, "<a href=\"%s/timeline?c=%T\">", g.zTop, zTarget);
10751097
}else if( strncmp(zTarget, "wiki:", 5)==0
@@ -1077,11 +1099,11 @@
10771099
zTarget += 5;
10781100
blob_appendf(p->pOut, "<a href=\"%s/wiki?name=%T\">", g.zTop, zTarget);
10791101
}else if( wiki_name_is_wellformed((const unsigned char *)zTarget) ){
10801102
blob_appendf(p->pOut, "<a href=\"%s/wiki?name=%T\">", g.zTop, zTarget);
10811103
}else{
1082
- blob_appendf(p->pOut, "[bad-link: %h]", zTarget);
1104
+ blob_appendf(p->pOut, "<span class=\"brokenlink\">[%h]</span>", zTarget);
10831105
zTerm = "";
10841106
}
10851107
assert( strlen(zTerm)<nClose );
10861108
sqlite3_snprintf(nClose, zClose, "%s", zTerm);
10871109
}
10881110
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -939,10 +939,26 @@
939 int n = strlen(z);
940 if( n<4 || n>UUID_SIZE ) return 0;
941 if( !validate16(z, n) ) return 0;
942 return 1;
943 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
944
945 /*
946 ** zTarget is guaranteed to be a UUID. It might be the UUID of a ticket.
947 ** If it is, store in *pClosed a true or false depending on whether or not
948 ** the ticket is closed and return true. If zTarget
@@ -1047,29 +1063,35 @@
1047 ** as crossed out if the ticket is closed.
1048 */
1049 if( isClosed ){
1050 if( g.okHistory ){
1051 blob_appendf(p->pOut,
1052 "<a href=\"%s/info/%s\"><span class=\"wikiTagCancelled\">",
1053 g.zTop, zTarget
1054 );
1055 zTerm = "</span></a>";
1056 }else{
1057 blob_appendf(p->pOut,"<span class=\"wikiTagCancelled\">");
1058 zTerm = "</span>";
1059 }
1060 }else{
1061 if( g.okHistory ){
1062 blob_appendf(p->pOut,"<a href=\"%s/info/%s\">",
1063 g.zTop, zTarget
1064 );
 
1065 }else{
1066 zTerm = "";
 
1067 }
1068 }
 
 
 
1069 }else if( g.okHistory ){
1070 blob_appendf(p->pOut, "<a href=\"%s/info/%s\">", g.zTop, zTarget);
 
1071 }
1072 }else if( strlen(zTarget)>=10 && fossil_isdigit(zTarget[0]) && zTarget[4]=='-'
1073 && db_int(0, "SELECT datetime(%Q) NOT NULL", zTarget) ){
1074 blob_appendf(p->pOut, "<a href=\"%s/timeline?c=%T\">", g.zTop, zTarget);
1075 }else if( strncmp(zTarget, "wiki:", 5)==0
@@ -1077,11 +1099,11 @@
1077 zTarget += 5;
1078 blob_appendf(p->pOut, "<a href=\"%s/wiki?name=%T\">", g.zTop, zTarget);
1079 }else if( wiki_name_is_wellformed((const unsigned char *)zTarget) ){
1080 blob_appendf(p->pOut, "<a href=\"%s/wiki?name=%T\">", g.zTop, zTarget);
1081 }else{
1082 blob_appendf(p->pOut, "[bad-link: %h]", zTarget);
1083 zTerm = "";
1084 }
1085 assert( strlen(zTerm)<nClose );
1086 sqlite3_snprintf(nClose, zClose, "%s", zTerm);
1087 }
1088
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -939,10 +939,26 @@
939 int n = strlen(z);
940 if( n<4 || n>UUID_SIZE ) return 0;
941 if( !validate16(z, n) ) return 0;
942 return 1;
943 }
944
945 /*
946 ** Return TRUE if a UUID corresponds to an artifact in this
947 ** repository.
948 */
949 static int in_this_repo(const char *zUuid){
950 static Stmt q;
951 int rc;
952 db_static_prepare(&q,
953 "SELECT 1 FROM blob WHERE uuid>=:u AND +uuid GLOB (:u || '*')"
954 );
955 db_bind_text(&q, ":u", zUuid);
956 rc = db_step(&q);
957 db_reset(&q);
958 return rc==SQLITE_ROW;
959 }
960
961 /*
962 ** zTarget is guaranteed to be a UUID. It might be the UUID of a ticket.
963 ** If it is, store in *pClosed a true or false depending on whether or not
964 ** the ticket is closed and return true. If zTarget
@@ -1047,29 +1063,35 @@
1063 ** as crossed out if the ticket is closed.
1064 */
1065 if( isClosed ){
1066 if( g.okHistory ){
1067 blob_appendf(p->pOut,
1068 "<a href=\"%s/info/%s\"><span class=\"wikiTagCancelled\">[",
1069 g.zTop, zTarget
1070 );
1071 zTerm = "]</span></a>";
1072 }else{
1073 blob_appendf(p->pOut,"<span class=\"wikiTagCancelled\">[");
1074 zTerm = "]</span>";
1075 }
1076 }else{
1077 if( g.okHistory ){
1078 blob_appendf(p->pOut,"<a href=\"%s/info/%s\">[",
1079 g.zTop, zTarget
1080 );
1081 zTerm = "]</a>";
1082 }else{
1083 blob_appendf(p->pOut, "[");
1084 zTerm = "]";
1085 }
1086 }
1087 }else if( !in_this_repo(zTarget) ){
1088 blob_appendf(p->pOut, "<span class=\"brokenlink\">[", zTarget);
1089 zTerm = "]</span>";
1090 }else if( g.okHistory ){
1091 blob_appendf(p->pOut, "<a href=\"%s/info/%s\">[", g.zTop, zTarget);
1092 zTerm = "]</a>";
1093 }
1094 }else if( strlen(zTarget)>=10 && fossil_isdigit(zTarget[0]) && zTarget[4]=='-'
1095 && db_int(0, "SELECT datetime(%Q) NOT NULL", zTarget) ){
1096 blob_appendf(p->pOut, "<a href=\"%s/timeline?c=%T\">", g.zTop, zTarget);
1097 }else if( strncmp(zTarget, "wiki:", 5)==0
@@ -1077,11 +1099,11 @@
1099 zTarget += 5;
1100 blob_appendf(p->pOut, "<a href=\"%s/wiki?name=%T\">", g.zTop, zTarget);
1101 }else if( wiki_name_is_wellformed((const unsigned char *)zTarget) ){
1102 blob_appendf(p->pOut, "<a href=\"%s/wiki?name=%T\">", g.zTop, zTarget);
1103 }else{
1104 blob_appendf(p->pOut, "<span class=\"brokenlink\">[%h]</span>", zTarget);
1105 zTerm = "";
1106 }
1107 assert( strlen(zTerm)<nClose );
1108 sqlite3_snprintf(nClose, zClose, "%s", zTerm);
1109 }
1110
+1 -1
--- src/winhttp.c
+++ src/winhttp.c
@@ -107,11 +107,11 @@
107107
}
108108
wanted -= got;
109109
}
110110
fclose(out);
111111
out = 0;
112
- sqlite3_snprintf(sizeof(zCmd), zCmd, "\"%s\" http \"%s\" %s %s %s%s",
112
+ sqlite3_snprintf(sizeof(zCmd), zCmd, "\"%s\" http \"%s\" %s %s %s --nossl%s",
113113
fossil_nameofexe(), g.zRepositoryName, zRequestFName, zReplyFName,
114114
inet_ntoa(p->addr.sin_addr), p->zOptions
115115
);
116116
fossil_system(zCmd);
117117
in = fopen(zReplyFName, "rb");
118118
--- src/winhttp.c
+++ src/winhttp.c
@@ -107,11 +107,11 @@
107 }
108 wanted -= got;
109 }
110 fclose(out);
111 out = 0;
112 sqlite3_snprintf(sizeof(zCmd), zCmd, "\"%s\" http \"%s\" %s %s %s%s",
113 fossil_nameofexe(), g.zRepositoryName, zRequestFName, zReplyFName,
114 inet_ntoa(p->addr.sin_addr), p->zOptions
115 );
116 fossil_system(zCmd);
117 in = fopen(zReplyFName, "rb");
118
--- src/winhttp.c
+++ src/winhttp.c
@@ -107,11 +107,11 @@
107 }
108 wanted -= got;
109 }
110 fclose(out);
111 out = 0;
112 sqlite3_snprintf(sizeof(zCmd), zCmd, "\"%s\" http \"%s\" %s %s %s --nossl%s",
113 fossil_nameofexe(), g.zRepositoryName, zRequestFName, zReplyFName,
114 inet_ntoa(p->addr.sin_addr), p->zOptions
115 );
116 fossil_system(zCmd);
117 in = fopen(zReplyFName, "rb");
118
+1 -1
--- src/xfer.c
+++ src/xfer.c
@@ -811,11 +811,11 @@
811811
login_set_anon_nobody_capabilities();
812812
memset(&xfer, 0, sizeof(xfer));
813813
blobarray_zero(xfer.aToken, count(xfer.aToken));
814814
cgi_set_content_type(g.zContentType);
815815
if( db_schema_is_outofdate() ){
816
- @ error database\sschema\sis\out-of-date\son\sthe\sserver.
816
+ @ error database\sschema\sis\sout-of-date\son\sthe\sserver.
817817
return;
818818
}
819819
blob_zero(&xfer.err);
820820
xfer.pIn = &g.cgiIn;
821821
xfer.pOut = cgi_output_blob();
822822
--- src/xfer.c
+++ src/xfer.c
@@ -811,11 +811,11 @@
811 login_set_anon_nobody_capabilities();
812 memset(&xfer, 0, sizeof(xfer));
813 blobarray_zero(xfer.aToken, count(xfer.aToken));
814 cgi_set_content_type(g.zContentType);
815 if( db_schema_is_outofdate() ){
816 @ error database\sschema\sis\out-of-date\son\sthe\sserver.
817 return;
818 }
819 blob_zero(&xfer.err);
820 xfer.pIn = &g.cgiIn;
821 xfer.pOut = cgi_output_blob();
822
--- src/xfer.c
+++ src/xfer.c
@@ -811,11 +811,11 @@
811 login_set_anon_nobody_capabilities();
812 memset(&xfer, 0, sizeof(xfer));
813 blobarray_zero(xfer.aToken, count(xfer.aToken));
814 cgi_set_content_type(g.zContentType);
815 if( db_schema_is_outofdate() ){
816 @ error database\sschema\sis\sout-of-date\son\sthe\sserver.
817 return;
818 }
819 blob_zero(&xfer.err);
820 xfer.pIn = &g.cgiIn;
821 xfer.pOut = cgi_output_blob();
822
+10 -4
--- win/Makefile.dmc
+++ win/Makefile.dmc
@@ -24,13 +24,13 @@
2424
TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(I18N) $(SSL) $(INCL)
2525
LIBS = $(DMDIR)\extra\lib\ zlib wsock32
2626
2727
SQLITE_OPTIONS = -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT2 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0
2828
29
-SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c leaf_.c login_.c main_.c manifest_.c md5_.c merge_.c merge3_.c name_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c sqlcmd_.c stash_.c stat_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c update_.c url_.c user_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c xfer_.c zip_.c
29
+SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c leaf_.c login_.c main_.c manifest_.c md5_.c merge_.c merge3_.c name_.c path_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c sqlcmd_.c stash_.c stat_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c update_.c url_.c user_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c xfer_.c zip_.c
3030
31
-OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\leaf$O $(OBJDIR)\login$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\name$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\rebuild$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winhttp$O $(OBJDIR)\xfer$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O
31
+OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\leaf$O $(OBJDIR)\login$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\rebuild$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winhttp$O $(OBJDIR)\xfer$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O
3232
3333
3434
RC=$(DMDIR)\bin\rcc
3535
RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__
3636
@@ -44,11 +44,11 @@
4444
4545
$(OBJDIR)\fossil.res: $B\win\fossil.rc
4646
$(RC) $(RCFLAGS) -o$@ $**
4747
4848
$(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res
49
- +echo add allrepo attach bag bisect blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo graph gzip http http_socket http_ssl http_transport import info leaf login main manifest md5 merge merge3 name pivot popen pqueue printf rebuild report rss schema search setup sha1 shun skins sqlcmd stash stat style sync tag tar th_main timeline tkt tktsetup undo update url user verify vfile wiki wikiformat winhttp xfer zip shell sqlite3 th th_lang > $@
49
+ +echo add allrepo attach bag bisect blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo graph gzip http http_socket http_ssl http_transport import info leaf login main manifest md5 merge merge3 name path pivot popen pqueue printf rebuild report rss schema search setup sha1 shun skins sqlcmd stash stat style sync tag tar th_main timeline tkt tktsetup undo update url user verify vfile wiki wikiformat winhttp xfer zip shell sqlite3 th th_lang > $@
5050
+echo fossil >> $@
5151
+echo fossil >> $@
5252
+echo $(LIBS) >> $@
5353
+echo. >> $@
5454
+echo fossil >> $@
@@ -358,10 +358,16 @@
358358
$(OBJDIR)\name$O : name_.c name.h
359359
$(TCC) -o$@ -c name_.c
360360
361361
name_.c : $(SRCDIR)\name.c
362362
+translate$E $** > $@
363
+
364
+$(OBJDIR)\path$O : path_.c path.h
365
+ $(TCC) -o$@ -c path_.c
366
+
367
+path_.c : $(SRCDIR)\path.c
368
+ +translate$E $** > $@
363369
364370
$(OBJDIR)\pivot$O : pivot_.c pivot.h
365371
$(TCC) -o$@ -c pivot_.c
366372
367373
pivot_.c : $(SRCDIR)\pivot.c
@@ -570,7 +576,7 @@
570576
571577
zip_.c : $(SRCDIR)\zip.c
572578
+translate$E $** > $@
573579
574580
headers: makeheaders$E page_index.h VERSION.h
575
- +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h graph_.c:graph.h gzip_.c:gzip.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h leaf_.c:leaf.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h
581
+ +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h graph_.c:graph.h gzip_.c:gzip.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h leaf_.c:leaf.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h path_.c:path.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h
576582
@copy /Y nul: headers
577583
--- win/Makefile.dmc
+++ win/Makefile.dmc
@@ -24,13 +24,13 @@
24 TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(I18N) $(SSL) $(INCL)
25 LIBS = $(DMDIR)\extra\lib\ zlib wsock32
26
27 SQLITE_OPTIONS = -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT2 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0
28
29 SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c leaf_.c login_.c main_.c manifest_.c md5_.c merge_.c merge3_.c name_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c sqlcmd_.c stash_.c stat_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c update_.c url_.c user_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c xfer_.c zip_.c
30
31 OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\leaf$O $(OBJDIR)\login$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\name$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\rebuild$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winhttp$O $(OBJDIR)\xfer$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O
32
33
34 RC=$(DMDIR)\bin\rcc
35 RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__
36
@@ -44,11 +44,11 @@
44
45 $(OBJDIR)\fossil.res: $B\win\fossil.rc
46 $(RC) $(RCFLAGS) -o$@ $**
47
48 $(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res
49 +echo add allrepo attach bag bisect blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo graph gzip http http_socket http_ssl http_transport import info leaf login main manifest md5 merge merge3 name pivot popen pqueue printf rebuild report rss schema search setup sha1 shun skins sqlcmd stash stat style sync tag tar th_main timeline tkt tktsetup undo update url user verify vfile wiki wikiformat winhttp xfer zip shell sqlite3 th th_lang > $@
50 +echo fossil >> $@
51 +echo fossil >> $@
52 +echo $(LIBS) >> $@
53 +echo. >> $@
54 +echo fossil >> $@
@@ -358,10 +358,16 @@
358 $(OBJDIR)\name$O : name_.c name.h
359 $(TCC) -o$@ -c name_.c
360
361 name_.c : $(SRCDIR)\name.c
362 +translate$E $** > $@
 
 
 
 
 
 
363
364 $(OBJDIR)\pivot$O : pivot_.c pivot.h
365 $(TCC) -o$@ -c pivot_.c
366
367 pivot_.c : $(SRCDIR)\pivot.c
@@ -570,7 +576,7 @@
570
571 zip_.c : $(SRCDIR)\zip.c
572 +translate$E $** > $@
573
574 headers: makeheaders$E page_index.h VERSION.h
575 +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h graph_.c:graph.h gzip_.c:gzip.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h leaf_.c:leaf.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h
576 @copy /Y nul: headers
577
--- win/Makefile.dmc
+++ win/Makefile.dmc
@@ -24,13 +24,13 @@
24 TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(I18N) $(SSL) $(INCL)
25 LIBS = $(DMDIR)\extra\lib\ zlib wsock32
26
27 SQLITE_OPTIONS = -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT2 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0
28
29 SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c leaf_.c login_.c main_.c manifest_.c md5_.c merge_.c merge3_.c name_.c path_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c sqlcmd_.c stash_.c stat_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c update_.c url_.c user_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c xfer_.c zip_.c
30
31 OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\leaf$O $(OBJDIR)\login$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\rebuild$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winhttp$O $(OBJDIR)\xfer$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O
32
33
34 RC=$(DMDIR)\bin\rcc
35 RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__
36
@@ -44,11 +44,11 @@
44
45 $(OBJDIR)\fossil.res: $B\win\fossil.rc
46 $(RC) $(RCFLAGS) -o$@ $**
47
48 $(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res
49 +echo add allrepo attach bag bisect blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo graph gzip http http_socket http_ssl http_transport import info leaf login main manifest md5 merge merge3 name path pivot popen pqueue printf rebuild report rss schema search setup sha1 shun skins sqlcmd stash stat style sync tag tar th_main timeline tkt tktsetup undo update url user verify vfile wiki wikiformat winhttp xfer zip shell sqlite3 th th_lang > $@
50 +echo fossil >> $@
51 +echo fossil >> $@
52 +echo $(LIBS) >> $@
53 +echo. >> $@
54 +echo fossil >> $@
@@ -358,10 +358,16 @@
358 $(OBJDIR)\name$O : name_.c name.h
359 $(TCC) -o$@ -c name_.c
360
361 name_.c : $(SRCDIR)\name.c
362 +translate$E $** > $@
363
364 $(OBJDIR)\path$O : path_.c path.h
365 $(TCC) -o$@ -c path_.c
366
367 path_.c : $(SRCDIR)\path.c
368 +translate$E $** > $@
369
370 $(OBJDIR)\pivot$O : pivot_.c pivot.h
371 $(TCC) -o$@ -c pivot_.c
372
373 pivot_.c : $(SRCDIR)\pivot.c
@@ -570,7 +576,7 @@
576
577 zip_.c : $(SRCDIR)\zip.c
578 +translate$E $** > $@
579
580 headers: makeheaders$E page_index.h VERSION.h
581 +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h graph_.c:graph.h gzip_.c:gzip.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h leaf_.c:leaf.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h path_.c:path.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h
582 @copy /Y nul: headers
583
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -117,10 +117,11 @@
117117
$(SRCDIR)/manifest.c \
118118
$(SRCDIR)/md5.c \
119119
$(SRCDIR)/merge.c \
120120
$(SRCDIR)/merge3.c \
121121
$(SRCDIR)/name.c \
122
+ $(SRCDIR)/path.c \
122123
$(SRCDIR)/pivot.c \
123124
$(SRCDIR)/popen.c \
124125
$(SRCDIR)/pqueue.c \
125126
$(SRCDIR)/printf.c \
126127
$(SRCDIR)/rebuild.c \
@@ -199,10 +200,11 @@
199200
$(OBJDIR)/manifest_.c \
200201
$(OBJDIR)/md5_.c \
201202
$(OBJDIR)/merge_.c \
202203
$(OBJDIR)/merge3_.c \
203204
$(OBJDIR)/name_.c \
205
+ $(OBJDIR)/path_.c \
204206
$(OBJDIR)/pivot_.c \
205207
$(OBJDIR)/popen_.c \
206208
$(OBJDIR)/pqueue_.c \
207209
$(OBJDIR)/printf_.c \
208210
$(OBJDIR)/rebuild_.c \
@@ -281,10 +283,11 @@
281283
$(OBJDIR)/manifest.o \
282284
$(OBJDIR)/md5.o \
283285
$(OBJDIR)/merge.o \
284286
$(OBJDIR)/merge3.o \
285287
$(OBJDIR)/name.o \
288
+ $(OBJDIR)/path.o \
286289
$(OBJDIR)/pivot.o \
287290
$(OBJDIR)/popen.o \
288291
$(OBJDIR)/pqueue.o \
289292
$(OBJDIR)/printf.o \
290293
$(OBJDIR)/rebuild.o \
@@ -382,11 +385,11 @@
382385
383386
384387
$(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex
385388
$(MKINDEX) $(TRANS_SRC) >$@
386389
$(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h
387
- $(MAKEHEADERS) $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h
390
+ $(MAKEHEADERS) $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h
388391
echo Done >$(OBJDIR)/headers
389392
390393
$(OBJDIR)/headers: Makefile
391394
Makefile:
392395
$(OBJDIR)/add_.c: $(SRCDIR)/add.c $(OBJDIR)/translate
@@ -702,10 +705,17 @@
702705
703706
$(OBJDIR)/name.o: $(OBJDIR)/name_.c $(OBJDIR)/name.h $(SRCDIR)/config.h
704707
$(XTCC) -o $(OBJDIR)/name.o -c $(OBJDIR)/name_.c
705708
706709
name.h: $(OBJDIR)/headers
710
+$(OBJDIR)/path_.c: $(SRCDIR)/path.c $(OBJDIR)/translate
711
+ $(TRANSLATE) $(SRCDIR)/path.c >$(OBJDIR)/path_.c
712
+
713
+$(OBJDIR)/path.o: $(OBJDIR)/path_.c $(OBJDIR)/path.h $(SRCDIR)/config.h
714
+ $(XTCC) -o $(OBJDIR)/path.o -c $(OBJDIR)/path_.c
715
+
716
+path.h: $(OBJDIR)/headers
707717
$(OBJDIR)/pivot_.c: $(SRCDIR)/pivot.c $(OBJDIR)/translate
708718
$(TRANSLATE) $(SRCDIR)/pivot.c >$(OBJDIR)/pivot_.c
709719
710720
$(OBJDIR)/pivot.o: $(OBJDIR)/pivot_.c $(OBJDIR)/pivot.h $(SRCDIR)/config.h
711721
$(XTCC) -o $(OBJDIR)/pivot.o -c $(OBJDIR)/pivot_.c
712722
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -117,10 +117,11 @@
117 $(SRCDIR)/manifest.c \
118 $(SRCDIR)/md5.c \
119 $(SRCDIR)/merge.c \
120 $(SRCDIR)/merge3.c \
121 $(SRCDIR)/name.c \
 
122 $(SRCDIR)/pivot.c \
123 $(SRCDIR)/popen.c \
124 $(SRCDIR)/pqueue.c \
125 $(SRCDIR)/printf.c \
126 $(SRCDIR)/rebuild.c \
@@ -199,10 +200,11 @@
199 $(OBJDIR)/manifest_.c \
200 $(OBJDIR)/md5_.c \
201 $(OBJDIR)/merge_.c \
202 $(OBJDIR)/merge3_.c \
203 $(OBJDIR)/name_.c \
 
204 $(OBJDIR)/pivot_.c \
205 $(OBJDIR)/popen_.c \
206 $(OBJDIR)/pqueue_.c \
207 $(OBJDIR)/printf_.c \
208 $(OBJDIR)/rebuild_.c \
@@ -281,10 +283,11 @@
281 $(OBJDIR)/manifest.o \
282 $(OBJDIR)/md5.o \
283 $(OBJDIR)/merge.o \
284 $(OBJDIR)/merge3.o \
285 $(OBJDIR)/name.o \
 
286 $(OBJDIR)/pivot.o \
287 $(OBJDIR)/popen.o \
288 $(OBJDIR)/pqueue.o \
289 $(OBJDIR)/printf.o \
290 $(OBJDIR)/rebuild.o \
@@ -382,11 +385,11 @@
382
383
384 $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex
385 $(MKINDEX) $(TRANS_SRC) >$@
386 $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h
387 $(MAKEHEADERS) $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h
388 echo Done >$(OBJDIR)/headers
389
390 $(OBJDIR)/headers: Makefile
391 Makefile:
392 $(OBJDIR)/add_.c: $(SRCDIR)/add.c $(OBJDIR)/translate
@@ -702,10 +705,17 @@
702
703 $(OBJDIR)/name.o: $(OBJDIR)/name_.c $(OBJDIR)/name.h $(SRCDIR)/config.h
704 $(XTCC) -o $(OBJDIR)/name.o -c $(OBJDIR)/name_.c
705
706 name.h: $(OBJDIR)/headers
 
 
 
 
 
 
 
707 $(OBJDIR)/pivot_.c: $(SRCDIR)/pivot.c $(OBJDIR)/translate
708 $(TRANSLATE) $(SRCDIR)/pivot.c >$(OBJDIR)/pivot_.c
709
710 $(OBJDIR)/pivot.o: $(OBJDIR)/pivot_.c $(OBJDIR)/pivot.h $(SRCDIR)/config.h
711 $(XTCC) -o $(OBJDIR)/pivot.o -c $(OBJDIR)/pivot_.c
712
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -117,10 +117,11 @@
117 $(SRCDIR)/manifest.c \
118 $(SRCDIR)/md5.c \
119 $(SRCDIR)/merge.c \
120 $(SRCDIR)/merge3.c \
121 $(SRCDIR)/name.c \
122 $(SRCDIR)/path.c \
123 $(SRCDIR)/pivot.c \
124 $(SRCDIR)/popen.c \
125 $(SRCDIR)/pqueue.c \
126 $(SRCDIR)/printf.c \
127 $(SRCDIR)/rebuild.c \
@@ -199,10 +200,11 @@
200 $(OBJDIR)/manifest_.c \
201 $(OBJDIR)/md5_.c \
202 $(OBJDIR)/merge_.c \
203 $(OBJDIR)/merge3_.c \
204 $(OBJDIR)/name_.c \
205 $(OBJDIR)/path_.c \
206 $(OBJDIR)/pivot_.c \
207 $(OBJDIR)/popen_.c \
208 $(OBJDIR)/pqueue_.c \
209 $(OBJDIR)/printf_.c \
210 $(OBJDIR)/rebuild_.c \
@@ -281,10 +283,11 @@
283 $(OBJDIR)/manifest.o \
284 $(OBJDIR)/md5.o \
285 $(OBJDIR)/merge.o \
286 $(OBJDIR)/merge3.o \
287 $(OBJDIR)/name.o \
288 $(OBJDIR)/path.o \
289 $(OBJDIR)/pivot.o \
290 $(OBJDIR)/popen.o \
291 $(OBJDIR)/pqueue.o \
292 $(OBJDIR)/printf.o \
293 $(OBJDIR)/rebuild.o \
@@ -382,11 +385,11 @@
385
386
387 $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex
388 $(MKINDEX) $(TRANS_SRC) >$@
389 $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h
390 $(MAKEHEADERS) $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h
391 echo Done >$(OBJDIR)/headers
392
393 $(OBJDIR)/headers: Makefile
394 Makefile:
395 $(OBJDIR)/add_.c: $(SRCDIR)/add.c $(OBJDIR)/translate
@@ -702,10 +705,17 @@
705
706 $(OBJDIR)/name.o: $(OBJDIR)/name_.c $(OBJDIR)/name.h $(SRCDIR)/config.h
707 $(XTCC) -o $(OBJDIR)/name.o -c $(OBJDIR)/name_.c
708
709 name.h: $(OBJDIR)/headers
710 $(OBJDIR)/path_.c: $(SRCDIR)/path.c $(OBJDIR)/translate
711 $(TRANSLATE) $(SRCDIR)/path.c >$(OBJDIR)/path_.c
712
713 $(OBJDIR)/path.o: $(OBJDIR)/path_.c $(OBJDIR)/path.h $(SRCDIR)/config.h
714 $(XTCC) -o $(OBJDIR)/path.o -c $(OBJDIR)/path_.c
715
716 path.h: $(OBJDIR)/headers
717 $(OBJDIR)/pivot_.c: $(SRCDIR)/pivot.c $(OBJDIR)/translate
718 $(TRANSLATE) $(SRCDIR)/pivot.c >$(OBJDIR)/pivot_.c
719
720 $(OBJDIR)/pivot.o: $(OBJDIR)/pivot_.c $(OBJDIR)/pivot.h $(SRCDIR)/config.h
721 $(XTCC) -o $(OBJDIR)/pivot.o -c $(OBJDIR)/pivot_.c
722
+10 -4
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -38,13 +38,13 @@
3838
LIBS = $(ZLIB) ws2_32.lib $(SSLLIB)
3939
LIBDIR = -LIBPATH:$(MSCDIR)\extra\lib -LIBPATH:$(ZLIBDIR)
4040
4141
SQLITE_OPTIONS = /DSQLITE_OMIT_LOAD_EXTENSION=1 /DSQLITE_THREADSAFE=0 /DSQLITE_DEFAULT_FILE_FORMAT=4 /DSQLITE_ENABLE_STAT2 /Dlocaltime=fossil_localtime /DSQLITE_ENABLE_LOCKING_STYLE=0
4242
43
-SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c leaf_.c login_.c main_.c manifest_.c md5_.c merge_.c merge3_.c name_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c sqlcmd_.c stash_.c stat_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c update_.c url_.c user_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c xfer_.c zip_.c
43
+SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c leaf_.c login_.c main_.c manifest_.c md5_.c merge_.c merge3_.c name_.c path_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c sqlcmd_.c stash_.c stat_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c update_.c url_.c user_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c xfer_.c zip_.c
4444
45
-OBJ = $(OX)\add$O $(OX)\allrepo$O $(OX)\attach$O $(OX)\bag$O $(OX)\bisect$O $(OX)\blob$O $(OX)\branch$O $(OX)\browse$O $(OX)\captcha$O $(OX)\cgi$O $(OX)\checkin$O $(OX)\checkout$O $(OX)\clearsign$O $(OX)\clone$O $(OX)\comformat$O $(OX)\configure$O $(OX)\content$O $(OX)\db$O $(OX)\delta$O $(OX)\deltacmd$O $(OX)\descendants$O $(OX)\diff$O $(OX)\diffcmd$O $(OX)\doc$O $(OX)\encode$O $(OX)\event$O $(OX)\export$O $(OX)\file$O $(OX)\finfo$O $(OX)\graph$O $(OX)\gzip$O $(OX)\http$O $(OX)\http_socket$O $(OX)\http_ssl$O $(OX)\http_transport$O $(OX)\import$O $(OX)\info$O $(OX)\leaf$O $(OX)\login$O $(OX)\main$O $(OX)\manifest$O $(OX)\md5$O $(OX)\merge$O $(OX)\merge3$O $(OX)\name$O $(OX)\pivot$O $(OX)\popen$O $(OX)\pqueue$O $(OX)\printf$O $(OX)\rebuild$O $(OX)\report$O $(OX)\rss$O $(OX)\schema$O $(OX)\search$O $(OX)\setup$O $(OX)\sha1$O $(OX)\shun$O $(OX)\skins$O $(OX)\sqlcmd$O $(OX)\stash$O $(OX)\stat$O $(OX)\style$O $(OX)\sync$O $(OX)\tag$O $(OX)\tar$O $(OX)\th_main$O $(OX)\timeline$O $(OX)\tkt$O $(OX)\tktsetup$O $(OX)\undo$O $(OX)\update$O $(OX)\url$O $(OX)\user$O $(OX)\verify$O $(OX)\vfile$O $(OX)\wiki$O $(OX)\wikiformat$O $(OX)\winhttp$O $(OX)\xfer$O $(OX)\zip$O $(OX)\shell$O $(OX)\sqlite3$O $(OX)\th$O $(OX)\th_lang$O
45
+OBJ = $(OX)\add$O $(OX)\allrepo$O $(OX)\attach$O $(OX)\bag$O $(OX)\bisect$O $(OX)\blob$O $(OX)\branch$O $(OX)\browse$O $(OX)\captcha$O $(OX)\cgi$O $(OX)\checkin$O $(OX)\checkout$O $(OX)\clearsign$O $(OX)\clone$O $(OX)\comformat$O $(OX)\configure$O $(OX)\content$O $(OX)\db$O $(OX)\delta$O $(OX)\deltacmd$O $(OX)\descendants$O $(OX)\diff$O $(OX)\diffcmd$O $(OX)\doc$O $(OX)\encode$O $(OX)\event$O $(OX)\export$O $(OX)\file$O $(OX)\finfo$O $(OX)\graph$O $(OX)\gzip$O $(OX)\http$O $(OX)\http_socket$O $(OX)\http_ssl$O $(OX)\http_transport$O $(OX)\import$O $(OX)\info$O $(OX)\leaf$O $(OX)\login$O $(OX)\main$O $(OX)\manifest$O $(OX)\md5$O $(OX)\merge$O $(OX)\merge3$O $(OX)\name$O $(OX)\path$O $(OX)\pivot$O $(OX)\popen$O $(OX)\pqueue$O $(OX)\printf$O $(OX)\rebuild$O $(OX)\report$O $(OX)\rss$O $(OX)\schema$O $(OX)\search$O $(OX)\setup$O $(OX)\sha1$O $(OX)\shun$O $(OX)\skins$O $(OX)\sqlcmd$O $(OX)\stash$O $(OX)\stat$O $(OX)\style$O $(OX)\sync$O $(OX)\tag$O $(OX)\tar$O $(OX)\th_main$O $(OX)\timeline$O $(OX)\tkt$O $(OX)\tktsetup$O $(OX)\undo$O $(OX)\update$O $(OX)\url$O $(OX)\user$O $(OX)\verify$O $(OX)\vfile$O $(OX)\wiki$O $(OX)\wikiformat$O $(OX)\winhttp$O $(OX)\xfer$O $(OX)\zip$O $(OX)\shell$O $(OX)\sqlite3$O $(OX)\th$O $(OX)\th_lang$O
4646
4747
4848
APPNAME = $(OX)\fossil$(E)
4949
5050
all: $(OX) $(APPNAME)
@@ -52,11 +52,11 @@
5252
$(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OX)\linkopts
5353
cd $(OX)
5454
link -LINK -OUT:$@ $(LIBDIR) @linkopts
5555
5656
$(OX)\linkopts: $B\win\Makefile.msc
57
- echo add allrepo attach bag bisect blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo graph gzip http http_socket http_ssl http_transport import info leaf login main manifest md5 merge merge3 name pivot popen pqueue printf rebuild report rss schema search setup sha1 shun skins sqlcmd stash stat style sync tag tar th_main timeline tkt tktsetup undo update url user verify vfile wiki wikiformat winhttp xfer zip sqlite3 th th_lang > $@
57
+ echo add allrepo attach bag bisect blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo graph gzip http http_socket http_ssl http_transport import info leaf login main manifest md5 merge merge3 name path pivot popen pqueue printf rebuild report rss schema search setup sha1 shun skins sqlcmd stash stat style sync tag tar th_main timeline tkt tktsetup undo update url user verify vfile wiki wikiformat winhttp xfer zip sqlite3 th th_lang > $@
5858
echo $(LIBS) >> $@
5959
6060
6161
6262
@@ -369,10 +369,16 @@
369369
$(OX)\name$O : name_.c name.h
370370
$(TCC) /Fo$@ -c name_.c
371371
372372
name_.c : $(SRCDIR)\name.c
373373
translate$E $** > $@
374
+
375
+$(OX)\path$O : path_.c path.h
376
+ $(TCC) /Fo$@ -c path_.c
377
+
378
+path_.c : $(SRCDIR)\path.c
379
+ translate$E $** > $@
374380
375381
$(OX)\pivot$O : pivot_.c pivot.h
376382
$(TCC) /Fo$@ -c pivot_.c
377383
378384
pivot_.c : $(SRCDIR)\pivot.c
@@ -581,7 +587,7 @@
581587
582588
zip_.c : $(SRCDIR)\zip.c
583589
translate$E $** > $@
584590
585591
headers: makeheaders$E page_index.h VERSION.h
586
- makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h graph_.c:graph.h gzip_.c:gzip.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h leaf_.c:leaf.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h
592
+ makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h graph_.c:graph.h gzip_.c:gzip.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h leaf_.c:leaf.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h path_.c:path.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h
587593
@copy /Y nul: headers
588594
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -38,13 +38,13 @@
38 LIBS = $(ZLIB) ws2_32.lib $(SSLLIB)
39 LIBDIR = -LIBPATH:$(MSCDIR)\extra\lib -LIBPATH:$(ZLIBDIR)
40
41 SQLITE_OPTIONS = /DSQLITE_OMIT_LOAD_EXTENSION=1 /DSQLITE_THREADSAFE=0 /DSQLITE_DEFAULT_FILE_FORMAT=4 /DSQLITE_ENABLE_STAT2 /Dlocaltime=fossil_localtime /DSQLITE_ENABLE_LOCKING_STYLE=0
42
43 SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c leaf_.c login_.c main_.c manifest_.c md5_.c merge_.c merge3_.c name_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c sqlcmd_.c stash_.c stat_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c update_.c url_.c user_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c xfer_.c zip_.c
44
45 OBJ = $(OX)\add$O $(OX)\allrepo$O $(OX)\attach$O $(OX)\bag$O $(OX)\bisect$O $(OX)\blob$O $(OX)\branch$O $(OX)\browse$O $(OX)\captcha$O $(OX)\cgi$O $(OX)\checkin$O $(OX)\checkout$O $(OX)\clearsign$O $(OX)\clone$O $(OX)\comformat$O $(OX)\configure$O $(OX)\content$O $(OX)\db$O $(OX)\delta$O $(OX)\deltacmd$O $(OX)\descendants$O $(OX)\diff$O $(OX)\diffcmd$O $(OX)\doc$O $(OX)\encode$O $(OX)\event$O $(OX)\export$O $(OX)\file$O $(OX)\finfo$O $(OX)\graph$O $(OX)\gzip$O $(OX)\http$O $(OX)\http_socket$O $(OX)\http_ssl$O $(OX)\http_transport$O $(OX)\import$O $(OX)\info$O $(OX)\leaf$O $(OX)\login$O $(OX)\main$O $(OX)\manifest$O $(OX)\md5$O $(OX)\merge$O $(OX)\merge3$O $(OX)\name$O $(OX)\pivot$O $(OX)\popen$O $(OX)\pqueue$O $(OX)\printf$O $(OX)\rebuild$O $(OX)\report$O $(OX)\rss$O $(OX)\schema$O $(OX)\search$O $(OX)\setup$O $(OX)\sha1$O $(OX)\shun$O $(OX)\skins$O $(OX)\sqlcmd$O $(OX)\stash$O $(OX)\stat$O $(OX)\style$O $(OX)\sync$O $(OX)\tag$O $(OX)\tar$O $(OX)\th_main$O $(OX)\timeline$O $(OX)\tkt$O $(OX)\tktsetup$O $(OX)\undo$O $(OX)\update$O $(OX)\url$O $(OX)\user$O $(OX)\verify$O $(OX)\vfile$O $(OX)\wiki$O $(OX)\wikiformat$O $(OX)\winhttp$O $(OX)\xfer$O $(OX)\zip$O $(OX)\shell$O $(OX)\sqlite3$O $(OX)\th$O $(OX)\th_lang$O
46
47
48 APPNAME = $(OX)\fossil$(E)
49
50 all: $(OX) $(APPNAME)
@@ -52,11 +52,11 @@
52 $(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OX)\linkopts
53 cd $(OX)
54 link -LINK -OUT:$@ $(LIBDIR) @linkopts
55
56 $(OX)\linkopts: $B\win\Makefile.msc
57 echo add allrepo attach bag bisect blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo graph gzip http http_socket http_ssl http_transport import info leaf login main manifest md5 merge merge3 name pivot popen pqueue printf rebuild report rss schema search setup sha1 shun skins sqlcmd stash stat style sync tag tar th_main timeline tkt tktsetup undo update url user verify vfile wiki wikiformat winhttp xfer zip sqlite3 th th_lang > $@
58 echo $(LIBS) >> $@
59
60
61
62
@@ -369,10 +369,16 @@
369 $(OX)\name$O : name_.c name.h
370 $(TCC) /Fo$@ -c name_.c
371
372 name_.c : $(SRCDIR)\name.c
373 translate$E $** > $@
 
 
 
 
 
 
374
375 $(OX)\pivot$O : pivot_.c pivot.h
376 $(TCC) /Fo$@ -c pivot_.c
377
378 pivot_.c : $(SRCDIR)\pivot.c
@@ -581,7 +587,7 @@
581
582 zip_.c : $(SRCDIR)\zip.c
583 translate$E $** > $@
584
585 headers: makeheaders$E page_index.h VERSION.h
586 makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h graph_.c:graph.h gzip_.c:gzip.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h leaf_.c:leaf.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h
587 @copy /Y nul: headers
588
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -38,13 +38,13 @@
38 LIBS = $(ZLIB) ws2_32.lib $(SSLLIB)
39 LIBDIR = -LIBPATH:$(MSCDIR)\extra\lib -LIBPATH:$(ZLIBDIR)
40
41 SQLITE_OPTIONS = /DSQLITE_OMIT_LOAD_EXTENSION=1 /DSQLITE_THREADSAFE=0 /DSQLITE_DEFAULT_FILE_FORMAT=4 /DSQLITE_ENABLE_STAT2 /Dlocaltime=fossil_localtime /DSQLITE_ENABLE_LOCKING_STYLE=0
42
43 SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c leaf_.c login_.c main_.c manifest_.c md5_.c merge_.c merge3_.c name_.c path_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c sqlcmd_.c stash_.c stat_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c update_.c url_.c user_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c xfer_.c zip_.c
44
45 OBJ = $(OX)\add$O $(OX)\allrepo$O $(OX)\attach$O $(OX)\bag$O $(OX)\bisect$O $(OX)\blob$O $(OX)\branch$O $(OX)\browse$O $(OX)\captcha$O $(OX)\cgi$O $(OX)\checkin$O $(OX)\checkout$O $(OX)\clearsign$O $(OX)\clone$O $(OX)\comformat$O $(OX)\configure$O $(OX)\content$O $(OX)\db$O $(OX)\delta$O $(OX)\deltacmd$O $(OX)\descendants$O $(OX)\diff$O $(OX)\diffcmd$O $(OX)\doc$O $(OX)\encode$O $(OX)\event$O $(OX)\export$O $(OX)\file$O $(OX)\finfo$O $(OX)\graph$O $(OX)\gzip$O $(OX)\http$O $(OX)\http_socket$O $(OX)\http_ssl$O $(OX)\http_transport$O $(OX)\import$O $(OX)\info$O $(OX)\leaf$O $(OX)\login$O $(OX)\main$O $(OX)\manifest$O $(OX)\md5$O $(OX)\merge$O $(OX)\merge3$O $(OX)\name$O $(OX)\path$O $(OX)\pivot$O $(OX)\popen$O $(OX)\pqueue$O $(OX)\printf$O $(OX)\rebuild$O $(OX)\report$O $(OX)\rss$O $(OX)\schema$O $(OX)\search$O $(OX)\setup$O $(OX)\sha1$O $(OX)\shun$O $(OX)\skins$O $(OX)\sqlcmd$O $(OX)\stash$O $(OX)\stat$O $(OX)\style$O $(OX)\sync$O $(OX)\tag$O $(OX)\tar$O $(OX)\th_main$O $(OX)\timeline$O $(OX)\tkt$O $(OX)\tktsetup$O $(OX)\undo$O $(OX)\update$O $(OX)\url$O $(OX)\user$O $(OX)\verify$O $(OX)\vfile$O $(OX)\wiki$O $(OX)\wikiformat$O $(OX)\winhttp$O $(OX)\xfer$O $(OX)\zip$O $(OX)\shell$O $(OX)\sqlite3$O $(OX)\th$O $(OX)\th_lang$O
46
47
48 APPNAME = $(OX)\fossil$(E)
49
50 all: $(OX) $(APPNAME)
@@ -52,11 +52,11 @@
52 $(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OX)\linkopts
53 cd $(OX)
54 link -LINK -OUT:$@ $(LIBDIR) @linkopts
55
56 $(OX)\linkopts: $B\win\Makefile.msc
57 echo add allrepo attach bag bisect blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo graph gzip http http_socket http_ssl http_transport import info leaf login main manifest md5 merge merge3 name path pivot popen pqueue printf rebuild report rss schema search setup sha1 shun skins sqlcmd stash stat style sync tag tar th_main timeline tkt tktsetup undo update url user verify vfile wiki wikiformat winhttp xfer zip sqlite3 th th_lang > $@
58 echo $(LIBS) >> $@
59
60
61
62
@@ -369,10 +369,16 @@
369 $(OX)\name$O : name_.c name.h
370 $(TCC) /Fo$@ -c name_.c
371
372 name_.c : $(SRCDIR)\name.c
373 translate$E $** > $@
374
375 $(OX)\path$O : path_.c path.h
376 $(TCC) /Fo$@ -c path_.c
377
378 path_.c : $(SRCDIR)\path.c
379 translate$E $** > $@
380
381 $(OX)\pivot$O : pivot_.c pivot.h
382 $(TCC) /Fo$@ -c pivot_.c
383
384 pivot_.c : $(SRCDIR)\pivot.c
@@ -581,7 +587,7 @@
587
588 zip_.c : $(SRCDIR)\zip.c
589 translate$E $** > $@
590
591 headers: makeheaders$E page_index.h VERSION.h
592 makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h graph_.c:graph.h gzip_.c:gzip.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h leaf_.c:leaf.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h path_.c:path.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h
593 @copy /Y nul: headers
594
+3 -3
--- www/faq.tcl
+++ www/faq.tcl
@@ -128,13 +128,13 @@
128128
faq {
129129
How do I make a clone of the fossil self-hosting repository?
130130
} {
131131
Any of the following commands should work:
132132
<blockquote><pre>
133
- fossil [/help/clone|clone] http://www.fossil-scm.org/ fossil.fossil<br>
134
- fossil [/help/clone|clone] http://www2.fossil-scm.org/ fossil.fossil<br>
135
- fossil [/help/clone|clone] http://www3.fossli-scm.org/site.cgi fossil.fossil
133
+ fossil [/help/clone|clone] http://www.fossil-scm.org/ fossil.fossil
134
+ fossil [/help/clone|clone] http://www2.fossil-scm.org/ fossil.fossil
135
+ fossil [/help/clone|clone] http://www3.fossil-scm.org/site.cgi fossil.fossil
136136
</pre></blockquote>
137137
Once you have the repository cloned, you can open a local check-out
138138
as follows:
139139
<blockquote><pre>
140140
mkdir src; cd src; fossil [/help/open|open] ../fossil.fossil
141141
--- www/faq.tcl
+++ www/faq.tcl
@@ -128,13 +128,13 @@
128 faq {
129 How do I make a clone of the fossil self-hosting repository?
130 } {
131 Any of the following commands should work:
132 <blockquote><pre>
133 fossil [/help/clone|clone] http://www.fossil-scm.org/ fossil.fossil<br>
134 fossil [/help/clone|clone] http://www2.fossil-scm.org/ fossil.fossil<br>
135 fossil [/help/clone|clone] http://www3.fossli-scm.org/site.cgi fossil.fossil
136 </pre></blockquote>
137 Once you have the repository cloned, you can open a local check-out
138 as follows:
139 <blockquote><pre>
140 mkdir src; cd src; fossil [/help/open|open] ../fossil.fossil
141
--- www/faq.tcl
+++ www/faq.tcl
@@ -128,13 +128,13 @@
128 faq {
129 How do I make a clone of the fossil self-hosting repository?
130 } {
131 Any of the following commands should work:
132 <blockquote><pre>
133 fossil [/help/clone|clone] http://www.fossil-scm.org/ fossil.fossil
134 fossil [/help/clone|clone] http://www2.fossil-scm.org/ fossil.fossil
135 fossil [/help/clone|clone] http://www3.fossil-scm.org/site.cgi fossil.fossil
136 </pre></blockquote>
137 Once you have the repository cloned, you can open a local check-out
138 as follows:
139 <blockquote><pre>
140 mkdir src; cd src; fossil [/help/open|open] ../fossil.fossil
141
+3 -3
--- www/faq.wiki
+++ www/faq.wiki
@@ -128,13 +128,13 @@
128128
<a name="q7"></a>
129129
<p><b>(7) How do I make a clone of the fossil self-hosting repository?</b></p>
130130
131131
<blockquote>Any of the following commands should work:
132132
<blockquote><pre>
133
-fossil [/help/clone|clone] http://www.fossil-scm.org/ fossil.fossil<br>
134
-fossil [/help/clone|clone] http://www2.fossil-scm.org/ fossil.fossil<br>
135
-fossil [/help/clone|clone] http://www3.fossli-scm.org/site.cgi fossil.fossil
133
+fossil [/help/clone|clone] http://www.fossil-scm.org/ fossil.fossil
134
+fossil [/help/clone|clone] http://www2.fossil-scm.org/ fossil.fossil
135
+fossil [/help/clone|clone] http://www3.fossil-scm.org/site.cgi fossil.fossil
136136
</pre></blockquote>
137137
Once you have the repository cloned, you can open a local check-out
138138
as follows:
139139
<blockquote><pre>
140140
mkdir src; cd src; fossil [/help/open|open] ../fossil.fossil
141141
--- www/faq.wiki
+++ www/faq.wiki
@@ -128,13 +128,13 @@
128 <a name="q7"></a>
129 <p><b>(7) How do I make a clone of the fossil self-hosting repository?</b></p>
130
131 <blockquote>Any of the following commands should work:
132 <blockquote><pre>
133 fossil [/help/clone|clone] http://www.fossil-scm.org/ fossil.fossil<br>
134 fossil [/help/clone|clone] http://www2.fossil-scm.org/ fossil.fossil<br>
135 fossil [/help/clone|clone] http://www3.fossli-scm.org/site.cgi fossil.fossil
136 </pre></blockquote>
137 Once you have the repository cloned, you can open a local check-out
138 as follows:
139 <blockquote><pre>
140 mkdir src; cd src; fossil [/help/open|open] ../fossil.fossil
141
--- www/faq.wiki
+++ www/faq.wiki
@@ -128,13 +128,13 @@
128 <a name="q7"></a>
129 <p><b>(7) How do I make a clone of the fossil self-hosting repository?</b></p>
130
131 <blockquote>Any of the following commands should work:
132 <blockquote><pre>
133 fossil [/help/clone|clone] http://www.fossil-scm.org/ fossil.fossil
134 fossil [/help/clone|clone] http://www2.fossil-scm.org/ fossil.fossil
135 fossil [/help/clone|clone] http://www3.fossil-scm.org/site.cgi fossil.fossil
136 </pre></blockquote>
137 Once you have the repository cloned, you can open a local check-out
138 as follows:
139 <blockquote><pre>
140 mkdir src; cd src; fossil [/help/open|open] ../fossil.fossil
141
--- www/mkdownload.tcl
+++ www/mkdownload.tcl
@@ -22,11 +22,15 @@
2222
<p>
2323
2424
<center><font size=4>
2525
<b>To install Fossil &rarr;</b> download the stand-alone executable
2626
and put it on your $PATH.
27
-</font></center>
27
+</font><p>
28
+RPMs available
29
+<a href="http://download.opensuse.org/repositories/home:/rmax:/fossil/">
30
+here</a>
31
+</center>
2832
2933
<table cellpadding="10">
3034
}
3135
3236
# Find all all unique timestamps.
3337
--- www/mkdownload.tcl
+++ www/mkdownload.tcl
@@ -22,11 +22,15 @@
22 <p>
23
24 <center><font size=4>
25 <b>To install Fossil &rarr;</b> download the stand-alone executable
26 and put it on your $PATH.
27 </font></center>
 
 
 
 
28
29 <table cellpadding="10">
30 }
31
32 # Find all all unique timestamps.
33
--- www/mkdownload.tcl
+++ www/mkdownload.tcl
@@ -22,11 +22,15 @@
22 <p>
23
24 <center><font size=4>
25 <b>To install Fossil &rarr;</b> download the stand-alone executable
26 and put it on your $PATH.
27 </font><p>
28 RPMs available
29 <a href="http://download.opensuse.org/repositories/home:/rmax:/fossil/">
30 here</a>
31 </center>
32
33 <table cellpadding="10">
34 }
35
36 # Find all all unique timestamps.
37

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button