Fossil SCM

Improvements to the Security-Audit page - mostly in providing additional information about the files in the CGI extension folder.

drh 2019-08-04 20:23 trunk
Commit a3bc6552eea4676d3bb55ed5b40ab608570e30b618d9edc3f2f6ce6ae4a77187
+2 -2
--- src/add.c
+++ src/add.c
@@ -328,11 +328,11 @@
328328
329329
file_canonical_name(g.argv[i], &fullName, 0);
330330
zName = blob_str(&fullName);
331331
isDir = file_isdir(zName, RepoFILE);
332332
if( isDir==1 ){
333
- vfile_scan(&fullName, nRoot-1, scanFlags, pClean, pIgnore);
333
+ vfile_scan(&fullName, nRoot-1, scanFlags, pClean, pIgnore, RepoFILE);
334334
}else if( isDir==0 ){
335335
fossil_warning("not found: %s", zName);
336336
}else{
337337
char *zTreeName = &zName[nRoot];
338338
if( !forceFlag && glob_match(pIgnore, zTreeName) ){
@@ -677,11 +677,11 @@
677677
n = strlen(g.zLocalRoot);
678678
blob_init(&path, g.zLocalRoot, n-1);
679679
/* now we read the complete file structure into a temp table */
680680
pClean = glob_create(zCleanFlag);
681681
pIgnore = glob_create(zIgnoreFlag);
682
- vfile_scan(&path, blob_size(&path), scanFlags, pClean, pIgnore);
682
+ vfile_scan(&path, blob_size(&path), scanFlags, pClean, pIgnore, RepoFILE);
683683
glob_free(pIgnore);
684684
glob_free(pClean);
685685
nAdd = add_files_in_sfile(vid);
686686
687687
/* step 2: search for missing files */
688688
--- src/add.c
+++ src/add.c
@@ -328,11 +328,11 @@
328
329 file_canonical_name(g.argv[i], &fullName, 0);
330 zName = blob_str(&fullName);
331 isDir = file_isdir(zName, RepoFILE);
332 if( isDir==1 ){
333 vfile_scan(&fullName, nRoot-1, scanFlags, pClean, pIgnore);
334 }else if( isDir==0 ){
335 fossil_warning("not found: %s", zName);
336 }else{
337 char *zTreeName = &zName[nRoot];
338 if( !forceFlag && glob_match(pIgnore, zTreeName) ){
@@ -677,11 +677,11 @@
677 n = strlen(g.zLocalRoot);
678 blob_init(&path, g.zLocalRoot, n-1);
679 /* now we read the complete file structure into a temp table */
680 pClean = glob_create(zCleanFlag);
681 pIgnore = glob_create(zIgnoreFlag);
682 vfile_scan(&path, blob_size(&path), scanFlags, pClean, pIgnore);
683 glob_free(pIgnore);
684 glob_free(pClean);
685 nAdd = add_files_in_sfile(vid);
686
687 /* step 2: search for missing files */
688
--- src/add.c
+++ src/add.c
@@ -328,11 +328,11 @@
328
329 file_canonical_name(g.argv[i], &fullName, 0);
330 zName = blob_str(&fullName);
331 isDir = file_isdir(zName, RepoFILE);
332 if( isDir==1 ){
333 vfile_scan(&fullName, nRoot-1, scanFlags, pClean, pIgnore, RepoFILE);
334 }else if( isDir==0 ){
335 fossil_warning("not found: %s", zName);
336 }else{
337 char *zTreeName = &zName[nRoot];
338 if( !forceFlag && glob_match(pIgnore, zTreeName) ){
@@ -677,11 +677,11 @@
677 n = strlen(g.zLocalRoot);
678 blob_init(&path, g.zLocalRoot, n-1);
679 /* now we read the complete file structure into a temp table */
680 pClean = glob_create(zCleanFlag);
681 pIgnore = glob_create(zIgnoreFlag);
682 vfile_scan(&path, blob_size(&path), scanFlags, pClean, pIgnore, RepoFILE);
683 glob_free(pIgnore);
684 glob_free(pClean);
685 nAdd = add_files_in_sfile(vid);
686
687 /* step 2: search for missing files */
688
+3 -3
--- src/checkin.c
+++ src/checkin.c
@@ -80,19 +80,19 @@
8080
db_multi_exec("CREATE TEMP TABLE sfile(pathname TEXT PRIMARY KEY %s,"
8181
" mtime INTEGER, size INTEGER)", filename_collation());
8282
nRoot = (int)strlen(g.zLocalRoot);
8383
if( argc==0 ){
8484
blob_init(&name, g.zLocalRoot, nRoot - 1);
85
- vfile_scan(&name, blob_size(&name), scanFlags, pIgnore, 0);
85
+ vfile_scan(&name, blob_size(&name), scanFlags, pIgnore, 0, RepoFILE);
8686
blob_reset(&name);
8787
}else{
8888
for(i=0; i<argc; i++){
8989
file_canonical_name(argv[i], &name, 0);
9090
zName = blob_str(&name);
9191
isDir = file_isdir(zName, RepoFILE);
9292
if( isDir==1 ){
93
- vfile_scan(&name, nRoot-1, scanFlags, pIgnore, 0);
93
+ vfile_scan(&name, nRoot-1, scanFlags, pIgnore, 0, RepoFILE);
9494
}else if( isDir==0 ){
9595
fossil_warning("not found: %s", &zName[nRoot]);
9696
}else if( file_access(zName, R_OK) ){
9797
fossil_fatal("cannot open %s", &zName[nRoot]);
9898
}else{
@@ -1105,11 +1105,11 @@
11051105
Glob *pEmptyDirs = glob_create(db_get("empty-dirs", 0));
11061106
Stmt q;
11071107
Blob root;
11081108
blob_init(&root, g.zLocalRoot, nRoot - 1);
11091109
vfile_dir_scan(&root, blob_size(&root), scanFlags, pIgnore,
1110
- pEmptyDirs);
1110
+ pEmptyDirs, RepoFILE);
11111111
blob_reset(&root);
11121112
db_prepare(&q,
11131113
"SELECT %Q || x FROM dscan_temp"
11141114
" WHERE x NOT IN (%s) AND y = 0"
11151115
" ORDER BY 1 DESC",
11161116
--- src/checkin.c
+++ src/checkin.c
@@ -80,19 +80,19 @@
80 db_multi_exec("CREATE TEMP TABLE sfile(pathname TEXT PRIMARY KEY %s,"
81 " mtime INTEGER, size INTEGER)", filename_collation());
82 nRoot = (int)strlen(g.zLocalRoot);
83 if( argc==0 ){
84 blob_init(&name, g.zLocalRoot, nRoot - 1);
85 vfile_scan(&name, blob_size(&name), scanFlags, pIgnore, 0);
86 blob_reset(&name);
87 }else{
88 for(i=0; i<argc; i++){
89 file_canonical_name(argv[i], &name, 0);
90 zName = blob_str(&name);
91 isDir = file_isdir(zName, RepoFILE);
92 if( isDir==1 ){
93 vfile_scan(&name, nRoot-1, scanFlags, pIgnore, 0);
94 }else if( isDir==0 ){
95 fossil_warning("not found: %s", &zName[nRoot]);
96 }else if( file_access(zName, R_OK) ){
97 fossil_fatal("cannot open %s", &zName[nRoot]);
98 }else{
@@ -1105,11 +1105,11 @@
1105 Glob *pEmptyDirs = glob_create(db_get("empty-dirs", 0));
1106 Stmt q;
1107 Blob root;
1108 blob_init(&root, g.zLocalRoot, nRoot - 1);
1109 vfile_dir_scan(&root, blob_size(&root), scanFlags, pIgnore,
1110 pEmptyDirs);
1111 blob_reset(&root);
1112 db_prepare(&q,
1113 "SELECT %Q || x FROM dscan_temp"
1114 " WHERE x NOT IN (%s) AND y = 0"
1115 " ORDER BY 1 DESC",
1116
--- src/checkin.c
+++ src/checkin.c
@@ -80,19 +80,19 @@
80 db_multi_exec("CREATE TEMP TABLE sfile(pathname TEXT PRIMARY KEY %s,"
81 " mtime INTEGER, size INTEGER)", filename_collation());
82 nRoot = (int)strlen(g.zLocalRoot);
83 if( argc==0 ){
84 blob_init(&name, g.zLocalRoot, nRoot - 1);
85 vfile_scan(&name, blob_size(&name), scanFlags, pIgnore, 0, RepoFILE);
86 blob_reset(&name);
87 }else{
88 for(i=0; i<argc; i++){
89 file_canonical_name(argv[i], &name, 0);
90 zName = blob_str(&name);
91 isDir = file_isdir(zName, RepoFILE);
92 if( isDir==1 ){
93 vfile_scan(&name, nRoot-1, scanFlags, pIgnore, 0, RepoFILE);
94 }else if( isDir==0 ){
95 fossil_warning("not found: %s", &zName[nRoot]);
96 }else if( file_access(zName, R_OK) ){
97 fossil_fatal("cannot open %s", &zName[nRoot]);
98 }else{
@@ -1105,11 +1105,11 @@
1105 Glob *pEmptyDirs = glob_create(db_get("empty-dirs", 0));
1106 Stmt q;
1107 Blob root;
1108 blob_init(&root, g.zLocalRoot, nRoot - 1);
1109 vfile_dir_scan(&root, blob_size(&root), scanFlags, pIgnore,
1110 pEmptyDirs, RepoFILE);
1111 blob_reset(&root);
1112 db_prepare(&q,
1113 "SELECT %Q || x FROM dscan_temp"
1114 " WHERE x NOT IN (%s) AND y = 0"
1115 " ORDER BY 1 DESC",
1116
+92 -11
--- src/extcgi.c
+++ src/extcgi.c
@@ -74,10 +74,33 @@
7474
"SCRIPT_NAME",
7575
"SERVER_NAME",
7676
"SERVER_PORT",
7777
"SERVER_PROTOCOL",
7878
};
79
+
80
+/*
81
+** Check a pathname to determine if it is acceptable for use as
82
+** extension CGI. Some pathnames are excluded for security reasons.
83
+** Return NULL on success or a static error string if there is
84
+** a failure.
85
+*/
86
+const char *ext_pathname_ok(const char *zName){
87
+ int i;
88
+ const char *zFailReason = 0;
89
+ for(i=0; zName[i]; i++){
90
+ char c = zName[i];
91
+ if( (c=='.' || c=='-') && (i==0 || zName[i-1]=='/') ){
92
+ zFailReason = "path element begins with '.' or '-'";
93
+ break;
94
+ }
95
+ if( !fossil_isalnum(c) && c!='_' && c!='-' && c!='.' && c!='/' ){
96
+ zFailReason = "illegal character in path";
97
+ break;
98
+ }
99
+ }
100
+ return zFailReason;
101
+}
79102
80103
/*
81104
** WEBPAGE: ext raw-content
82105
**
83106
** Relay an HTTP request to secondary CGI after first checking the
@@ -131,21 +154,13 @@
131154
}
132155
if( zName==0 ){
133156
zFailReason = "no path beyond /ext";
134157
goto ext_not_found;
135158
}
136
- for(i=0; zName[i]; i++){
137
- char c = zName[i];
138
- if( (c=='.' || c=='-') && (i==0 || zName[i-1]=='/') ){
139
- zFailReason = "path element begins with '.' or '-'";
140
- goto ext_not_found;
141
- }
142
- if( !fossil_isalnum(c) && c!='_' && c!='-' && c!='.' && c!='/' ){
143
- zFailReason = "illegal character in path";
144
- goto ext_not_found;
145
- }
146
- }
159
+ zFailReason = ext_pathname_ok(zName);
160
+ if( zFailReason ) goto ext_not_found;
161
+ zFailReason = "???";
147162
if( file_isdir(g.zExtRoot,ExtFILE)!=1 ){
148163
zFailReason = "extroot is not a directory";
149164
goto ext_not_found;
150165
}
151166
zPath = mprintf("%s/%s", g.zExtRoot, zName);
@@ -297,5 +312,71 @@
297312
@ <p>Reason for failure: %h(zFailReason)</p>
298313
}
299314
}
300315
return;
301316
}
317
+
318
+/*
319
+** Create a temporary SFILE table and fill it with one entry for each file
320
+** in the extension document root directory (g.zExtRoot). The SFILE table
321
+** looks like this:
322
+**
323
+** CREATE TEMP TABLE sfile(
324
+** pathname TEXT PRIMARY KEY,
325
+** isexe BOOLEAN
326
+** ) WITHOUT ROWID;
327
+*/
328
+void ext_files(void){
329
+ Blob base;
330
+ db_multi_exec(
331
+ "CREATE TEMP TABLE sfile(\n"
332
+ " pathname TEXT PRIMARY KEY,\n"
333
+ " isexe BOOLEAN\n"
334
+ ") WITHOUT ROWID;"
335
+ );
336
+ blob_init(&base, g.zExtRoot, -1);
337
+ vfile_scan(&base, blob_size(&base),
338
+ SCAN_ALL|SCAN_ISEXE,
339
+ 0, 0, ExtFILE);
340
+ blob_zero(&base);
341
+}
342
+
343
+/*
344
+** WEBPAGE: extfilelist
345
+**
346
+** List all files in the extension CGI document root and its subfolders.
347
+*/
348
+void ext_filelist_page(void){
349
+ Stmt q;
350
+ login_check_credentials();
351
+ if( !g.perm.Admin ){
352
+ login_needed(0);
353
+ return;
354
+ }
355
+ ext_files();
356
+ style_header("CGI Extension Filelist");
357
+ @ <table border="0" cellspacing="0" cellpadding="3">
358
+ @ <tbody>
359
+ db_prepare(&q, "SELECT pathname, isexe FROM sfile"
360
+ " ORDER BY pathname");
361
+ while( db_step(&q)==SQLITE_ROW ){
362
+ const char *zName = db_column_text(&q,0);
363
+ int isExe = db_column_int(&q,1);
364
+ @ <tr>
365
+ if( ext_pathname_ok(zName)!=0 ){
366
+ @ <td><span style="opacity:0.5;">%h(zName)</span></td>
367
+ @ <td>data file</td>
368
+ }else{
369
+ @ <td><a href="%R/ext/%h(zName)">%h(zName)</a></td>
370
+ if( isExe ){
371
+ @ <td>CGI</td>
372
+ }else{
373
+ @ <td>static content</td>
374
+ }
375
+ }
376
+ @ </tr>
377
+ }
378
+ db_finalize(&q);
379
+ @ </tbody>
380
+ @ </table>
381
+ style_footer();
382
+}
302383
--- src/extcgi.c
+++ src/extcgi.c
@@ -74,10 +74,33 @@
74 "SCRIPT_NAME",
75 "SERVER_NAME",
76 "SERVER_PORT",
77 "SERVER_PROTOCOL",
78 };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
80 /*
81 ** WEBPAGE: ext raw-content
82 **
83 ** Relay an HTTP request to secondary CGI after first checking the
@@ -131,21 +154,13 @@
131 }
132 if( zName==0 ){
133 zFailReason = "no path beyond /ext";
134 goto ext_not_found;
135 }
136 for(i=0; zName[i]; i++){
137 char c = zName[i];
138 if( (c=='.' || c=='-') && (i==0 || zName[i-1]=='/') ){
139 zFailReason = "path element begins with '.' or '-'";
140 goto ext_not_found;
141 }
142 if( !fossil_isalnum(c) && c!='_' && c!='-' && c!='.' && c!='/' ){
143 zFailReason = "illegal character in path";
144 goto ext_not_found;
145 }
146 }
147 if( file_isdir(g.zExtRoot,ExtFILE)!=1 ){
148 zFailReason = "extroot is not a directory";
149 goto ext_not_found;
150 }
151 zPath = mprintf("%s/%s", g.zExtRoot, zName);
@@ -297,5 +312,71 @@
297 @ <p>Reason for failure: %h(zFailReason)</p>
298 }
299 }
300 return;
301 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
302
--- src/extcgi.c
+++ src/extcgi.c
@@ -74,10 +74,33 @@
74 "SCRIPT_NAME",
75 "SERVER_NAME",
76 "SERVER_PORT",
77 "SERVER_PROTOCOL",
78 };
79
80 /*
81 ** Check a pathname to determine if it is acceptable for use as
82 ** extension CGI. Some pathnames are excluded for security reasons.
83 ** Return NULL on success or a static error string if there is
84 ** a failure.
85 */
86 const char *ext_pathname_ok(const char *zName){
87 int i;
88 const char *zFailReason = 0;
89 for(i=0; zName[i]; i++){
90 char c = zName[i];
91 if( (c=='.' || c=='-') && (i==0 || zName[i-1]=='/') ){
92 zFailReason = "path element begins with '.' or '-'";
93 break;
94 }
95 if( !fossil_isalnum(c) && c!='_' && c!='-' && c!='.' && c!='/' ){
96 zFailReason = "illegal character in path";
97 break;
98 }
99 }
100 return zFailReason;
101 }
102
103 /*
104 ** WEBPAGE: ext raw-content
105 **
106 ** Relay an HTTP request to secondary CGI after first checking the
@@ -131,21 +154,13 @@
154 }
155 if( zName==0 ){
156 zFailReason = "no path beyond /ext";
157 goto ext_not_found;
158 }
159 zFailReason = ext_pathname_ok(zName);
160 if( zFailReason ) goto ext_not_found;
161 zFailReason = "???";
 
 
 
 
 
 
 
 
162 if( file_isdir(g.zExtRoot,ExtFILE)!=1 ){
163 zFailReason = "extroot is not a directory";
164 goto ext_not_found;
165 }
166 zPath = mprintf("%s/%s", g.zExtRoot, zName);
@@ -297,5 +312,71 @@
312 @ <p>Reason for failure: %h(zFailReason)</p>
313 }
314 }
315 return;
316 }
317
318 /*
319 ** Create a temporary SFILE table and fill it with one entry for each file
320 ** in the extension document root directory (g.zExtRoot). The SFILE table
321 ** looks like this:
322 **
323 ** CREATE TEMP TABLE sfile(
324 ** pathname TEXT PRIMARY KEY,
325 ** isexe BOOLEAN
326 ** ) WITHOUT ROWID;
327 */
328 void ext_files(void){
329 Blob base;
330 db_multi_exec(
331 "CREATE TEMP TABLE sfile(\n"
332 " pathname TEXT PRIMARY KEY,\n"
333 " isexe BOOLEAN\n"
334 ") WITHOUT ROWID;"
335 );
336 blob_init(&base, g.zExtRoot, -1);
337 vfile_scan(&base, blob_size(&base),
338 SCAN_ALL|SCAN_ISEXE,
339 0, 0, ExtFILE);
340 blob_zero(&base);
341 }
342
343 /*
344 ** WEBPAGE: extfilelist
345 **
346 ** List all files in the extension CGI document root and its subfolders.
347 */
348 void ext_filelist_page(void){
349 Stmt q;
350 login_check_credentials();
351 if( !g.perm.Admin ){
352 login_needed(0);
353 return;
354 }
355 ext_files();
356 style_header("CGI Extension Filelist");
357 @ <table border="0" cellspacing="0" cellpadding="3">
358 @ <tbody>
359 db_prepare(&q, "SELECT pathname, isexe FROM sfile"
360 " ORDER BY pathname");
361 while( db_step(&q)==SQLITE_ROW ){
362 const char *zName = db_column_text(&q,0);
363 int isExe = db_column_int(&q,1);
364 @ <tr>
365 if( ext_pathname_ok(zName)!=0 ){
366 @ <td><span style="opacity:0.5;">%h(zName)</span></td>
367 @ <td>data file</td>
368 }else{
369 @ <td><a href="%R/ext/%h(zName)">%h(zName)</a></td>
370 if( isExe ){
371 @ <td>CGI</td>
372 }else{
373 @ <td>static content</td>
374 }
375 }
376 @ </tr>
377 }
378 db_finalize(&q);
379 @ </tbody>
380 @ </table>
381 style_footer();
382 }
383
+2
--- src/main.c
+++ src/main.c
@@ -148,10 +148,11 @@
148148
unsigned iRepoDataVers; /* Initial data version for repository database */
149149
char *zRepositoryOption; /* Most recent cached repository option value */
150150
char *zRepositoryName; /* Name of the repository database file */
151151
char *zLocalDbName; /* Name of the local database file */
152152
char *zOpenRevision; /* Check-in version to use during database open */
153
+ char *zCmdName; /* Name of the Fossil command currently running */
153154
int localOpen; /* True if the local database is open */
154155
char *zLocalRoot; /* The directory holding the local database */
155156
int minPrefix; /* Number of digits needed for a distinct UUID */
156157
int eHashPolicy; /* Current hash policy. One of HPOLICY_* */
157158
int fSqlTrace; /* True if --sqltrace flag is present */
@@ -786,10 +787,11 @@
786787
fossil_panic("file descriptor 2 is not open. (fd=%d, errno=%d)",
787788
fd, x);
788789
}
789790
}
790791
#endif
792
+ g.zCmdName = zCmdName;
791793
rc = dispatch_name_search(zCmdName, CMDFLAG_COMMAND|CMDFLAG_PREFIX, &pCmd);
792794
if( rc==1 ){
793795
#ifdef FOSSIL_ENABLE_TH1_HOOKS
794796
if( !g.isHTTP && !g.fNoThHook ){
795797
rc = Th_CommandHook(zCmdName, 0);
796798
--- src/main.c
+++ src/main.c
@@ -148,10 +148,11 @@
148 unsigned iRepoDataVers; /* Initial data version for repository database */
149 char *zRepositoryOption; /* Most recent cached repository option value */
150 char *zRepositoryName; /* Name of the repository database file */
151 char *zLocalDbName; /* Name of the local database file */
152 char *zOpenRevision; /* Check-in version to use during database open */
 
153 int localOpen; /* True if the local database is open */
154 char *zLocalRoot; /* The directory holding the local database */
155 int minPrefix; /* Number of digits needed for a distinct UUID */
156 int eHashPolicy; /* Current hash policy. One of HPOLICY_* */
157 int fSqlTrace; /* True if --sqltrace flag is present */
@@ -786,10 +787,11 @@
786 fossil_panic("file descriptor 2 is not open. (fd=%d, errno=%d)",
787 fd, x);
788 }
789 }
790 #endif
 
791 rc = dispatch_name_search(zCmdName, CMDFLAG_COMMAND|CMDFLAG_PREFIX, &pCmd);
792 if( rc==1 ){
793 #ifdef FOSSIL_ENABLE_TH1_HOOKS
794 if( !g.isHTTP && !g.fNoThHook ){
795 rc = Th_CommandHook(zCmdName, 0);
796
--- src/main.c
+++ src/main.c
@@ -148,10 +148,11 @@
148 unsigned iRepoDataVers; /* Initial data version for repository database */
149 char *zRepositoryOption; /* Most recent cached repository option value */
150 char *zRepositoryName; /* Name of the repository database file */
151 char *zLocalDbName; /* Name of the local database file */
152 char *zOpenRevision; /* Check-in version to use during database open */
153 char *zCmdName; /* Name of the Fossil command currently running */
154 int localOpen; /* True if the local database is open */
155 char *zLocalRoot; /* The directory holding the local database */
156 int minPrefix; /* Number of digits needed for a distinct UUID */
157 int eHashPolicy; /* Current hash policy. One of HPOLICY_* */
158 int fSqlTrace; /* True if --sqltrace flag is present */
@@ -786,10 +787,11 @@
787 fossil_panic("file descriptor 2 is not open. (fd=%d, errno=%d)",
788 fd, x);
789 }
790 }
791 #endif
792 g.zCmdName = zCmdName;
793 rc = dispatch_name_search(zCmdName, CMDFLAG_COMMAND|CMDFLAG_PREFIX, &pCmd);
794 if( rc==1 ){
795 #ifdef FOSSIL_ENABLE_TH1_HOOKS
796 if( !g.isHTTP && !g.fNoThHook ){
797 rc = Th_CommandHook(zCmdName, 0);
798
+1 -1
--- src/repolist.c
+++ src/repolist.c
@@ -133,11 +133,11 @@
133133
*/
134134
blob_init(&base, g.zRepositoryName, -1);
135135
sqlite3_open(":memory:", &g.db);
136136
db_multi_exec("CREATE TABLE sfile(pathname TEXT);");
137137
db_multi_exec("CREATE TABLE vfile(pathname);");
138
- vfile_scan(&base, blob_size(&base), 0, 0, 0);
138
+ vfile_scan(&base, blob_size(&base), 0, 0, 0, ExtFILE);
139139
db_multi_exec("DELETE FROM sfile WHERE pathname NOT GLOB '*[^/].fossil'");
140140
allRepo = 0;
141141
}
142142
n = db_int(0, "SELECT count(*) FROM sfile");
143143
if( n==0 ){
144144
--- src/repolist.c
+++ src/repolist.c
@@ -133,11 +133,11 @@
133 */
134 blob_init(&base, g.zRepositoryName, -1);
135 sqlite3_open(":memory:", &g.db);
136 db_multi_exec("CREATE TABLE sfile(pathname TEXT);");
137 db_multi_exec("CREATE TABLE vfile(pathname);");
138 vfile_scan(&base, blob_size(&base), 0, 0, 0);
139 db_multi_exec("DELETE FROM sfile WHERE pathname NOT GLOB '*[^/].fossil'");
140 allRepo = 0;
141 }
142 n = db_int(0, "SELECT count(*) FROM sfile");
143 if( n==0 ){
144
--- src/repolist.c
+++ src/repolist.c
@@ -133,11 +133,11 @@
133 */
134 blob_init(&base, g.zRepositoryName, -1);
135 sqlite3_open(":memory:", &g.db);
136 db_multi_exec("CREATE TABLE sfile(pathname TEXT);");
137 db_multi_exec("CREATE TABLE vfile(pathname);");
138 vfile_scan(&base, blob_size(&base), 0, 0, 0, ExtFILE);
139 db_multi_exec("DELETE FROM sfile WHERE pathname NOT GLOB '*[^/].fossil'");
140 allRepo = 0;
141 }
142 n = db_int(0, "SELECT count(*) FROM sfile");
143 if( n==0 ){
144
--- src/security_audit.c
+++ src/security_audit.c
@@ -402,17 +402,18 @@
402402
#endif
403403
404404
if( g.zErrlog==0 || fossil_strcmp(g.zErrlog,"-")==0 ){
405405
@ <li><p>
406406
@ The server error log is disabled.
407
- @ To set up an error log:
408
- @ <ul>
409
- @ <li>If running from CGI, make an entry "errorlog: <i>FILENAME</i>"
410
- @ in the CGI script.
411
- @ <li>If running the "fossil server" or "fossil http" commands,
412
- @ add the "--errorlog <i>FILENAME</i>" command-line option.
413
- @ </ul>
407
+ @ To set up an error log,
408
+ if( fossil_strcmp(g.zCmdName, "cgi")==0 ){
409
+ @ make an entry like "errorlog: <i>FILENAME</i>" in the
410
+ @ CGI script at %h(P("SCRIPT_FILENAME")).
411
+ }else{
412
+ @ add the "--errorlog <i>FILENAME</i>" option to the
413
+ @ "%h(g.argv[0]) %h(g.zCmdName)" command that launched this server.
414
+ }
414415
}else{
415416
FILE *pTest = fossil_fopen(g.zErrlog,"a");
416417
if( pTest==0 ){
417418
@ <li><p>
418419
@ <b>Error:</b>
@@ -425,12 +426,18 @@
425426
@ %,lld(file_size(g.zErrlog, ExtFILE)) bytes in size.
426427
}
427428
}
428429
429430
if( g.zExtRoot ){
431
+ int nFile;
432
+ int nCgi;
433
+ ext_files();
434
+ nFile = db_int(0, "SELECT count(*) FROM sfile");
435
+ nCgi = nFile==0 ? 0 : db_int(0,"SELECT count(*) FROM sfile WHERE isexe");
430436
@ <li><p> CGI Extensions are enabled with a document root
431
- @ of <b>%h(g.zExtRoot)</b>.
437
+ @ at <a href='%R/extfilelist'>%h(g.zExtRoot)</a> holding
438
+ @ %d(nCgi) CGIs and %d(nFile-nCgi) static content and data files.
432439
}
433440
434441
@ <li><p> User capability summary:
435442
capability_summary();
436443
437444
--- src/security_audit.c
+++ src/security_audit.c
@@ -402,17 +402,18 @@
402 #endif
403
404 if( g.zErrlog==0 || fossil_strcmp(g.zErrlog,"-")==0 ){
405 @ <li><p>
406 @ The server error log is disabled.
407 @ To set up an error log:
408 @ <ul>
409 @ <li>If running from CGI, make an entry "errorlog: <i>FILENAME</i>"
410 @ in the CGI script.
411 @ <li>If running the "fossil server" or "fossil http" commands,
412 @ add the "--errorlog <i>FILENAME</i>" command-line option.
413 @ </ul>
 
414 }else{
415 FILE *pTest = fossil_fopen(g.zErrlog,"a");
416 if( pTest==0 ){
417 @ <li><p>
418 @ <b>Error:</b>
@@ -425,12 +426,18 @@
425 @ %,lld(file_size(g.zErrlog, ExtFILE)) bytes in size.
426 }
427 }
428
429 if( g.zExtRoot ){
 
 
 
 
 
430 @ <li><p> CGI Extensions are enabled with a document root
431 @ of <b>%h(g.zExtRoot)</b>.
 
432 }
433
434 @ <li><p> User capability summary:
435 capability_summary();
436
437
--- src/security_audit.c
+++ src/security_audit.c
@@ -402,17 +402,18 @@
402 #endif
403
404 if( g.zErrlog==0 || fossil_strcmp(g.zErrlog,"-")==0 ){
405 @ <li><p>
406 @ The server error log is disabled.
407 @ To set up an error log,
408 if( fossil_strcmp(g.zCmdName, "cgi")==0 ){
409 @ make an entry like "errorlog: <i>FILENAME</i>" in the
410 @ CGI script at %h(P("SCRIPT_FILENAME")).
411 }else{
412 @ add the "--errorlog <i>FILENAME</i>" option to the
413 @ "%h(g.argv[0]) %h(g.zCmdName)" command that launched this server.
414 }
415 }else{
416 FILE *pTest = fossil_fopen(g.zErrlog,"a");
417 if( pTest==0 ){
418 @ <li><p>
419 @ <b>Error:</b>
@@ -425,12 +426,18 @@
426 @ %,lld(file_size(g.zErrlog, ExtFILE)) bytes in size.
427 }
428 }
429
430 if( g.zExtRoot ){
431 int nFile;
432 int nCgi;
433 ext_files();
434 nFile = db_int(0, "SELECT count(*) FROM sfile");
435 nCgi = nFile==0 ? 0 : db_int(0,"SELECT count(*) FROM sfile WHERE isexe");
436 @ <li><p> CGI Extensions are enabled with a document root
437 @ at <a href='%R/extfilelist'>%h(g.zExtRoot)</a> holding
438 @ %d(nCgi) CGIs and %d(nFile-nCgi) static content and data files.
439 }
440
441 @ <li><p> User capability summary:
442 capability_summary();
443
444
+5 -1
--- src/stat.c
+++ src/stat.c
@@ -104,11 +104,15 @@
104104
nDPend = db_int(0,"SELECT count(*) FROM pending_alert"
105105
" WHERE NOT sentDigest");
106106
@ <tr><th>Pending&nbsp;Alerts:</th><td>
107107
@ %,d(nPend) normal, %,d(nDPend) digest
108108
@ </td></tr>
109
- @ <tr><th>Subscribers:</th><td>
109
+ if( g.perm.Admin ){
110
+ @ <tr><th><a href="%R/subscribers">Subscribers:</a></th><td>
111
+ }else{
112
+ @ <tr><th>Subscribers:</th><td>
113
+ }
110114
nSub = db_int(0, "SELECT count(*) FROM subscriber");
111115
nASub = db_int(0, "SELECT count(*) FROM subscriber WHERE sverified"
112116
" AND NOT sdonotcall AND length(ssub)>1");
113117
@ %,d(nASub) active, %,d(nSub) total
114118
@ </td></tr>
115119
--- src/stat.c
+++ src/stat.c
@@ -104,11 +104,15 @@
104 nDPend = db_int(0,"SELECT count(*) FROM pending_alert"
105 " WHERE NOT sentDigest");
106 @ <tr><th>Pending&nbsp;Alerts:</th><td>
107 @ %,d(nPend) normal, %,d(nDPend) digest
108 @ </td></tr>
109 @ <tr><th>Subscribers:</th><td>
 
 
 
 
110 nSub = db_int(0, "SELECT count(*) FROM subscriber");
111 nASub = db_int(0, "SELECT count(*) FROM subscriber WHERE sverified"
112 " AND NOT sdonotcall AND length(ssub)>1");
113 @ %,d(nASub) active, %,d(nSub) total
114 @ </td></tr>
115
--- src/stat.c
+++ src/stat.c
@@ -104,11 +104,15 @@
104 nDPend = db_int(0,"SELECT count(*) FROM pending_alert"
105 " WHERE NOT sentDigest");
106 @ <tr><th>Pending&nbsp;Alerts:</th><td>
107 @ %,d(nPend) normal, %,d(nDPend) digest
108 @ </td></tr>
109 if( g.perm.Admin ){
110 @ <tr><th><a href="%R/subscribers">Subscribers:</a></th><td>
111 }else{
112 @ <tr><th>Subscribers:</th><td>
113 }
114 nSub = db_int(0, "SELECT count(*) FROM subscriber");
115 nASub = db_int(0, "SELECT count(*) FROM subscriber WHERE sverified"
116 " AND NOT sdonotcall AND length(ssub)>1");
117 @ %,d(nASub) active, %,d(nSub) total
118 @ </td></tr>
119
+43 -22
--- src/vfile.c
+++ src/vfile.c
@@ -430,19 +430,21 @@
430430
#define SCAN_ALL 0x001 /* Includes files that begin with "." */
431431
#define SCAN_TEMP 0x002 /* Only Fossil-generated files like *-baseline */
432432
#define SCAN_NESTED 0x004 /* Scan for empty dirs in nested checkouts */
433433
#define SCAN_MTIME 0x008 /* Populate mtime column */
434434
#define SCAN_SIZE 0x010 /* Populate size column */
435
+#define SCAN_ISEXE 0x020 /* Populate isexe column */
435436
#endif /* INTERFACE */
436437
437438
/*
438439
** Load into table SFILE the name of every ordinary file in
439440
** the directory pPath. Omit the first nPrefix characters of
440441
** of pPath when inserting into the SFILE table.
441
-**
442442
** Subdirectories are scanned recursively.
443
-** Omit files named in VFILE.
443
+**
444
+** Omit files named in VFILE if eFType==RepoFILE. Include all files
445
+** if eFType==ExtFILE.
444446
**
445447
** Files whose names begin with "." are omitted unless the SCAN_ALL
446448
** flag is set.
447449
**
448450
** Any files or directories that match the glob patterns pIgnore*
@@ -452,11 +454,12 @@
452454
void vfile_scan(
453455
Blob *pPath, /* Directory to be scanned */
454456
int nPrefix, /* Number of bytes in directory name */
455457
unsigned scanFlags, /* Zero or more SCAN_xxx flags */
456458
Glob *pIgnore1, /* Do not add files that match this GLOB */
457
- Glob *pIgnore2 /* Omit files matching this GLOB too */
459
+ Glob *pIgnore2, /* Omit files matching this GLOB too */
460
+ int eFType /* ExtFILE or RepoFILE */
458461
){
459462
DIR *d;
460463
int origSize;
461464
struct dirent *pEntry;
462465
int skipAll = 0;
@@ -472,20 +475,34 @@
472475
blob_resize(pPath, origSize);
473476
}
474477
if( skipAll ) return;
475478
476479
if( depth==0 ){
477
- db_prepare(&ins,
478
- "INSERT OR IGNORE INTO sfile(pathname%s%s) SELECT :file%s%s"
479
- " WHERE NOT EXISTS(SELECT 1 FROM vfile WHERE"
480
- " pathname=:file %s)",
481
- scanFlags & SCAN_MTIME ? ", mtime" : "",
482
- scanFlags & SCAN_SIZE ? ", size" : "",
483
- scanFlags & SCAN_MTIME ? ", :mtime" : "",
484
- scanFlags & SCAN_SIZE ? ", :size" : "",
485
- filename_collation()
486
- );
480
+ if( eFType==ExtFILE ){
481
+ db_prepare(&ins,
482
+ "INSERT OR IGNORE INTO sfile(pathname%s%s%s) VALUES(:file%s%s%s)",
483
+ scanFlags & SCAN_MTIME ? ",mtime" : "",
484
+ scanFlags & SCAN_SIZE ? ",size" : "",
485
+ scanFlags & SCAN_ISEXE ? ",isexe" : "",
486
+ scanFlags & SCAN_MTIME ? ",:mtime" : "",
487
+ scanFlags & SCAN_SIZE ? ",:size" : "",
488
+ scanFlags & SCAN_ISEXE ? ",:isexe" : ""
489
+ );
490
+ }else{
491
+ db_prepare(&ins,
492
+ "INSERT OR IGNORE INTO sfile(pathname%s%s%s) SELECT :file%s%s%s"
493
+ " WHERE NOT EXISTS(SELECT 1 FROM vfile WHERE"
494
+ " pathname=:file %s)",
495
+ scanFlags & SCAN_MTIME ? ",mtime" : "",
496
+ scanFlags & SCAN_SIZE ? ",size" : "",
497
+ scanFlags & SCAN_ISEXE ? ",isexe" : "",
498
+ scanFlags & SCAN_MTIME ? ",:mtime" : "",
499
+ scanFlags & SCAN_SIZE ? ",:size" : "",
500
+ scanFlags & SCAN_ISEXE ? ",:isexe" : "",
501
+ filename_collation()
502
+ );
503
+ }
487504
}
488505
depth++;
489506
490507
zNative = fossil_utf8_to_path(blob_str(pPath), 1);
491508
d = opendir(zNative);
@@ -504,16 +521,16 @@
504521
if( glob_match(pIgnore1, &zPath[nPrefix+1]) ||
505522
glob_match(pIgnore2, &zPath[nPrefix+1]) ){
506523
/* do nothing */
507524
#ifdef _DIRENT_HAVE_D_TYPE
508525
}else if( (pEntry->d_type==DT_UNKNOWN || pEntry->d_type==DT_LNK)
509
- ? (file_isdir(zPath, RepoFILE)==1) : (pEntry->d_type==DT_DIR) ){
526
+ ? (file_isdir(zPath, eFType)==1) : (pEntry->d_type==DT_DIR) ){
510527
#else
511
- }else if( file_isdir(zPath, RepoFILE)==1 ){
528
+ }else if( file_isdir(zPath, eFType)==1 ){
512529
#endif
513530
if( !vfile_top_of_checkout(zPath) ){
514
- vfile_scan(pPath, nPrefix, scanFlags, pIgnore1, pIgnore2);
531
+ vfile_scan(pPath, nPrefix, scanFlags, pIgnore1, pIgnore2, eFType);
515532
}
516533
#ifdef _DIRENT_HAVE_D_TYPE
517534
}else if( (pEntry->d_type==DT_UNKNOWN || pEntry->d_type==DT_LNK)
518535
? (file_isfile_or_link(zPath)) : (pEntry->d_type==DT_REG) ){
519536
#else
@@ -520,14 +537,17 @@
520537
}else if( file_isfile_or_link(zPath) ){
521538
#endif
522539
if( (scanFlags & SCAN_TEMP)==0 || is_temporary_file(zUtf8) ){
523540
db_bind_text(&ins, ":file", &zPath[nPrefix+1]);
524541
if( scanFlags & SCAN_MTIME ){
525
- db_bind_int(&ins, ":mtime", file_mtime(zPath, RepoFILE));
542
+ db_bind_int(&ins, ":mtime", file_mtime(zPath, eFType));
526543
}
527544
if( scanFlags & SCAN_SIZE ){
528
- db_bind_int(&ins, ":size", file_size(zPath, RepoFILE));
545
+ db_bind_int(&ins, ":size", file_size(zPath, eFType));
546
+ }
547
+ if( scanFlags & SCAN_ISEXE ){
548
+ db_bind_int(&ins, ":isexe", file_isexe(zPath, eFType));
529549
}
530550
db_step(&ins);
531551
db_reset(&ins);
532552
}
533553
}
@@ -564,11 +584,12 @@
564584
int vfile_dir_scan(
565585
Blob *pPath, /* Base directory to be scanned */
566586
int nPrefix, /* Number of bytes in base directory name */
567587
unsigned scanFlags, /* Zero or more SCAN_xxx flags */
568588
Glob *pIgnore1, /* Do not add directories that match this GLOB */
569
- Glob *pIgnore2 /* Omit directories matching this GLOB too */
589
+ Glob *pIgnore2, /* Omit directories matching this GLOB too */
590
+ int eFType /* ExtFILE or RepoFILE */
570591
){
571592
int result = 0;
572593
DIR *d;
573594
int origSize;
574595
struct dirent *pEntry;
@@ -624,18 +645,18 @@
624645
if( glob_match(pIgnore1, &zPath[nPrefix+1]) ||
625646
glob_match(pIgnore2, &zPath[nPrefix+1]) ){
626647
/* do nothing */
627648
#ifdef _DIRENT_HAVE_D_TYPE
628649
}else if( (pEntry->d_type==DT_UNKNOWN || pEntry->d_type==DT_LNK)
629
- ? (file_isdir(zPath, RepoFILE)==1) : (pEntry->d_type==DT_DIR) ){
650
+ ? (file_isdir(zPath, eFType)==1) : (pEntry->d_type==DT_DIR) ){
630651
#else
631
- }else if( file_isdir(zPath, RepoFILE)==1 ){
652
+ }else if( file_isdir(zPath, eFType)==1 ){
632653
#endif
633654
if( (scanFlags & SCAN_NESTED) || !vfile_top_of_checkout(zPath) ){
634655
char *zSavePath = mprintf("%s", zPath);
635656
int count = vfile_dir_scan(pPath, nPrefix, scanFlags, pIgnore1,
636
- pIgnore2);
657
+ pIgnore2, eFType);
637658
db_bind_text(&ins, ":file", &zSavePath[nPrefix+1]);
638659
db_bind_int(&ins, ":count", count);
639660
db_step(&ins);
640661
db_reset(&ins);
641662
fossil_free(zSavePath);
642663
--- src/vfile.c
+++ src/vfile.c
@@ -430,19 +430,21 @@
430 #define SCAN_ALL 0x001 /* Includes files that begin with "." */
431 #define SCAN_TEMP 0x002 /* Only Fossil-generated files like *-baseline */
432 #define SCAN_NESTED 0x004 /* Scan for empty dirs in nested checkouts */
433 #define SCAN_MTIME 0x008 /* Populate mtime column */
434 #define SCAN_SIZE 0x010 /* Populate size column */
 
435 #endif /* INTERFACE */
436
437 /*
438 ** Load into table SFILE the name of every ordinary file in
439 ** the directory pPath. Omit the first nPrefix characters of
440 ** of pPath when inserting into the SFILE table.
441 **
442 ** Subdirectories are scanned recursively.
443 ** Omit files named in VFILE.
 
 
444 **
445 ** Files whose names begin with "." are omitted unless the SCAN_ALL
446 ** flag is set.
447 **
448 ** Any files or directories that match the glob patterns pIgnore*
@@ -452,11 +454,12 @@
452 void vfile_scan(
453 Blob *pPath, /* Directory to be scanned */
454 int nPrefix, /* Number of bytes in directory name */
455 unsigned scanFlags, /* Zero or more SCAN_xxx flags */
456 Glob *pIgnore1, /* Do not add files that match this GLOB */
457 Glob *pIgnore2 /* Omit files matching this GLOB too */
 
458 ){
459 DIR *d;
460 int origSize;
461 struct dirent *pEntry;
462 int skipAll = 0;
@@ -472,20 +475,34 @@
472 blob_resize(pPath, origSize);
473 }
474 if( skipAll ) return;
475
476 if( depth==0 ){
477 db_prepare(&ins,
478 "INSERT OR IGNORE INTO sfile(pathname%s%s) SELECT :file%s%s"
479 " WHERE NOT EXISTS(SELECT 1 FROM vfile WHERE"
480 " pathname=:file %s)",
481 scanFlags & SCAN_MTIME ? ", mtime" : "",
482 scanFlags & SCAN_SIZE ? ", size" : "",
483 scanFlags & SCAN_MTIME ? ", :mtime" : "",
484 scanFlags & SCAN_SIZE ? ", :size" : "",
485 filename_collation()
486 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
487 }
488 depth++;
489
490 zNative = fossil_utf8_to_path(blob_str(pPath), 1);
491 d = opendir(zNative);
@@ -504,16 +521,16 @@
504 if( glob_match(pIgnore1, &zPath[nPrefix+1]) ||
505 glob_match(pIgnore2, &zPath[nPrefix+1]) ){
506 /* do nothing */
507 #ifdef _DIRENT_HAVE_D_TYPE
508 }else if( (pEntry->d_type==DT_UNKNOWN || pEntry->d_type==DT_LNK)
509 ? (file_isdir(zPath, RepoFILE)==1) : (pEntry->d_type==DT_DIR) ){
510 #else
511 }else if( file_isdir(zPath, RepoFILE)==1 ){
512 #endif
513 if( !vfile_top_of_checkout(zPath) ){
514 vfile_scan(pPath, nPrefix, scanFlags, pIgnore1, pIgnore2);
515 }
516 #ifdef _DIRENT_HAVE_D_TYPE
517 }else if( (pEntry->d_type==DT_UNKNOWN || pEntry->d_type==DT_LNK)
518 ? (file_isfile_or_link(zPath)) : (pEntry->d_type==DT_REG) ){
519 #else
@@ -520,14 +537,17 @@
520 }else if( file_isfile_or_link(zPath) ){
521 #endif
522 if( (scanFlags & SCAN_TEMP)==0 || is_temporary_file(zUtf8) ){
523 db_bind_text(&ins, ":file", &zPath[nPrefix+1]);
524 if( scanFlags & SCAN_MTIME ){
525 db_bind_int(&ins, ":mtime", file_mtime(zPath, RepoFILE));
526 }
527 if( scanFlags & SCAN_SIZE ){
528 db_bind_int(&ins, ":size", file_size(zPath, RepoFILE));
 
 
 
529 }
530 db_step(&ins);
531 db_reset(&ins);
532 }
533 }
@@ -564,11 +584,12 @@
564 int vfile_dir_scan(
565 Blob *pPath, /* Base directory to be scanned */
566 int nPrefix, /* Number of bytes in base directory name */
567 unsigned scanFlags, /* Zero or more SCAN_xxx flags */
568 Glob *pIgnore1, /* Do not add directories that match this GLOB */
569 Glob *pIgnore2 /* Omit directories matching this GLOB too */
 
570 ){
571 int result = 0;
572 DIR *d;
573 int origSize;
574 struct dirent *pEntry;
@@ -624,18 +645,18 @@
624 if( glob_match(pIgnore1, &zPath[nPrefix+1]) ||
625 glob_match(pIgnore2, &zPath[nPrefix+1]) ){
626 /* do nothing */
627 #ifdef _DIRENT_HAVE_D_TYPE
628 }else if( (pEntry->d_type==DT_UNKNOWN || pEntry->d_type==DT_LNK)
629 ? (file_isdir(zPath, RepoFILE)==1) : (pEntry->d_type==DT_DIR) ){
630 #else
631 }else if( file_isdir(zPath, RepoFILE)==1 ){
632 #endif
633 if( (scanFlags & SCAN_NESTED) || !vfile_top_of_checkout(zPath) ){
634 char *zSavePath = mprintf("%s", zPath);
635 int count = vfile_dir_scan(pPath, nPrefix, scanFlags, pIgnore1,
636 pIgnore2);
637 db_bind_text(&ins, ":file", &zSavePath[nPrefix+1]);
638 db_bind_int(&ins, ":count", count);
639 db_step(&ins);
640 db_reset(&ins);
641 fossil_free(zSavePath);
642
--- src/vfile.c
+++ src/vfile.c
@@ -430,19 +430,21 @@
430 #define SCAN_ALL 0x001 /* Includes files that begin with "." */
431 #define SCAN_TEMP 0x002 /* Only Fossil-generated files like *-baseline */
432 #define SCAN_NESTED 0x004 /* Scan for empty dirs in nested checkouts */
433 #define SCAN_MTIME 0x008 /* Populate mtime column */
434 #define SCAN_SIZE 0x010 /* Populate size column */
435 #define SCAN_ISEXE 0x020 /* Populate isexe column */
436 #endif /* INTERFACE */
437
438 /*
439 ** Load into table SFILE the name of every ordinary file in
440 ** the directory pPath. Omit the first nPrefix characters of
441 ** of pPath when inserting into the SFILE table.
 
442 ** Subdirectories are scanned recursively.
443 **
444 ** Omit files named in VFILE if eFType==RepoFILE. Include all files
445 ** if eFType==ExtFILE.
446 **
447 ** Files whose names begin with "." are omitted unless the SCAN_ALL
448 ** flag is set.
449 **
450 ** Any files or directories that match the glob patterns pIgnore*
@@ -452,11 +454,12 @@
454 void vfile_scan(
455 Blob *pPath, /* Directory to be scanned */
456 int nPrefix, /* Number of bytes in directory name */
457 unsigned scanFlags, /* Zero or more SCAN_xxx flags */
458 Glob *pIgnore1, /* Do not add files that match this GLOB */
459 Glob *pIgnore2, /* Omit files matching this GLOB too */
460 int eFType /* ExtFILE or RepoFILE */
461 ){
462 DIR *d;
463 int origSize;
464 struct dirent *pEntry;
465 int skipAll = 0;
@@ -472,20 +475,34 @@
475 blob_resize(pPath, origSize);
476 }
477 if( skipAll ) return;
478
479 if( depth==0 ){
480 if( eFType==ExtFILE ){
481 db_prepare(&ins,
482 "INSERT OR IGNORE INTO sfile(pathname%s%s%s) VALUES(:file%s%s%s)",
483 scanFlags & SCAN_MTIME ? ",mtime" : "",
484 scanFlags & SCAN_SIZE ? ",size" : "",
485 scanFlags & SCAN_ISEXE ? ",isexe" : "",
486 scanFlags & SCAN_MTIME ? ",:mtime" : "",
487 scanFlags & SCAN_SIZE ? ",:size" : "",
488 scanFlags & SCAN_ISEXE ? ",:isexe" : ""
489 );
490 }else{
491 db_prepare(&ins,
492 "INSERT OR IGNORE INTO sfile(pathname%s%s%s) SELECT :file%s%s%s"
493 " WHERE NOT EXISTS(SELECT 1 FROM vfile WHERE"
494 " pathname=:file %s)",
495 scanFlags & SCAN_MTIME ? ",mtime" : "",
496 scanFlags & SCAN_SIZE ? ",size" : "",
497 scanFlags & SCAN_ISEXE ? ",isexe" : "",
498 scanFlags & SCAN_MTIME ? ",:mtime" : "",
499 scanFlags & SCAN_SIZE ? ",:size" : "",
500 scanFlags & SCAN_ISEXE ? ",:isexe" : "",
501 filename_collation()
502 );
503 }
504 }
505 depth++;
506
507 zNative = fossil_utf8_to_path(blob_str(pPath), 1);
508 d = opendir(zNative);
@@ -504,16 +521,16 @@
521 if( glob_match(pIgnore1, &zPath[nPrefix+1]) ||
522 glob_match(pIgnore2, &zPath[nPrefix+1]) ){
523 /* do nothing */
524 #ifdef _DIRENT_HAVE_D_TYPE
525 }else if( (pEntry->d_type==DT_UNKNOWN || pEntry->d_type==DT_LNK)
526 ? (file_isdir(zPath, eFType)==1) : (pEntry->d_type==DT_DIR) ){
527 #else
528 }else if( file_isdir(zPath, eFType)==1 ){
529 #endif
530 if( !vfile_top_of_checkout(zPath) ){
531 vfile_scan(pPath, nPrefix, scanFlags, pIgnore1, pIgnore2, eFType);
532 }
533 #ifdef _DIRENT_HAVE_D_TYPE
534 }else if( (pEntry->d_type==DT_UNKNOWN || pEntry->d_type==DT_LNK)
535 ? (file_isfile_or_link(zPath)) : (pEntry->d_type==DT_REG) ){
536 #else
@@ -520,14 +537,17 @@
537 }else if( file_isfile_or_link(zPath) ){
538 #endif
539 if( (scanFlags & SCAN_TEMP)==0 || is_temporary_file(zUtf8) ){
540 db_bind_text(&ins, ":file", &zPath[nPrefix+1]);
541 if( scanFlags & SCAN_MTIME ){
542 db_bind_int(&ins, ":mtime", file_mtime(zPath, eFType));
543 }
544 if( scanFlags & SCAN_SIZE ){
545 db_bind_int(&ins, ":size", file_size(zPath, eFType));
546 }
547 if( scanFlags & SCAN_ISEXE ){
548 db_bind_int(&ins, ":isexe", file_isexe(zPath, eFType));
549 }
550 db_step(&ins);
551 db_reset(&ins);
552 }
553 }
@@ -564,11 +584,12 @@
584 int vfile_dir_scan(
585 Blob *pPath, /* Base directory to be scanned */
586 int nPrefix, /* Number of bytes in base directory name */
587 unsigned scanFlags, /* Zero or more SCAN_xxx flags */
588 Glob *pIgnore1, /* Do not add directories that match this GLOB */
589 Glob *pIgnore2, /* Omit directories matching this GLOB too */
590 int eFType /* ExtFILE or RepoFILE */
591 ){
592 int result = 0;
593 DIR *d;
594 int origSize;
595 struct dirent *pEntry;
@@ -624,18 +645,18 @@
645 if( glob_match(pIgnore1, &zPath[nPrefix+1]) ||
646 glob_match(pIgnore2, &zPath[nPrefix+1]) ){
647 /* do nothing */
648 #ifdef _DIRENT_HAVE_D_TYPE
649 }else if( (pEntry->d_type==DT_UNKNOWN || pEntry->d_type==DT_LNK)
650 ? (file_isdir(zPath, eFType)==1) : (pEntry->d_type==DT_DIR) ){
651 #else
652 }else if( file_isdir(zPath, eFType)==1 ){
653 #endif
654 if( (scanFlags & SCAN_NESTED) || !vfile_top_of_checkout(zPath) ){
655 char *zSavePath = mprintf("%s", zPath);
656 int count = vfile_dir_scan(pPath, nPrefix, scanFlags, pIgnore1,
657 pIgnore2, eFType);
658 db_bind_text(&ins, ":file", &zSavePath[nPrefix+1]);
659 db_bind_int(&ins, ":count", count);
660 db_step(&ins);
661 db_reset(&ins);
662 fossil_free(zSavePath);
663

Keyboard Shortcuts

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