Fossil SCM

2.12.1 release candidate with security fixes.

drh 2020-08-20 13:01 branch-2.12 merge
Commit 40feec329163103293d98dfcc2d119d1a16b227ac9adc52450a7546738648f1b
+30 -10
--- src/add.c
+++ src/add.c
@@ -156,10 +156,11 @@
156156
*/
157157
static int add_one_file(
158158
const char *zPath, /* Tree-name of file to add. */
159159
int vid /* Add to this VFILE */
160160
){
161
+ int doSkip = 0;
161162
if( !file_is_simple_pathname(zPath, 1) ){
162163
fossil_warning("filename contains illegal characters: %s", zPath);
163164
return 0;
164165
}
165166
if( db_exists("SELECT 1 FROM vfile"
@@ -168,17 +169,22 @@
168169
" WHERE pathname=%Q %s AND deleted",
169170
zPath, filename_collation());
170171
}else{
171172
char *zFullname = mprintf("%s%s", g.zLocalRoot, zPath);
172173
int isExe = file_isexe(zFullname, RepoFILE);
173
- db_multi_exec(
174
- "INSERT INTO vfile(vid,deleted,rid,mrid,pathname,isexe,islink,mhash)"
175
- "VALUES(%d,0,0,0,%Q,%d,%d,NULL)",
176
- vid, zPath, isExe, file_islink(0));
174
+ if( file_nondir_objects_on_path(g.zLocalRoot, zFullname) ){
175
+ /* Do not add unsafe files to the vfile */
176
+ doSkip = 1;
177
+ }else{
178
+ db_multi_exec(
179
+ "INSERT INTO vfile(vid,deleted,rid,mrid,pathname,isexe,islink,mhash)"
180
+ "VALUES(%d,0,0,0,%Q,%d,%d,NULL)",
181
+ vid, zPath, isExe, file_islink(0));
182
+ }
177183
fossil_free(zFullname);
178184
}
179
- if( db_changes() ){
185
+ if( db_changes() && !doSkip ){
180186
fossil_print("ADDED %s\n", zPath);
181187
return 1;
182188
}else{
183189
fossil_print("SKIP %s\n", zPath);
184190
return 0;
@@ -186,11 +192,13 @@
186192
}
187193
188194
/*
189195
** Add all files in the sfile temp table.
190196
**
191
-** Automatically exclude the repository file.
197
+** Automatically exclude the repository file and any other files
198
+** with reserved names. Also exclude files that are beneath an
199
+** existing symlink.
192200
*/
193201
static int add_files_in_sfile(int vid){
194202
const char *zRepo; /* Name of the repository database file */
195203
int nAdd = 0; /* Number of files added */
196204
int i; /* Loop counter */
@@ -208,18 +216,30 @@
208216
if( filenames_are_case_sensitive() ){
209217
xCmp = fossil_strcmp;
210218
}else{
211219
xCmp = fossil_stricmp;
212220
}
213
- db_prepare(&loop, "SELECT pathname FROM sfile ORDER BY pathname");
221
+ db_prepare(&loop,
222
+ "SELECT pathname FROM sfile"
223
+ " WHERE pathname NOT IN ("
224
+ "SELECT sfile.pathname FROM vfile, sfile"
225
+ " WHERE vfile.islink"
226
+ " AND NOT vfile.deleted"
227
+ " AND sfile.pathname>(vfile.pathname||'/')"
228
+ " AND sfile.pathname<(vfile.pathname||'0'))"
229
+ " ORDER BY pathname");
214230
while( db_step(&loop)==SQLITE_ROW ){
215231
const char *zToAdd = db_column_text(&loop, 0);
216232
if( fossil_strcmp(zToAdd, zRepo)==0 ) continue;
217
- for(i=0; (zReserved = fossil_reserved_name(i, 0))!=0; i++){
218
- if( xCmp(zToAdd, zReserved)==0 ) break;
233
+ if( strchr(zToAdd,'/') ){
234
+ if( file_is_reserved_name(zToAdd, -1) ) continue;
235
+ }else{
236
+ for(i=0; (zReserved = fossil_reserved_name(i, 0))!=0; i++){
237
+ if( xCmp(zToAdd, zReserved)==0 ) break;
238
+ }
239
+ if( zReserved ) continue;
219240
}
220
- if( zReserved ) continue;
221241
nAdd += add_one_file(zToAdd, vid);
222242
}
223243
db_finalize(&loop);
224244
blob_reset(&repoName);
225245
return nAdd;
226246
--- src/add.c
+++ src/add.c
@@ -156,10 +156,11 @@
156 */
157 static int add_one_file(
158 const char *zPath, /* Tree-name of file to add. */
159 int vid /* Add to this VFILE */
160 ){
 
161 if( !file_is_simple_pathname(zPath, 1) ){
162 fossil_warning("filename contains illegal characters: %s", zPath);
163 return 0;
164 }
165 if( db_exists("SELECT 1 FROM vfile"
@@ -168,17 +169,22 @@
168 " WHERE pathname=%Q %s AND deleted",
169 zPath, filename_collation());
170 }else{
171 char *zFullname = mprintf("%s%s", g.zLocalRoot, zPath);
172 int isExe = file_isexe(zFullname, RepoFILE);
173 db_multi_exec(
174 "INSERT INTO vfile(vid,deleted,rid,mrid,pathname,isexe,islink,mhash)"
175 "VALUES(%d,0,0,0,%Q,%d,%d,NULL)",
176 vid, zPath, isExe, file_islink(0));
 
 
 
 
 
177 fossil_free(zFullname);
178 }
179 if( db_changes() ){
180 fossil_print("ADDED %s\n", zPath);
181 return 1;
182 }else{
183 fossil_print("SKIP %s\n", zPath);
184 return 0;
@@ -186,11 +192,13 @@
186 }
187
188 /*
189 ** Add all files in the sfile temp table.
190 **
191 ** Automatically exclude the repository file.
 
 
192 */
193 static int add_files_in_sfile(int vid){
194 const char *zRepo; /* Name of the repository database file */
195 int nAdd = 0; /* Number of files added */
196 int i; /* Loop counter */
@@ -208,18 +216,30 @@
208 if( filenames_are_case_sensitive() ){
209 xCmp = fossil_strcmp;
210 }else{
211 xCmp = fossil_stricmp;
212 }
213 db_prepare(&loop, "SELECT pathname FROM sfile ORDER BY pathname");
 
 
 
 
 
 
 
 
214 while( db_step(&loop)==SQLITE_ROW ){
215 const char *zToAdd = db_column_text(&loop, 0);
216 if( fossil_strcmp(zToAdd, zRepo)==0 ) continue;
217 for(i=0; (zReserved = fossil_reserved_name(i, 0))!=0; i++){
218 if( xCmp(zToAdd, zReserved)==0 ) break;
 
 
 
 
 
219 }
220 if( zReserved ) continue;
221 nAdd += add_one_file(zToAdd, vid);
222 }
223 db_finalize(&loop);
224 blob_reset(&repoName);
225 return nAdd;
226
--- src/add.c
+++ src/add.c
@@ -156,10 +156,11 @@
156 */
157 static int add_one_file(
158 const char *zPath, /* Tree-name of file to add. */
159 int vid /* Add to this VFILE */
160 ){
161 int doSkip = 0;
162 if( !file_is_simple_pathname(zPath, 1) ){
163 fossil_warning("filename contains illegal characters: %s", zPath);
164 return 0;
165 }
166 if( db_exists("SELECT 1 FROM vfile"
@@ -168,17 +169,22 @@
169 " WHERE pathname=%Q %s AND deleted",
170 zPath, filename_collation());
171 }else{
172 char *zFullname = mprintf("%s%s", g.zLocalRoot, zPath);
173 int isExe = file_isexe(zFullname, RepoFILE);
174 if( file_nondir_objects_on_path(g.zLocalRoot, zFullname) ){
175 /* Do not add unsafe files to the vfile */
176 doSkip = 1;
177 }else{
178 db_multi_exec(
179 "INSERT INTO vfile(vid,deleted,rid,mrid,pathname,isexe,islink,mhash)"
180 "VALUES(%d,0,0,0,%Q,%d,%d,NULL)",
181 vid, zPath, isExe, file_islink(0));
182 }
183 fossil_free(zFullname);
184 }
185 if( db_changes() && !doSkip ){
186 fossil_print("ADDED %s\n", zPath);
187 return 1;
188 }else{
189 fossil_print("SKIP %s\n", zPath);
190 return 0;
@@ -186,11 +192,13 @@
192 }
193
194 /*
195 ** Add all files in the sfile temp table.
196 **
197 ** Automatically exclude the repository file and any other files
198 ** with reserved names. Also exclude files that are beneath an
199 ** existing symlink.
200 */
201 static int add_files_in_sfile(int vid){
202 const char *zRepo; /* Name of the repository database file */
203 int nAdd = 0; /* Number of files added */
204 int i; /* Loop counter */
@@ -208,18 +216,30 @@
216 if( filenames_are_case_sensitive() ){
217 xCmp = fossil_strcmp;
218 }else{
219 xCmp = fossil_stricmp;
220 }
221 db_prepare(&loop,
222 "SELECT pathname FROM sfile"
223 " WHERE pathname NOT IN ("
224 "SELECT sfile.pathname FROM vfile, sfile"
225 " WHERE vfile.islink"
226 " AND NOT vfile.deleted"
227 " AND sfile.pathname>(vfile.pathname||'/')"
228 " AND sfile.pathname<(vfile.pathname||'0'))"
229 " ORDER BY pathname");
230 while( db_step(&loop)==SQLITE_ROW ){
231 const char *zToAdd = db_column_text(&loop, 0);
232 if( fossil_strcmp(zToAdd, zRepo)==0 ) continue;
233 if( strchr(zToAdd,'/') ){
234 if( file_is_reserved_name(zToAdd, -1) ) continue;
235 }else{
236 for(i=0; (zReserved = fossil_reserved_name(i, 0))!=0; i++){
237 if( xCmp(zToAdd, zReserved)==0 ) break;
238 }
239 if( zReserved ) continue;
240 }
 
241 nAdd += add_one_file(zToAdd, vid);
242 }
243 db_finalize(&loop);
244 blob_reset(&repoName);
245 return nAdd;
246
--- src/checkin.c
+++ src/checkin.c
@@ -856,12 +856,14 @@
856856
857857
if( zIgnoreFlag==0 ){
858858
zIgnoreFlag = db_get("ignore-glob", 0);
859859
}
860860
pIgnore = glob_create(zIgnoreFlag);
861
+#ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
861862
/* Always consider symlinks. */
862863
g.allowSymlinks = db_allow_symlinks_by_default();
864
+#endif
863865
locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore);
864866
glob_free(pIgnore);
865867
866868
blob_zero(&report);
867869
status_report(&report, flags);
@@ -1015,12 +1017,14 @@
10151017
verify_all_options();
10161018
pIgnore = glob_create(zIgnoreFlag);
10171019
pKeep = glob_create(zKeepFlag);
10181020
pClean = glob_create(zCleanFlag);
10191021
nRoot = (int)strlen(g.zLocalRoot);
1022
+#ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
10201023
/* Always consider symlinks. */
10211024
g.allowSymlinks = db_allow_symlinks_by_default();
1025
+#endif
10221026
if( !dirsOnlyFlag ){
10231027
Stmt q;
10241028
Blob repo;
10251029
if( !dryRunFlag && !disableUndo ) undo_begin();
10261030
locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore);
10271031
--- src/checkin.c
+++ src/checkin.c
@@ -856,12 +856,14 @@
856
857 if( zIgnoreFlag==0 ){
858 zIgnoreFlag = db_get("ignore-glob", 0);
859 }
860 pIgnore = glob_create(zIgnoreFlag);
 
861 /* Always consider symlinks. */
862 g.allowSymlinks = db_allow_symlinks_by_default();
 
863 locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore);
864 glob_free(pIgnore);
865
866 blob_zero(&report);
867 status_report(&report, flags);
@@ -1015,12 +1017,14 @@
1015 verify_all_options();
1016 pIgnore = glob_create(zIgnoreFlag);
1017 pKeep = glob_create(zKeepFlag);
1018 pClean = glob_create(zCleanFlag);
1019 nRoot = (int)strlen(g.zLocalRoot);
 
1020 /* Always consider symlinks. */
1021 g.allowSymlinks = db_allow_symlinks_by_default();
 
1022 if( !dirsOnlyFlag ){
1023 Stmt q;
1024 Blob repo;
1025 if( !dryRunFlag && !disableUndo ) undo_begin();
1026 locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore);
1027
--- src/checkin.c
+++ src/checkin.c
@@ -856,12 +856,14 @@
856
857 if( zIgnoreFlag==0 ){
858 zIgnoreFlag = db_get("ignore-glob", 0);
859 }
860 pIgnore = glob_create(zIgnoreFlag);
861 #ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
862 /* Always consider symlinks. */
863 g.allowSymlinks = db_allow_symlinks_by_default();
864 #endif
865 locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore);
866 glob_free(pIgnore);
867
868 blob_zero(&report);
869 status_report(&report, flags);
@@ -1015,12 +1017,14 @@
1017 verify_all_options();
1018 pIgnore = glob_create(zIgnoreFlag);
1019 pKeep = glob_create(zKeepFlag);
1020 pClean = glob_create(zCleanFlag);
1021 nRoot = (int)strlen(g.zLocalRoot);
1022 #ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
1023 /* Always consider symlinks. */
1024 g.allowSymlinks = db_allow_symlinks_by_default();
1025 #endif
1026 if( !dirsOnlyFlag ){
1027 Stmt q;
1028 Blob repo;
1029 if( !dryRunFlag && !disableUndo ) undo_begin();
1030 locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore);
1031
--- src/configure.c
+++ src/configure.c
@@ -143,11 +143,13 @@
143143
{ "keep-glob", CONFIGSET_PROJ },
144144
{ "crlf-glob", CONFIGSET_PROJ },
145145
{ "crnl-glob", CONFIGSET_PROJ },
146146
{ "encoding-glob", CONFIGSET_PROJ },
147147
{ "empty-dirs", CONFIGSET_PROJ },
148
+#ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
148149
{ "allow-symlinks", CONFIGSET_PROJ },
150
+#endif
149151
{ "dotfiles", CONFIGSET_PROJ },
150152
{ "parent-project-code", CONFIGSET_PROJ },
151153
{ "parent-project-name", CONFIGSET_PROJ },
152154
{ "hash-policy", CONFIGSET_PROJ },
153155
{ "comment-format", CONFIGSET_PROJ },
154156
--- src/configure.c
+++ src/configure.c
@@ -143,11 +143,13 @@
143 { "keep-glob", CONFIGSET_PROJ },
144 { "crlf-glob", CONFIGSET_PROJ },
145 { "crnl-glob", CONFIGSET_PROJ },
146 { "encoding-glob", CONFIGSET_PROJ },
147 { "empty-dirs", CONFIGSET_PROJ },
 
148 { "allow-symlinks", CONFIGSET_PROJ },
 
149 { "dotfiles", CONFIGSET_PROJ },
150 { "parent-project-code", CONFIGSET_PROJ },
151 { "parent-project-name", CONFIGSET_PROJ },
152 { "hash-policy", CONFIGSET_PROJ },
153 { "comment-format", CONFIGSET_PROJ },
154
--- src/configure.c
+++ src/configure.c
@@ -143,11 +143,13 @@
143 { "keep-glob", CONFIGSET_PROJ },
144 { "crlf-glob", CONFIGSET_PROJ },
145 { "crnl-glob", CONFIGSET_PROJ },
146 { "encoding-glob", CONFIGSET_PROJ },
147 { "empty-dirs", CONFIGSET_PROJ },
148 #ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
149 { "allow-symlinks", CONFIGSET_PROJ },
150 #endif
151 { "dotfiles", CONFIGSET_PROJ },
152 { "parent-project-code", CONFIGSET_PROJ },
153 { "parent-project-name", CONFIGSET_PROJ },
154 { "hash-policy", CONFIGSET_PROJ },
155 { "comment-format", CONFIGSET_PROJ },
156
+80 -17
--- src/db.c
+++ src/db.c
@@ -130,10 +130,13 @@
130130
char *azBeforeCommit[5]; /* Commands to run prior to COMMIT */
131131
int nBeforeCommit; /* Number of entries in azBeforeCommit */
132132
int nPriorChanges; /* sqlite3_total_changes() at transaction start */
133133
const char *zStartFile; /* File in which transaction was started */
134134
int iStartLine; /* Line of zStartFile where transaction started */
135
+ int (*xAuth)(void*,int,const char*,const char*,const char*,const char*);
136
+ void *pAuthArg; /* Argument to the authorizer */
137
+ const char *zAuthName; /* Name of the authorizer */
135138
} db = {0, 0, 0, 0, 0, 0, };
136139
137140
/*
138141
** Arrange for the given file to be deleted on a failure.
139142
*/
@@ -316,10 +319,36 @@
316319
}
317320
db.aHook[db.nCommitHook].sequence = sequence;
318321
db.aHook[db.nCommitHook].xHook = x;
319322
db.nCommitHook++;
320323
}
324
+
325
+/*
326
+** Set or unset the query authorizer callback function
327
+*/
328
+void db_set_authorizer(
329
+ int(*xAuth)(void*,int,const char*,const char*,const char*,const char*),
330
+ void *pArg,
331
+ const char *zName /* for tracing */
332
+){
333
+ if( db.xAuth ){
334
+ fossil_panic("multiple active db_set_authorizer() calls");
335
+ }
336
+ if( g.db ) sqlite3_set_authorizer(g.db, xAuth, pArg);
337
+ db.xAuth = xAuth;
338
+ db.pAuthArg = pArg;
339
+ db.zAuthName = zName;
340
+ if( g.fSqlTrace ) fossil_trace("-- set authorizer %s\n", zName);
341
+}
342
+void db_clear_authorizer(void){
343
+ if( db.zAuthName && g.fSqlTrace ){
344
+ fossil_trace("-- discontinue authorizer %s\n", db.zAuthName);
345
+ }
346
+ if( g.db ) sqlite3_set_authorizer(g.db, 0, 0);
347
+ db.xAuth = 0;
348
+ db.pAuthArg = 0;
349
+}
321350
322351
#if INTERFACE
323352
/*
324353
** Possible flags to db_vprepare
325354
*/
@@ -844,34 +873,37 @@
844873
void db_init_database(
845874
const char *zFileName, /* Name of database file to create */
846875
const char *zSchema, /* First part of schema */
847876
... /* Additional SQL to run. Terminate with NULL. */
848877
){
849
- sqlite3 *db;
878
+ sqlite3 *xdb;
850879
int rc;
851880
const char *zSql;
852881
va_list ap;
853882
854
- db = db_open(zFileName ? zFileName : ":memory:");
855
- sqlite3_exec(db, "BEGIN EXCLUSIVE", 0, 0, 0);
856
- rc = sqlite3_exec(db, zSchema, 0, 0, 0);
883
+ xdb = db_open(zFileName ? zFileName : ":memory:");
884
+ sqlite3_exec(xdb, "BEGIN EXCLUSIVE", 0, 0, 0);
885
+ if( db.xAuth ){
886
+ sqlite3_set_authorizer(xdb, db.xAuth, db.pAuthArg);
887
+ }
888
+ rc = sqlite3_exec(xdb, zSchema, 0, 0, 0);
857889
if( rc!=SQLITE_OK ){
858
- db_err("%s", sqlite3_errmsg(db));
890
+ db_err("%s", sqlite3_errmsg(xdb));
859891
}
860892
va_start(ap, zSchema);
861893
while( (zSql = va_arg(ap, const char*))!=0 ){
862
- rc = sqlite3_exec(db, zSql, 0, 0, 0);
894
+ rc = sqlite3_exec(xdb, zSql, 0, 0, 0);
863895
if( rc!=SQLITE_OK ){
864
- db_err("%s", sqlite3_errmsg(db));
896
+ db_err("%s", sqlite3_errmsg(xdb));
865897
}
866898
}
867899
va_end(ap);
868
- sqlite3_exec(db, "COMMIT", 0, 0, 0);
900
+ sqlite3_exec(xdb, "COMMIT", 0, 0, 0);
869901
if( zFileName || g.db!=0 ){
870
- sqlite3_close(db);
902
+ sqlite3_close(xdb);
871903
}else{
872
- g.db = db;
904
+ g.db = xdb;
873905
}
874906
}
875907
876908
/*
877909
** Function to return the number of seconds since 1970. This is
@@ -1793,11 +1825,11 @@
17931825
/*
17941826
** Returns non-zero if the default value for the "allow-symlinks" setting
17951827
** is "on". When on Windows, this always returns false.
17961828
*/
17971829
int db_allow_symlinks_by_default(void){
1798
-#if defined(_WIN32)
1830
+#if defined(_WIN32) || !defined(FOSSIL_LEGACY_ALLOW_SYMLINKS)
17991831
return 0;
18001832
#else
18011833
return 1;
18021834
#endif
18031835
}
@@ -2086,10 +2118,11 @@
20862118
** argument is true. Ignore unfinalized statements when false.
20872119
*/
20882120
void db_close(int reportErrors){
20892121
sqlite3_stmt *pStmt;
20902122
if( g.db==0 ) return;
2123
+ sqlite3_set_authorizer(g.db, 0, 0);
20912124
if( g.fSqlStats ){
20922125
int cur, hiwtr;
20932126
sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_USED, &cur, &hiwtr, 0);
20942127
fprintf(stderr, "-- LOOKASIDE_USED %10d %10d\n", cur, hiwtr);
20952128
sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &cur, &hiwtr, 0);
@@ -2115,17 +2148,20 @@
21152148
fprintf(stderr, "-- prepared statements %10d\n", db.nPrepare);
21162149
}
21172150
while( db.pAllStmt ){
21182151
db_finalize(db.pAllStmt);
21192152
}
2120
- if( db.nBegin && reportErrors ){
2121
- fossil_warning("Transaction started at %s:%d never commits",
2122
- db.zStartFile, db.iStartLine);
2153
+ if( db.nBegin ){
2154
+ if( reportErrors ){
2155
+ fossil_warning("Transaction started at %s:%d never commits",
2156
+ db.zStartFile, db.iStartLine);
2157
+ }
21232158
db_end_transaction(1);
21242159
}
21252160
pStmt = 0;
2126
- g.dbIgnoreErrors++; /* Stop "database locked" warnings from PRAGMA optimize */
2161
+ sqlite3_busy_timeout(g.db, 0);
2162
+ g.dbIgnoreErrors++; /* Stop "database locked" warnings */
21272163
sqlite3_exec(g.db, "PRAGMA optimize", 0, 0, 0);
21282164
g.dbIgnoreErrors--;
21292165
db_close_config();
21302166
21312167
/* If the localdb has a lot of unused free space,
@@ -2165,10 +2201,11 @@
21652201
if( g.db ){
21662202
int rc;
21672203
sqlite3_wal_checkpoint(g.db, 0);
21682204
rc = sqlite3_close(g.db);
21692205
if( g.fSqlTrace ) fossil_trace("-- sqlite3_close(%d)\n", rc);
2206
+ db_clear_authorizer();
21702207
}
21712208
g.db = 0;
21722209
g.repositoryOpen = 0;
21732210
g.localOpen = 0;
21742211
}
@@ -2919,17 +2956,19 @@
29192956
dflt = 0;
29202957
}
29212958
fossil_free(zVal);
29222959
return dflt;
29232960
}
2961
+#ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
29242962
int db_get_versioned_boolean(const char *zName, int dflt){
29252963
char *zVal = db_get_versioned(zName, 0);
29262964
if( zVal==0 ) return dflt;
29272965
if( is_truth(zVal) ) return 1;
29282966
if( is_false(zVal) ) return 0;
29292967
return dflt;
29302968
}
2969
+#endif /* FOSSIL_LEGACY_ALLOW_SYMLINKS */
29312970
char *db_lget(const char *zName, const char *zDefault){
29322971
return db_text(zDefault,
29332972
"SELECT value FROM vvar WHERE name=%Q", zName);
29342973
}
29352974
void db_lset(const char *zName, const char *zValue){
@@ -3128,11 +3167,13 @@
31283167
void cmd_open(void){
31293168
int emptyFlag;
31303169
int keepFlag;
31313170
int forceMissingFlag;
31323171
int allowNested;
3172
+#ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
31333173
int allowSymlinks;
3174
+#endif
31343175
int setmtimeFlag; /* --setmtime. Set mtimes on files */
31353176
int bForce = 0; /* --force. Open even if non-empty dir */
31363177
static char *azNewArgv[] = { 0, "checkout", "--prompt", 0, 0, 0, 0 };
31373178
const char *zWorkDir; /* --workdir value */
31383179
const char *zRepo = 0; /* Name of the repository file */
@@ -3239,10 +3280,11 @@
32393280
}else if( db_exists("SELECT 1 FROM event WHERE type='ci'") ){
32403281
g.zOpenRevision = db_get("main-branch", 0);
32413282
}
32423283
}
32433284
3285
+#ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
32443286
if( g.zOpenRevision ){
32453287
/* Since the repository is open and we know the revision now,
32463288
** refresh the allow-symlinks flag. Since neither the local
32473289
** checkout nor the configuration database are open at this
32483290
** point, this should always return the versioned setting,
@@ -3252,10 +3294,11 @@
32523294
** repository or global configuration databases only. */
32533295
allowSymlinks = db_get_versioned_boolean("allow-symlinks", -1);
32543296
}else{
32553297
allowSymlinks = -1; /* Use non-versioned settings only. */
32563298
}
3299
+#endif
32573300
32583301
#if defined(_WIN32) || defined(__CYGWIN__)
32593302
# define LOCALDB_NAME "./_FOSSIL_"
32603303
#else
32613304
# define LOCALDB_NAME "./.fslckout"
@@ -3265,10 +3308,11 @@
32653308
"COMMIT; PRAGMA journal_mode=WAL; BEGIN;",
32663309
#endif
32673310
(char*)0);
32683311
db_delete_on_failure(LOCALDB_NAME);
32693312
db_open_local(0);
3313
+#ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
32703314
if( allowSymlinks>=0 ){
32713315
/* Use the value from the versioned setting, which was read
32723316
** prior to opening the local checkout (i.e. which is most
32733317
** likely empty and does not actually contain any versioned
32743318
** setting files yet). Normally, this value would be given
@@ -3281,10 +3325,11 @@
32813325
** point, this will probably be the setting value from the
32823326
** repository or global configuration databases. */
32833327
g.allowSymlinks = db_get_boolean("allow-symlinks",
32843328
db_allow_symlinks_by_default());
32853329
}
3330
+#endif /* FOSSIL_LEGACY_ALLOW_SYMLINKS */
32863331
db_lset("repository", zRepo);
32873332
db_record_repository_filename(zRepo);
32883333
db_set_checkout(0);
32893334
azNewArgv[0] = g.argv[0];
32903335
g.argv = azNewArgv;
@@ -3392,11 +3437,29 @@
33923437
** SETTING: admin-log boolean default=off
33933438
**
33943439
** When the admin-log setting is enabled, configuration changes are recorded
33953440
** in the "admin_log" table of the repository.
33963441
*/
3397
-#if defined(_WIN32)
3442
+#if !defined(FOSSIL_LEGACY_ALLOW_SYMLINKS)
3443
+/*
3444
+** SETTING: allow-symlinks boolean default=off
3445
+**
3446
+** When allow-symlinks is OFF (which is the default and recommended setting)
3447
+** symbolic links are treated like text files that contain a single line of
3448
+** content which is the name of their target. If allow-symlinks is ON,
3449
+** the symbolic links are actually followed.
3450
+**
3451
+** The use of symbolic links is dangerous. If you checkout a maliciously
3452
+** crafted checkin that contains symbolic links, it is possible that files
3453
+** outside of the working directory might be overwritten.
3454
+**
3455
+** Keep this setting OFF unless you have a very good reason to turn it
3456
+** on and you implicitly trust the integrity of the repositories you
3457
+** open.
3458
+*/
3459
+#endif
3460
+#if defined(_WIN32) && defined(FOSSIL_LEGACY_ALLOW_SYMLINKS)
33983461
/*
33993462
** SETTING: allow-symlinks boolean default=off versionable
34003463
**
34013464
** When allow-symlinks is OFF, symbolic links in the repository are followed
34023465
** and treated no differently from real files. When allow-symlinks is ON,
@@ -3403,11 +3466,11 @@
34033466
** the object to which the symbolic link points is ignored, and the content
34043467
** of the symbolic link that is stored in the repository is the name of the
34053468
** object to which the symbolic link points.
34063469
*/
34073470
#endif
3408
-#if !defined(_WIN32)
3471
+#if !defined(_WIN32) && defined(FOSSIL_LEGACY_ALLOW_SYMLINKS)
34093472
/*
34103473
** SETTING: allow-symlinks boolean default=on versionable
34113474
**
34123475
** When allow-symlinks is OFF, symbolic links in the repository are followed
34133476
** and treated no differently from real files. When allow-symlinks is ON,
34143477
--- src/db.c
+++ src/db.c
@@ -130,10 +130,13 @@
130 char *azBeforeCommit[5]; /* Commands to run prior to COMMIT */
131 int nBeforeCommit; /* Number of entries in azBeforeCommit */
132 int nPriorChanges; /* sqlite3_total_changes() at transaction start */
133 const char *zStartFile; /* File in which transaction was started */
134 int iStartLine; /* Line of zStartFile where transaction started */
 
 
 
135 } db = {0, 0, 0, 0, 0, 0, };
136
137 /*
138 ** Arrange for the given file to be deleted on a failure.
139 */
@@ -316,10 +319,36 @@
316 }
317 db.aHook[db.nCommitHook].sequence = sequence;
318 db.aHook[db.nCommitHook].xHook = x;
319 db.nCommitHook++;
320 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
321
322 #if INTERFACE
323 /*
324 ** Possible flags to db_vprepare
325 */
@@ -844,34 +873,37 @@
844 void db_init_database(
845 const char *zFileName, /* Name of database file to create */
846 const char *zSchema, /* First part of schema */
847 ... /* Additional SQL to run. Terminate with NULL. */
848 ){
849 sqlite3 *db;
850 int rc;
851 const char *zSql;
852 va_list ap;
853
854 db = db_open(zFileName ? zFileName : ":memory:");
855 sqlite3_exec(db, "BEGIN EXCLUSIVE", 0, 0, 0);
856 rc = sqlite3_exec(db, zSchema, 0, 0, 0);
 
 
 
857 if( rc!=SQLITE_OK ){
858 db_err("%s", sqlite3_errmsg(db));
859 }
860 va_start(ap, zSchema);
861 while( (zSql = va_arg(ap, const char*))!=0 ){
862 rc = sqlite3_exec(db, zSql, 0, 0, 0);
863 if( rc!=SQLITE_OK ){
864 db_err("%s", sqlite3_errmsg(db));
865 }
866 }
867 va_end(ap);
868 sqlite3_exec(db, "COMMIT", 0, 0, 0);
869 if( zFileName || g.db!=0 ){
870 sqlite3_close(db);
871 }else{
872 g.db = db;
873 }
874 }
875
876 /*
877 ** Function to return the number of seconds since 1970. This is
@@ -1793,11 +1825,11 @@
1793 /*
1794 ** Returns non-zero if the default value for the "allow-symlinks" setting
1795 ** is "on". When on Windows, this always returns false.
1796 */
1797 int db_allow_symlinks_by_default(void){
1798 #if defined(_WIN32)
1799 return 0;
1800 #else
1801 return 1;
1802 #endif
1803 }
@@ -2086,10 +2118,11 @@
2086 ** argument is true. Ignore unfinalized statements when false.
2087 */
2088 void db_close(int reportErrors){
2089 sqlite3_stmt *pStmt;
2090 if( g.db==0 ) return;
 
2091 if( g.fSqlStats ){
2092 int cur, hiwtr;
2093 sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_USED, &cur, &hiwtr, 0);
2094 fprintf(stderr, "-- LOOKASIDE_USED %10d %10d\n", cur, hiwtr);
2095 sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &cur, &hiwtr, 0);
@@ -2115,17 +2148,20 @@
2115 fprintf(stderr, "-- prepared statements %10d\n", db.nPrepare);
2116 }
2117 while( db.pAllStmt ){
2118 db_finalize(db.pAllStmt);
2119 }
2120 if( db.nBegin && reportErrors ){
2121 fossil_warning("Transaction started at %s:%d never commits",
2122 db.zStartFile, db.iStartLine);
 
 
2123 db_end_transaction(1);
2124 }
2125 pStmt = 0;
2126 g.dbIgnoreErrors++; /* Stop "database locked" warnings from PRAGMA optimize */
 
2127 sqlite3_exec(g.db, "PRAGMA optimize", 0, 0, 0);
2128 g.dbIgnoreErrors--;
2129 db_close_config();
2130
2131 /* If the localdb has a lot of unused free space,
@@ -2165,10 +2201,11 @@
2165 if( g.db ){
2166 int rc;
2167 sqlite3_wal_checkpoint(g.db, 0);
2168 rc = sqlite3_close(g.db);
2169 if( g.fSqlTrace ) fossil_trace("-- sqlite3_close(%d)\n", rc);
 
2170 }
2171 g.db = 0;
2172 g.repositoryOpen = 0;
2173 g.localOpen = 0;
2174 }
@@ -2919,17 +2956,19 @@
2919 dflt = 0;
2920 }
2921 fossil_free(zVal);
2922 return dflt;
2923 }
 
2924 int db_get_versioned_boolean(const char *zName, int dflt){
2925 char *zVal = db_get_versioned(zName, 0);
2926 if( zVal==0 ) return dflt;
2927 if( is_truth(zVal) ) return 1;
2928 if( is_false(zVal) ) return 0;
2929 return dflt;
2930 }
 
2931 char *db_lget(const char *zName, const char *zDefault){
2932 return db_text(zDefault,
2933 "SELECT value FROM vvar WHERE name=%Q", zName);
2934 }
2935 void db_lset(const char *zName, const char *zValue){
@@ -3128,11 +3167,13 @@
3128 void cmd_open(void){
3129 int emptyFlag;
3130 int keepFlag;
3131 int forceMissingFlag;
3132 int allowNested;
 
3133 int allowSymlinks;
 
3134 int setmtimeFlag; /* --setmtime. Set mtimes on files */
3135 int bForce = 0; /* --force. Open even if non-empty dir */
3136 static char *azNewArgv[] = { 0, "checkout", "--prompt", 0, 0, 0, 0 };
3137 const char *zWorkDir; /* --workdir value */
3138 const char *zRepo = 0; /* Name of the repository file */
@@ -3239,10 +3280,11 @@
3239 }else if( db_exists("SELECT 1 FROM event WHERE type='ci'") ){
3240 g.zOpenRevision = db_get("main-branch", 0);
3241 }
3242 }
3243
 
3244 if( g.zOpenRevision ){
3245 /* Since the repository is open and we know the revision now,
3246 ** refresh the allow-symlinks flag. Since neither the local
3247 ** checkout nor the configuration database are open at this
3248 ** point, this should always return the versioned setting,
@@ -3252,10 +3294,11 @@
3252 ** repository or global configuration databases only. */
3253 allowSymlinks = db_get_versioned_boolean("allow-symlinks", -1);
3254 }else{
3255 allowSymlinks = -1; /* Use non-versioned settings only. */
3256 }
 
3257
3258 #if defined(_WIN32) || defined(__CYGWIN__)
3259 # define LOCALDB_NAME "./_FOSSIL_"
3260 #else
3261 # define LOCALDB_NAME "./.fslckout"
@@ -3265,10 +3308,11 @@
3265 "COMMIT; PRAGMA journal_mode=WAL; BEGIN;",
3266 #endif
3267 (char*)0);
3268 db_delete_on_failure(LOCALDB_NAME);
3269 db_open_local(0);
 
3270 if( allowSymlinks>=0 ){
3271 /* Use the value from the versioned setting, which was read
3272 ** prior to opening the local checkout (i.e. which is most
3273 ** likely empty and does not actually contain any versioned
3274 ** setting files yet). Normally, this value would be given
@@ -3281,10 +3325,11 @@
3281 ** point, this will probably be the setting value from the
3282 ** repository or global configuration databases. */
3283 g.allowSymlinks = db_get_boolean("allow-symlinks",
3284 db_allow_symlinks_by_default());
3285 }
 
3286 db_lset("repository", zRepo);
3287 db_record_repository_filename(zRepo);
3288 db_set_checkout(0);
3289 azNewArgv[0] = g.argv[0];
3290 g.argv = azNewArgv;
@@ -3392,11 +3437,29 @@
3392 ** SETTING: admin-log boolean default=off
3393 **
3394 ** When the admin-log setting is enabled, configuration changes are recorded
3395 ** in the "admin_log" table of the repository.
3396 */
3397 #if defined(_WIN32)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3398 /*
3399 ** SETTING: allow-symlinks boolean default=off versionable
3400 **
3401 ** When allow-symlinks is OFF, symbolic links in the repository are followed
3402 ** and treated no differently from real files. When allow-symlinks is ON,
@@ -3403,11 +3466,11 @@
3403 ** the object to which the symbolic link points is ignored, and the content
3404 ** of the symbolic link that is stored in the repository is the name of the
3405 ** object to which the symbolic link points.
3406 */
3407 #endif
3408 #if !defined(_WIN32)
3409 /*
3410 ** SETTING: allow-symlinks boolean default=on versionable
3411 **
3412 ** When allow-symlinks is OFF, symbolic links in the repository are followed
3413 ** and treated no differently from real files. When allow-symlinks is ON,
3414
--- src/db.c
+++ src/db.c
@@ -130,10 +130,13 @@
130 char *azBeforeCommit[5]; /* Commands to run prior to COMMIT */
131 int nBeforeCommit; /* Number of entries in azBeforeCommit */
132 int nPriorChanges; /* sqlite3_total_changes() at transaction start */
133 const char *zStartFile; /* File in which transaction was started */
134 int iStartLine; /* Line of zStartFile where transaction started */
135 int (*xAuth)(void*,int,const char*,const char*,const char*,const char*);
136 void *pAuthArg; /* Argument to the authorizer */
137 const char *zAuthName; /* Name of the authorizer */
138 } db = {0, 0, 0, 0, 0, 0, };
139
140 /*
141 ** Arrange for the given file to be deleted on a failure.
142 */
@@ -316,10 +319,36 @@
319 }
320 db.aHook[db.nCommitHook].sequence = sequence;
321 db.aHook[db.nCommitHook].xHook = x;
322 db.nCommitHook++;
323 }
324
325 /*
326 ** Set or unset the query authorizer callback function
327 */
328 void db_set_authorizer(
329 int(*xAuth)(void*,int,const char*,const char*,const char*,const char*),
330 void *pArg,
331 const char *zName /* for tracing */
332 ){
333 if( db.xAuth ){
334 fossil_panic("multiple active db_set_authorizer() calls");
335 }
336 if( g.db ) sqlite3_set_authorizer(g.db, xAuth, pArg);
337 db.xAuth = xAuth;
338 db.pAuthArg = pArg;
339 db.zAuthName = zName;
340 if( g.fSqlTrace ) fossil_trace("-- set authorizer %s\n", zName);
341 }
342 void db_clear_authorizer(void){
343 if( db.zAuthName && g.fSqlTrace ){
344 fossil_trace("-- discontinue authorizer %s\n", db.zAuthName);
345 }
346 if( g.db ) sqlite3_set_authorizer(g.db, 0, 0);
347 db.xAuth = 0;
348 db.pAuthArg = 0;
349 }
350
351 #if INTERFACE
352 /*
353 ** Possible flags to db_vprepare
354 */
@@ -844,34 +873,37 @@
873 void db_init_database(
874 const char *zFileName, /* Name of database file to create */
875 const char *zSchema, /* First part of schema */
876 ... /* Additional SQL to run. Terminate with NULL. */
877 ){
878 sqlite3 *xdb;
879 int rc;
880 const char *zSql;
881 va_list ap;
882
883 xdb = db_open(zFileName ? zFileName : ":memory:");
884 sqlite3_exec(xdb, "BEGIN EXCLUSIVE", 0, 0, 0);
885 if( db.xAuth ){
886 sqlite3_set_authorizer(xdb, db.xAuth, db.pAuthArg);
887 }
888 rc = sqlite3_exec(xdb, zSchema, 0, 0, 0);
889 if( rc!=SQLITE_OK ){
890 db_err("%s", sqlite3_errmsg(xdb));
891 }
892 va_start(ap, zSchema);
893 while( (zSql = va_arg(ap, const char*))!=0 ){
894 rc = sqlite3_exec(xdb, zSql, 0, 0, 0);
895 if( rc!=SQLITE_OK ){
896 db_err("%s", sqlite3_errmsg(xdb));
897 }
898 }
899 va_end(ap);
900 sqlite3_exec(xdb, "COMMIT", 0, 0, 0);
901 if( zFileName || g.db!=0 ){
902 sqlite3_close(xdb);
903 }else{
904 g.db = xdb;
905 }
906 }
907
908 /*
909 ** Function to return the number of seconds since 1970. This is
@@ -1793,11 +1825,11 @@
1825 /*
1826 ** Returns non-zero if the default value for the "allow-symlinks" setting
1827 ** is "on". When on Windows, this always returns false.
1828 */
1829 int db_allow_symlinks_by_default(void){
1830 #if defined(_WIN32) || !defined(FOSSIL_LEGACY_ALLOW_SYMLINKS)
1831 return 0;
1832 #else
1833 return 1;
1834 #endif
1835 }
@@ -2086,10 +2118,11 @@
2118 ** argument is true. Ignore unfinalized statements when false.
2119 */
2120 void db_close(int reportErrors){
2121 sqlite3_stmt *pStmt;
2122 if( g.db==0 ) return;
2123 sqlite3_set_authorizer(g.db, 0, 0);
2124 if( g.fSqlStats ){
2125 int cur, hiwtr;
2126 sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_USED, &cur, &hiwtr, 0);
2127 fprintf(stderr, "-- LOOKASIDE_USED %10d %10d\n", cur, hiwtr);
2128 sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &cur, &hiwtr, 0);
@@ -2115,17 +2148,20 @@
2148 fprintf(stderr, "-- prepared statements %10d\n", db.nPrepare);
2149 }
2150 while( db.pAllStmt ){
2151 db_finalize(db.pAllStmt);
2152 }
2153 if( db.nBegin ){
2154 if( reportErrors ){
2155 fossil_warning("Transaction started at %s:%d never commits",
2156 db.zStartFile, db.iStartLine);
2157 }
2158 db_end_transaction(1);
2159 }
2160 pStmt = 0;
2161 sqlite3_busy_timeout(g.db, 0);
2162 g.dbIgnoreErrors++; /* Stop "database locked" warnings */
2163 sqlite3_exec(g.db, "PRAGMA optimize", 0, 0, 0);
2164 g.dbIgnoreErrors--;
2165 db_close_config();
2166
2167 /* If the localdb has a lot of unused free space,
@@ -2165,10 +2201,11 @@
2201 if( g.db ){
2202 int rc;
2203 sqlite3_wal_checkpoint(g.db, 0);
2204 rc = sqlite3_close(g.db);
2205 if( g.fSqlTrace ) fossil_trace("-- sqlite3_close(%d)\n", rc);
2206 db_clear_authorizer();
2207 }
2208 g.db = 0;
2209 g.repositoryOpen = 0;
2210 g.localOpen = 0;
2211 }
@@ -2919,17 +2956,19 @@
2956 dflt = 0;
2957 }
2958 fossil_free(zVal);
2959 return dflt;
2960 }
2961 #ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
2962 int db_get_versioned_boolean(const char *zName, int dflt){
2963 char *zVal = db_get_versioned(zName, 0);
2964 if( zVal==0 ) return dflt;
2965 if( is_truth(zVal) ) return 1;
2966 if( is_false(zVal) ) return 0;
2967 return dflt;
2968 }
2969 #endif /* FOSSIL_LEGACY_ALLOW_SYMLINKS */
2970 char *db_lget(const char *zName, const char *zDefault){
2971 return db_text(zDefault,
2972 "SELECT value FROM vvar WHERE name=%Q", zName);
2973 }
2974 void db_lset(const char *zName, const char *zValue){
@@ -3128,11 +3167,13 @@
3167 void cmd_open(void){
3168 int emptyFlag;
3169 int keepFlag;
3170 int forceMissingFlag;
3171 int allowNested;
3172 #ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
3173 int allowSymlinks;
3174 #endif
3175 int setmtimeFlag; /* --setmtime. Set mtimes on files */
3176 int bForce = 0; /* --force. Open even if non-empty dir */
3177 static char *azNewArgv[] = { 0, "checkout", "--prompt", 0, 0, 0, 0 };
3178 const char *zWorkDir; /* --workdir value */
3179 const char *zRepo = 0; /* Name of the repository file */
@@ -3239,10 +3280,11 @@
3280 }else if( db_exists("SELECT 1 FROM event WHERE type='ci'") ){
3281 g.zOpenRevision = db_get("main-branch", 0);
3282 }
3283 }
3284
3285 #ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
3286 if( g.zOpenRevision ){
3287 /* Since the repository is open and we know the revision now,
3288 ** refresh the allow-symlinks flag. Since neither the local
3289 ** checkout nor the configuration database are open at this
3290 ** point, this should always return the versioned setting,
@@ -3252,10 +3294,11 @@
3294 ** repository or global configuration databases only. */
3295 allowSymlinks = db_get_versioned_boolean("allow-symlinks", -1);
3296 }else{
3297 allowSymlinks = -1; /* Use non-versioned settings only. */
3298 }
3299 #endif
3300
3301 #if defined(_WIN32) || defined(__CYGWIN__)
3302 # define LOCALDB_NAME "./_FOSSIL_"
3303 #else
3304 # define LOCALDB_NAME "./.fslckout"
@@ -3265,10 +3308,11 @@
3308 "COMMIT; PRAGMA journal_mode=WAL; BEGIN;",
3309 #endif
3310 (char*)0);
3311 db_delete_on_failure(LOCALDB_NAME);
3312 db_open_local(0);
3313 #ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
3314 if( allowSymlinks>=0 ){
3315 /* Use the value from the versioned setting, which was read
3316 ** prior to opening the local checkout (i.e. which is most
3317 ** likely empty and does not actually contain any versioned
3318 ** setting files yet). Normally, this value would be given
@@ -3281,10 +3325,11 @@
3325 ** point, this will probably be the setting value from the
3326 ** repository or global configuration databases. */
3327 g.allowSymlinks = db_get_boolean("allow-symlinks",
3328 db_allow_symlinks_by_default());
3329 }
3330 #endif /* FOSSIL_LEGACY_ALLOW_SYMLINKS */
3331 db_lset("repository", zRepo);
3332 db_record_repository_filename(zRepo);
3333 db_set_checkout(0);
3334 azNewArgv[0] = g.argv[0];
3335 g.argv = azNewArgv;
@@ -3392,11 +3437,29 @@
3437 ** SETTING: admin-log boolean default=off
3438 **
3439 ** When the admin-log setting is enabled, configuration changes are recorded
3440 ** in the "admin_log" table of the repository.
3441 */
3442 #if !defined(FOSSIL_LEGACY_ALLOW_SYMLINKS)
3443 /*
3444 ** SETTING: allow-symlinks boolean default=off
3445 **
3446 ** When allow-symlinks is OFF (which is the default and recommended setting)
3447 ** symbolic links are treated like text files that contain a single line of
3448 ** content which is the name of their target. If allow-symlinks is ON,
3449 ** the symbolic links are actually followed.
3450 **
3451 ** The use of symbolic links is dangerous. If you checkout a maliciously
3452 ** crafted checkin that contains symbolic links, it is possible that files
3453 ** outside of the working directory might be overwritten.
3454 **
3455 ** Keep this setting OFF unless you have a very good reason to turn it
3456 ** on and you implicitly trust the integrity of the repositories you
3457 ** open.
3458 */
3459 #endif
3460 #if defined(_WIN32) && defined(FOSSIL_LEGACY_ALLOW_SYMLINKS)
3461 /*
3462 ** SETTING: allow-symlinks boolean default=off versionable
3463 **
3464 ** When allow-symlinks is OFF, symbolic links in the repository are followed
3465 ** and treated no differently from real files. When allow-symlinks is ON,
@@ -3403,11 +3466,11 @@
3466 ** the object to which the symbolic link points is ignored, and the content
3467 ** of the symbolic link that is stored in the repository is the name of the
3468 ** object to which the symbolic link points.
3469 */
3470 #endif
3471 #if !defined(_WIN32) && defined(FOSSIL_LEGACY_ALLOW_SYMLINKS)
3472 /*
3473 ** SETTING: allow-symlinks boolean default=on versionable
3474 **
3475 ** When allow-symlinks is OFF, symbolic links in the repository are followed
3476 ** and treated no differently from real files. When allow-symlinks is ON,
3477
+159 -1
--- src/file.c
+++ src/file.c
@@ -323,10 +323,82 @@
323323
** On Windows, always return False.
324324
*/
325325
int file_islink(const char *zFilename){
326326
return file_perm(zFilename, RepoFILE)==PERM_LNK;
327327
}
328
+
329
+/*
330
+** Check every sub-directory of zRoot along the path to zFile.
331
+** If any sub-directory is really an ordinary file or a symbolic link,
332
+** return an integer which is the length of the prefix of zFile which
333
+** is the name of that object. Return 0 if all no non-directory
334
+** objects are found along the path.
335
+**
336
+** Example: Given inputs
337
+**
338
+** zRoot = /home/alice/project1
339
+** zFile = /home/alice/project1/main/src/js/fileA.js
340
+**
341
+** Look for objects in the following order:
342
+**
343
+** /home/alice/project/main
344
+** /home/alice/project/main/src
345
+** /home/alice/project/main/src/js
346
+**
347
+** If any of those objects exist and are something other than a directory
348
+** then return the length of the name of the first non-directory object
349
+** seen.
350
+*/
351
+int file_nondir_objects_on_path(const char *zRoot, const char *zFile){
352
+ int i = (int)strlen(zRoot);
353
+ char *z = fossil_strdup(zFile);
354
+ assert( fossil_strnicmp(zRoot, z, i)==0 );
355
+ if( i && zRoot[i-1]=='/' ) i--;
356
+ while( z[i]=='/' ){
357
+ int j, rc;
358
+ for(j=i+1; z[j] && z[j]!='/'; j++){}
359
+ if( z[j]!='/' ) break;
360
+ z[j] = 0;
361
+ rc = file_isdir(z, SymFILE);
362
+ if( rc!=1 ){
363
+ if( rc==2 ){
364
+ fossil_free(z);
365
+ return j;
366
+ }
367
+ break;
368
+ }
369
+ z[j] = '/';
370
+ i = j;
371
+ }
372
+ fossil_free(z);
373
+ return 0;
374
+}
375
+
376
+/*
377
+** The file named zFile is suppose to be an in-tree file. Check to
378
+** ensure that it will be safe to write to this file by verifying that
379
+** there are no symlinks or other non-directory objects in between the
380
+** root of the checkout and zFile.
381
+**
382
+** If a problem is found, print a warning message (using fossil_warning())
383
+** and return non-zero. If everything is ok, return zero.
384
+*/
385
+int file_unsafe_in_tree_path(const char *zFile){
386
+ int n;
387
+ if( !file_is_absolute_path(zFile) ){
388
+ fossil_panic("%s is not an absolute pathname",zFile);
389
+ }
390
+ if( fossil_strnicmp(g.zLocalRoot, zFile, (int)strlen(g.zLocalRoot)) ){
391
+ fossil_panic("%s is not a prefix of %s", g.zLocalRoot, zFile);
392
+ }
393
+ n = file_nondir_objects_on_path(g.zLocalRoot, zFile);
394
+ if( n ){
395
+ fossil_warning("cannot write to %s because non-directory object %.*s"
396
+ " is in the way", zFile, n, zFile);
397
+ }
398
+ return n;
399
+}
328400
329401
/*
330402
** Return 1 if zFilename is a directory. Return 0 if zFilename
331403
** does not exist. Return 2 if zFilename exists but is something
332404
** other than a directory.
@@ -570,11 +642,14 @@
570642
*/
571643
int file_setexe(const char *zFilename, int onoff){
572644
int rc = 0;
573645
#if !defined(_WIN32)
574646
struct stat buf;
575
- if( fossil_stat(zFilename, &buf, RepoFILE)!=0 || S_ISLNK(buf.st_mode) ){
647
+ if( fossil_stat(zFilename, &buf, RepoFILE)!=0
648
+ || S_ISLNK(buf.st_mode)
649
+ || S_ISDIR(buf.st_mode)
650
+ ){
576651
return 0;
577652
}
578653
if( onoff ){
579654
int targetMode = (buf.st_mode & 0444)>>2;
580655
if( (buf.st_mode & 0100)==0 ){
@@ -2397,5 +2472,88 @@
23972472
changeCount);
23982473
}else{
23992474
fossil_print("Touched %d file(s)\n", changeCount);
24002475
}
24012476
}
2477
+
2478
+/*
2479
+** Returns non-zero if the specified file name ends with any reserved name,
2480
+** e.g.: _FOSSIL_ or .fslckout. Specifically, it returns 1 for exact match
2481
+** or 2 for a tail match on a longer file name.
2482
+**
2483
+** For the sake of efficiency, zFilename must be a canonical name, e.g. an
2484
+** absolute path using only forward slash ('/') as a directory separator.
2485
+**
2486
+** nFilename must be the length of zFilename. When negative, strlen() will
2487
+** be used to calculate it.
2488
+*/
2489
+int file_is_reserved_name(const char *zFilename, int nFilename){
2490
+ const char *zEnd; /* one-after-the-end of zFilename */
2491
+ int gotSuffix = 0; /* length of suffix (-wal, -shm, -journal) */
2492
+
2493
+ assert( zFilename && "API misuse" );
2494
+ if( nFilename<0 ) nFilename = (int)strlen(zFilename);
2495
+ if( nFilename<8 ) return 0; /* strlen("_FOSSIL_") */
2496
+ zEnd = zFilename + nFilename;
2497
+ if( nFilename>=12 ){ /* strlen("_FOSSIL_-(shm|wal)") */
2498
+ /* Check for (-wal, -shm, -journal) suffixes, with an eye towards
2499
+ ** runtime speed. */
2500
+ if( zEnd[-4]=='-' ){
2501
+ if( fossil_strnicmp("wal", &zEnd[-3], 3)
2502
+ && fossil_strnicmp("shm", &zEnd[-3], 3) ){
2503
+ return 0;
2504
+ }
2505
+ gotSuffix = 4;
2506
+ }else if( nFilename>=16 && zEnd[-8]=='-' ){ /*strlen(_FOSSIL_-journal) */
2507
+ if( fossil_strnicmp("journal", &zEnd[-7], 7) ) return 0;
2508
+ gotSuffix = 8;
2509
+ }
2510
+ if( gotSuffix ){
2511
+ assert( 4==gotSuffix || 8==gotSuffix );
2512
+ zEnd -= gotSuffix;
2513
+ nFilename -= gotSuffix;
2514
+ gotSuffix = 1;
2515
+ }
2516
+ assert( nFilename>=8 && "strlen(_FOSSIL_)" );
2517
+ assert( gotSuffix==0 || gotSuffix==1 );
2518
+ }
2519
+ switch( zEnd[-1] ){
2520
+ case '_':{
2521
+ if( fossil_strnicmp("_FOSSIL_", &zEnd[-8], 8) ) return 0;
2522
+ if( 8==nFilename ) return 1;
2523
+ return zEnd[-9]=='/' ? 2 : gotSuffix;
2524
+ }
2525
+ case 'T':
2526
+ case 't':{
2527
+ if( nFilename<9 || zEnd[-9]!='.'
2528
+ || fossil_strnicmp(".fslckout", &zEnd[-9], 9) ){
2529
+ return 0;
2530
+ }
2531
+ if( 9==nFilename ) return 1;
2532
+ return zEnd[-10]=='/' ? 2 : gotSuffix;
2533
+ }
2534
+ default:{
2535
+ return 0;
2536
+ }
2537
+ }
2538
+}
2539
+
2540
+/*
2541
+** COMMAND: test-is-reserved-name
2542
+**
2543
+** Usage: %fossil test-is-ckout-db FILENAMES...
2544
+**
2545
+** Passes each given name to file_is_reserved_name() and outputs one
2546
+** line per file: the result value of that function followed by the
2547
+** name.
2548
+*/
2549
+void test_is_reserved_name_cmd(void){
2550
+ int i;
2551
+
2552
+ if(g.argc<3){
2553
+ usage("FILENAME_1 [...FILENAME_N]");
2554
+ }
2555
+ for( i = 2; i < g.argc; ++i ){
2556
+ const int check = file_is_reserved_name(g.argv[i], -1);
2557
+ fossil_print("%d %s\n", check, g.argv[i]);
2558
+ }
2559
+}
24022560
--- src/file.c
+++ src/file.c
@@ -323,10 +323,82 @@
323 ** On Windows, always return False.
324 */
325 int file_islink(const char *zFilename){
326 return file_perm(zFilename, RepoFILE)==PERM_LNK;
327 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
328
329 /*
330 ** Return 1 if zFilename is a directory. Return 0 if zFilename
331 ** does not exist. Return 2 if zFilename exists but is something
332 ** other than a directory.
@@ -570,11 +642,14 @@
570 */
571 int file_setexe(const char *zFilename, int onoff){
572 int rc = 0;
573 #if !defined(_WIN32)
574 struct stat buf;
575 if( fossil_stat(zFilename, &buf, RepoFILE)!=0 || S_ISLNK(buf.st_mode) ){
 
 
 
576 return 0;
577 }
578 if( onoff ){
579 int targetMode = (buf.st_mode & 0444)>>2;
580 if( (buf.st_mode & 0100)==0 ){
@@ -2397,5 +2472,88 @@
2397 changeCount);
2398 }else{
2399 fossil_print("Touched %d file(s)\n", changeCount);
2400 }
2401 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2402
--- src/file.c
+++ src/file.c
@@ -323,10 +323,82 @@
323 ** On Windows, always return False.
324 */
325 int file_islink(const char *zFilename){
326 return file_perm(zFilename, RepoFILE)==PERM_LNK;
327 }
328
329 /*
330 ** Check every sub-directory of zRoot along the path to zFile.
331 ** If any sub-directory is really an ordinary file or a symbolic link,
332 ** return an integer which is the length of the prefix of zFile which
333 ** is the name of that object. Return 0 if all no non-directory
334 ** objects are found along the path.
335 **
336 ** Example: Given inputs
337 **
338 ** zRoot = /home/alice/project1
339 ** zFile = /home/alice/project1/main/src/js/fileA.js
340 **
341 ** Look for objects in the following order:
342 **
343 ** /home/alice/project/main
344 ** /home/alice/project/main/src
345 ** /home/alice/project/main/src/js
346 **
347 ** If any of those objects exist and are something other than a directory
348 ** then return the length of the name of the first non-directory object
349 ** seen.
350 */
351 int file_nondir_objects_on_path(const char *zRoot, const char *zFile){
352 int i = (int)strlen(zRoot);
353 char *z = fossil_strdup(zFile);
354 assert( fossil_strnicmp(zRoot, z, i)==0 );
355 if( i && zRoot[i-1]=='/' ) i--;
356 while( z[i]=='/' ){
357 int j, rc;
358 for(j=i+1; z[j] && z[j]!='/'; j++){}
359 if( z[j]!='/' ) break;
360 z[j] = 0;
361 rc = file_isdir(z, SymFILE);
362 if( rc!=1 ){
363 if( rc==2 ){
364 fossil_free(z);
365 return j;
366 }
367 break;
368 }
369 z[j] = '/';
370 i = j;
371 }
372 fossil_free(z);
373 return 0;
374 }
375
376 /*
377 ** The file named zFile is suppose to be an in-tree file. Check to
378 ** ensure that it will be safe to write to this file by verifying that
379 ** there are no symlinks or other non-directory objects in between the
380 ** root of the checkout and zFile.
381 **
382 ** If a problem is found, print a warning message (using fossil_warning())
383 ** and return non-zero. If everything is ok, return zero.
384 */
385 int file_unsafe_in_tree_path(const char *zFile){
386 int n;
387 if( !file_is_absolute_path(zFile) ){
388 fossil_panic("%s is not an absolute pathname",zFile);
389 }
390 if( fossil_strnicmp(g.zLocalRoot, zFile, (int)strlen(g.zLocalRoot)) ){
391 fossil_panic("%s is not a prefix of %s", g.zLocalRoot, zFile);
392 }
393 n = file_nondir_objects_on_path(g.zLocalRoot, zFile);
394 if( n ){
395 fossil_warning("cannot write to %s because non-directory object %.*s"
396 " is in the way", zFile, n, zFile);
397 }
398 return n;
399 }
400
401 /*
402 ** Return 1 if zFilename is a directory. Return 0 if zFilename
403 ** does not exist. Return 2 if zFilename exists but is something
404 ** other than a directory.
@@ -570,11 +642,14 @@
642 */
643 int file_setexe(const char *zFilename, int onoff){
644 int rc = 0;
645 #if !defined(_WIN32)
646 struct stat buf;
647 if( fossil_stat(zFilename, &buf, RepoFILE)!=0
648 || S_ISLNK(buf.st_mode)
649 || S_ISDIR(buf.st_mode)
650 ){
651 return 0;
652 }
653 if( onoff ){
654 int targetMode = (buf.st_mode & 0444)>>2;
655 if( (buf.st_mode & 0100)==0 ){
@@ -2397,5 +2472,88 @@
2472 changeCount);
2473 }else{
2474 fossil_print("Touched %d file(s)\n", changeCount);
2475 }
2476 }
2477
2478 /*
2479 ** Returns non-zero if the specified file name ends with any reserved name,
2480 ** e.g.: _FOSSIL_ or .fslckout. Specifically, it returns 1 for exact match
2481 ** or 2 for a tail match on a longer file name.
2482 **
2483 ** For the sake of efficiency, zFilename must be a canonical name, e.g. an
2484 ** absolute path using only forward slash ('/') as a directory separator.
2485 **
2486 ** nFilename must be the length of zFilename. When negative, strlen() will
2487 ** be used to calculate it.
2488 */
2489 int file_is_reserved_name(const char *zFilename, int nFilename){
2490 const char *zEnd; /* one-after-the-end of zFilename */
2491 int gotSuffix = 0; /* length of suffix (-wal, -shm, -journal) */
2492
2493 assert( zFilename && "API misuse" );
2494 if( nFilename<0 ) nFilename = (int)strlen(zFilename);
2495 if( nFilename<8 ) return 0; /* strlen("_FOSSIL_") */
2496 zEnd = zFilename + nFilename;
2497 if( nFilename>=12 ){ /* strlen("_FOSSIL_-(shm|wal)") */
2498 /* Check for (-wal, -shm, -journal) suffixes, with an eye towards
2499 ** runtime speed. */
2500 if( zEnd[-4]=='-' ){
2501 if( fossil_strnicmp("wal", &zEnd[-3], 3)
2502 && fossil_strnicmp("shm", &zEnd[-3], 3) ){
2503 return 0;
2504 }
2505 gotSuffix = 4;
2506 }else if( nFilename>=16 && zEnd[-8]=='-' ){ /*strlen(_FOSSIL_-journal) */
2507 if( fossil_strnicmp("journal", &zEnd[-7], 7) ) return 0;
2508 gotSuffix = 8;
2509 }
2510 if( gotSuffix ){
2511 assert( 4==gotSuffix || 8==gotSuffix );
2512 zEnd -= gotSuffix;
2513 nFilename -= gotSuffix;
2514 gotSuffix = 1;
2515 }
2516 assert( nFilename>=8 && "strlen(_FOSSIL_)" );
2517 assert( gotSuffix==0 || gotSuffix==1 );
2518 }
2519 switch( zEnd[-1] ){
2520 case '_':{
2521 if( fossil_strnicmp("_FOSSIL_", &zEnd[-8], 8) ) return 0;
2522 if( 8==nFilename ) return 1;
2523 return zEnd[-9]=='/' ? 2 : gotSuffix;
2524 }
2525 case 'T':
2526 case 't':{
2527 if( nFilename<9 || zEnd[-9]!='.'
2528 || fossil_strnicmp(".fslckout", &zEnd[-9], 9) ){
2529 return 0;
2530 }
2531 if( 9==nFilename ) return 1;
2532 return zEnd[-10]=='/' ? 2 : gotSuffix;
2533 }
2534 default:{
2535 return 0;
2536 }
2537 }
2538 }
2539
2540 /*
2541 ** COMMAND: test-is-reserved-name
2542 **
2543 ** Usage: %fossil test-is-ckout-db FILENAMES...
2544 **
2545 ** Passes each given name to file_is_reserved_name() and outputs one
2546 ** line per file: the result value of that function followed by the
2547 ** name.
2548 */
2549 void test_is_reserved_name_cmd(void){
2550 int i;
2551
2552 if(g.argc<3){
2553 usage("FILENAME_1 [...FILENAME_N]");
2554 }
2555 for( i = 2; i < g.argc; ++i ){
2556 const int check = file_is_reserved_name(g.argv[i], -1);
2557 fossil_print("%d %s\n", check, g.argv[i]);
2558 }
2559 }
2560
+10 -1
--- src/http.c
+++ src/http.c
@@ -375,17 +375,26 @@
375375
j -= 4;
376376
zLine[j] = 0;
377377
}
378378
if( (mHttpFlags & HTTP_QUIET)==0 ){
379379
fossil_print("redirect with status %d to %s\n", rc, &zLine[i]);
380
+ }
381
+ if( g.url.isFile || g.url.isSsh ){
382
+ fossil_warning("cannot redirect from %s to %s", g.url.canonical,
383
+ &zLine[i]);
384
+ goto write_err;
380385
}
381386
wasHttps = g.url.isHttps;
382387
url_parse(&zLine[i], 0);
383388
if( wasHttps && !g.url.isHttps ){
384389
fossil_warning("cannot redirect from HTTPS to HTTP");
385390
goto write_err;
386
- }
391
+ }
392
+ if( g.url.isSsh || g.url.isFile ){
393
+ fossil_warning("cannot redirect to %s", &zLine[i]);
394
+ goto write_err;
395
+ }
387396
transport_close(&g.url);
388397
transport_global_shutdown(&g.url);
389398
fSeenHttpAuth = 0;
390399
if( g.zHttpAuth ) free(g.zHttpAuth);
391400
g.zHttpAuth = get_httpauth();
392401
--- src/http.c
+++ src/http.c
@@ -375,17 +375,26 @@
375 j -= 4;
376 zLine[j] = 0;
377 }
378 if( (mHttpFlags & HTTP_QUIET)==0 ){
379 fossil_print("redirect with status %d to %s\n", rc, &zLine[i]);
 
 
 
 
 
380 }
381 wasHttps = g.url.isHttps;
382 url_parse(&zLine[i], 0);
383 if( wasHttps && !g.url.isHttps ){
384 fossil_warning("cannot redirect from HTTPS to HTTP");
385 goto write_err;
386 }
 
 
 
 
387 transport_close(&g.url);
388 transport_global_shutdown(&g.url);
389 fSeenHttpAuth = 0;
390 if( g.zHttpAuth ) free(g.zHttpAuth);
391 g.zHttpAuth = get_httpauth();
392
--- src/http.c
+++ src/http.c
@@ -375,17 +375,26 @@
375 j -= 4;
376 zLine[j] = 0;
377 }
378 if( (mHttpFlags & HTTP_QUIET)==0 ){
379 fossil_print("redirect with status %d to %s\n", rc, &zLine[i]);
380 }
381 if( g.url.isFile || g.url.isSsh ){
382 fossil_warning("cannot redirect from %s to %s", g.url.canonical,
383 &zLine[i]);
384 goto write_err;
385 }
386 wasHttps = g.url.isHttps;
387 url_parse(&zLine[i], 0);
388 if( wasHttps && !g.url.isHttps ){
389 fossil_warning("cannot redirect from HTTPS to HTTP");
390 goto write_err;
391 }
392 if( g.url.isSsh || g.url.isFile ){
393 fossil_warning("cannot redirect to %s", &zLine[i]);
394 goto write_err;
395 }
396 transport_close(&g.url);
397 transport_global_shutdown(&g.url);
398 fSeenHttpAuth = 0;
399 if( g.zHttpAuth ) free(g.zHttpAuth);
400 g.zHttpAuth = get_httpauth();
401
--- src/json_config.c
+++ src/json_config.c
@@ -83,11 +83,13 @@
8383
{ "keep-glob", CONFIGSET_PROJ },
8484
{ "crlf-glob", CONFIGSET_PROJ },
8585
{ "crnl-glob", CONFIGSET_PROJ },
8686
{ "encoding-glob", CONFIGSET_PROJ },
8787
{ "empty-dirs", CONFIGSET_PROJ },
88
+#ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
8889
{ "allow-symlinks", CONFIGSET_PROJ },
90
+#endif
8991
{ "dotfiles", CONFIGSET_PROJ },
9092
9193
{ "ticket-table", CONFIGSET_TKT },
9294
{ "ticket-common", CONFIGSET_TKT },
9395
{ "ticket-change", CONFIGSET_TKT },
9496
--- src/json_config.c
+++ src/json_config.c
@@ -83,11 +83,13 @@
83 { "keep-glob", CONFIGSET_PROJ },
84 { "crlf-glob", CONFIGSET_PROJ },
85 { "crnl-glob", CONFIGSET_PROJ },
86 { "encoding-glob", CONFIGSET_PROJ },
87 { "empty-dirs", CONFIGSET_PROJ },
 
88 { "allow-symlinks", CONFIGSET_PROJ },
 
89 { "dotfiles", CONFIGSET_PROJ },
90
91 { "ticket-table", CONFIGSET_TKT },
92 { "ticket-common", CONFIGSET_TKT },
93 { "ticket-change", CONFIGSET_TKT },
94
--- src/json_config.c
+++ src/json_config.c
@@ -83,11 +83,13 @@
83 { "keep-glob", CONFIGSET_PROJ },
84 { "crlf-glob", CONFIGSET_PROJ },
85 { "crnl-glob", CONFIGSET_PROJ },
86 { "encoding-glob", CONFIGSET_PROJ },
87 { "empty-dirs", CONFIGSET_PROJ },
88 #ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
89 { "allow-symlinks", CONFIGSET_PROJ },
90 #endif
91 { "dotfiles", CONFIGSET_PROJ },
92
93 { "ticket-table", CONFIGSET_TKT },
94 { "ticket-common", CONFIGSET_TKT },
95 { "ticket-change", CONFIGSET_TKT },
96
+3
--- src/main.c
+++ src/main.c
@@ -1227,10 +1227,13 @@
12271227
#if defined(FOSSIL_DYNAMIC_BUILD)
12281228
blob_append(pOut, "FOSSIL_DYNAMIC_BUILD\n", -1);
12291229
#else
12301230
blob_append(pOut, "FOSSIL_STATIC_BUILD\n", -1);
12311231
#endif
1232
+#if defined(FOSSIL_LEGACY_ALLOW_SYMLINKS)
1233
+ blob_append(pOut, "FOSSIL_LEGACY_ALLOW_SYMLINKS\n", -1);
1234
+#endif
12321235
#if defined(HAVE_PLEDGE)
12331236
blob_append(pOut, "HAVE_PLEDGE\n", -1);
12341237
#endif
12351238
#if defined(USE_MMAN_H)
12361239
blob_append(pOut, "USE_MMAN_H\n", -1);
12371240
--- src/main.c
+++ src/main.c
@@ -1227,10 +1227,13 @@
1227 #if defined(FOSSIL_DYNAMIC_BUILD)
1228 blob_append(pOut, "FOSSIL_DYNAMIC_BUILD\n", -1);
1229 #else
1230 blob_append(pOut, "FOSSIL_STATIC_BUILD\n", -1);
1231 #endif
 
 
 
1232 #if defined(HAVE_PLEDGE)
1233 blob_append(pOut, "HAVE_PLEDGE\n", -1);
1234 #endif
1235 #if defined(USE_MMAN_H)
1236 blob_append(pOut, "USE_MMAN_H\n", -1);
1237
--- src/main.c
+++ src/main.c
@@ -1227,10 +1227,13 @@
1227 #if defined(FOSSIL_DYNAMIC_BUILD)
1228 blob_append(pOut, "FOSSIL_DYNAMIC_BUILD\n", -1);
1229 #else
1230 blob_append(pOut, "FOSSIL_STATIC_BUILD\n", -1);
1231 #endif
1232 #if defined(FOSSIL_LEGACY_ALLOW_SYMLINKS)
1233 blob_append(pOut, "FOSSIL_LEGACY_ALLOW_SYMLINKS\n", -1);
1234 #endif
1235 #if defined(HAVE_PLEDGE)
1236 blob_append(pOut, "HAVE_PLEDGE\n", -1);
1237 #endif
1238 #if defined(USE_MMAN_H)
1239 blob_append(pOut, "USE_MMAN_H\n", -1);
1240
+21 -3
--- src/manifest.c
+++ src/manifest.c
@@ -481,14 +481,23 @@
481481
blob_appendf(pErr, "line 1 not recognized");
482482
return 0;
483483
}
484484
/* Then verify the Z-card.
485485
*/
486
+#if 1
487
+ /* Disable this ***ONLY*** (ONLY!) when testing hand-written inputs
488
+ for card-related syntax errors. */
486489
if( verify_z_card(z, n, pErr)==2 ){
487490
blob_reset(pContent);
488491
return 0;
489492
}
493
+#else
494
+#warning ACHTUNG - z-card check is disabled for testing purposes.
495
+ if(0 && verify_z_card(NULL, 0, NULL)){
496
+ /*avoid unused static func error*/
497
+ }
498
+#endif
490499
491500
/* Allocate a Manifest object to hold the parsed control artifact.
492501
*/
493502
p = fossil_malloc( sizeof(*p) );
494503
memset(p, 0, sizeof(*p));
@@ -601,10 +610,11 @@
601610
case 'E': {
602611
if( p->rEventDate>0.0 ) SYNTAX("more than one E-card");
603612
p->rEventDate = db_double(0.0,"SELECT julianday(%Q)", next_token(&x,0));
604613
if( p->rEventDate<=0.0 ) SYNTAX("malformed date on E-card");
605614
p->zEventId = next_token(&x, &sz);
615
+ if( p->zEventId==0 ) SYNTAX("missing hash on E-card");
606616
if( !hname_validate(p->zEventId, sz) ){
607617
SYNTAX("malformed hash on E-card");
608618
}
609619
p->type = CFTYPE_EVENT;
610620
break;
@@ -625,10 +635,11 @@
625635
if( !file_is_simple_pathname_nonstrict(zName) ){
626636
SYNTAX("F-card filename is not a simple path");
627637
}
628638
zUuid = next_token(&x, &sz);
629639
if( p->zBaseline==0 || zUuid!=0 ){
640
+ if( zUuid==0 ) SYNTAX("missing hash on F-card");
630641
if( !hname_validate(zUuid,sz) ){
631642
SYNTAX("F-card hash invalid");
632643
}
633644
}
634645
zPerm = next_token(&x,0);
@@ -643,17 +654,24 @@
643654
p->nFileAlloc = p->nFileAlloc*2 + 10;
644655
p->aFile = fossil_realloc(p->aFile,
645656
p->nFileAlloc*sizeof(p->aFile[0]) );
646657
}
647658
i = p->nFile++;
659
+ if( i>0 && fossil_strcmp(p->aFile[i-1].zName, zName)>=0 ){
660
+ SYNTAX("incorrect F-card sort order");
661
+ }
662
+ if( file_is_reserved_name(zName,-1) ){
663
+ /* If reserved names leaked into historical manifests due to
664
+ ** slack oversight by older versions of Fossil, simply ignore
665
+ ** those files */
666
+ p->nFile--;
667
+ break;
668
+ }
648669
p->aFile[i].zName = zName;
649670
p->aFile[i].zUuid = zUuid;
650671
p->aFile[i].zPerm = zPerm;
651672
p->aFile[i].zPrior = zPriorName;
652
- if( i>0 && fossil_strcmp(p->aFile[i-1].zName, zName)>=0 ){
653
- SYNTAX("incorrect F-card sort order");
654
- }
655673
p->type = CFTYPE_MANIFEST;
656674
break;
657675
}
658676
659677
/*
660678
--- src/manifest.c
+++ src/manifest.c
@@ -481,14 +481,23 @@
481 blob_appendf(pErr, "line 1 not recognized");
482 return 0;
483 }
484 /* Then verify the Z-card.
485 */
 
 
 
486 if( verify_z_card(z, n, pErr)==2 ){
487 blob_reset(pContent);
488 return 0;
489 }
 
 
 
 
 
 
490
491 /* Allocate a Manifest object to hold the parsed control artifact.
492 */
493 p = fossil_malloc( sizeof(*p) );
494 memset(p, 0, sizeof(*p));
@@ -601,10 +610,11 @@
601 case 'E': {
602 if( p->rEventDate>0.0 ) SYNTAX("more than one E-card");
603 p->rEventDate = db_double(0.0,"SELECT julianday(%Q)", next_token(&x,0));
604 if( p->rEventDate<=0.0 ) SYNTAX("malformed date on E-card");
605 p->zEventId = next_token(&x, &sz);
 
606 if( !hname_validate(p->zEventId, sz) ){
607 SYNTAX("malformed hash on E-card");
608 }
609 p->type = CFTYPE_EVENT;
610 break;
@@ -625,10 +635,11 @@
625 if( !file_is_simple_pathname_nonstrict(zName) ){
626 SYNTAX("F-card filename is not a simple path");
627 }
628 zUuid = next_token(&x, &sz);
629 if( p->zBaseline==0 || zUuid!=0 ){
 
630 if( !hname_validate(zUuid,sz) ){
631 SYNTAX("F-card hash invalid");
632 }
633 }
634 zPerm = next_token(&x,0);
@@ -643,17 +654,24 @@
643 p->nFileAlloc = p->nFileAlloc*2 + 10;
644 p->aFile = fossil_realloc(p->aFile,
645 p->nFileAlloc*sizeof(p->aFile[0]) );
646 }
647 i = p->nFile++;
 
 
 
 
 
 
 
 
 
 
648 p->aFile[i].zName = zName;
649 p->aFile[i].zUuid = zUuid;
650 p->aFile[i].zPerm = zPerm;
651 p->aFile[i].zPrior = zPriorName;
652 if( i>0 && fossil_strcmp(p->aFile[i-1].zName, zName)>=0 ){
653 SYNTAX("incorrect F-card sort order");
654 }
655 p->type = CFTYPE_MANIFEST;
656 break;
657 }
658
659 /*
660
--- src/manifest.c
+++ src/manifest.c
@@ -481,14 +481,23 @@
481 blob_appendf(pErr, "line 1 not recognized");
482 return 0;
483 }
484 /* Then verify the Z-card.
485 */
486 #if 1
487 /* Disable this ***ONLY*** (ONLY!) when testing hand-written inputs
488 for card-related syntax errors. */
489 if( verify_z_card(z, n, pErr)==2 ){
490 blob_reset(pContent);
491 return 0;
492 }
493 #else
494 #warning ACHTUNG - z-card check is disabled for testing purposes.
495 if(0 && verify_z_card(NULL, 0, NULL)){
496 /*avoid unused static func error*/
497 }
498 #endif
499
500 /* Allocate a Manifest object to hold the parsed control artifact.
501 */
502 p = fossil_malloc( sizeof(*p) );
503 memset(p, 0, sizeof(*p));
@@ -601,10 +610,11 @@
610 case 'E': {
611 if( p->rEventDate>0.0 ) SYNTAX("more than one E-card");
612 p->rEventDate = db_double(0.0,"SELECT julianday(%Q)", next_token(&x,0));
613 if( p->rEventDate<=0.0 ) SYNTAX("malformed date on E-card");
614 p->zEventId = next_token(&x, &sz);
615 if( p->zEventId==0 ) SYNTAX("missing hash on E-card");
616 if( !hname_validate(p->zEventId, sz) ){
617 SYNTAX("malformed hash on E-card");
618 }
619 p->type = CFTYPE_EVENT;
620 break;
@@ -625,10 +635,11 @@
635 if( !file_is_simple_pathname_nonstrict(zName) ){
636 SYNTAX("F-card filename is not a simple path");
637 }
638 zUuid = next_token(&x, &sz);
639 if( p->zBaseline==0 || zUuid!=0 ){
640 if( zUuid==0 ) SYNTAX("missing hash on F-card");
641 if( !hname_validate(zUuid,sz) ){
642 SYNTAX("F-card hash invalid");
643 }
644 }
645 zPerm = next_token(&x,0);
@@ -643,17 +654,24 @@
654 p->nFileAlloc = p->nFileAlloc*2 + 10;
655 p->aFile = fossil_realloc(p->aFile,
656 p->nFileAlloc*sizeof(p->aFile[0]) );
657 }
658 i = p->nFile++;
659 if( i>0 && fossil_strcmp(p->aFile[i-1].zName, zName)>=0 ){
660 SYNTAX("incorrect F-card sort order");
661 }
662 if( file_is_reserved_name(zName,-1) ){
663 /* If reserved names leaked into historical manifests due to
664 ** slack oversight by older versions of Fossil, simply ignore
665 ** those files */
666 p->nFile--;
667 break;
668 }
669 p->aFile[i].zName = zName;
670 p->aFile[i].zUuid = zUuid;
671 p->aFile[i].zPerm = zPerm;
672 p->aFile[i].zPrior = zPriorName;
 
 
 
673 p->type = CFTYPE_MANIFEST;
674 break;
675 }
676
677 /*
678
+3 -3
--- src/report.c
+++ src/report.c
@@ -230,15 +230,15 @@
230230
231231
/*
232232
** Activate the query authorizer
233233
*/
234234
void report_restrict_sql(char **pzErr){
235
- sqlite3_set_authorizer(g.db, report_query_authorizer, (void*)pzErr);
235
+ db_set_authorizer(report_query_authorizer,(void*)pzErr,"Ticket-Report");
236236
sqlite3_limit(g.db, SQLITE_LIMIT_VDBE_OP, 10000);
237237
}
238238
void report_unrestrict_sql(void){
239
- sqlite3_set_authorizer(g.db, 0, 0);
239
+ db_clear_authorizer();
240240
}
241241
242242
243243
/*
244244
** Check the given SQL to see if is a valid query that does not
@@ -680,11 +680,11 @@
680680
*/
681681
if( pState->nCount==0 ){
682682
/* Turn off the authorizer. It is no longer doing anything since the
683683
** query has already been prepared.
684684
*/
685
- sqlite3_set_authorizer(g.db, 0, 0);
685
+ db_clear_authorizer();
686686
687687
/* Figure out the number of columns, the column that determines background
688688
** color, and whether or not this row of data is represented by multiple
689689
** rows in the table.
690690
*/
691691
--- src/report.c
+++ src/report.c
@@ -230,15 +230,15 @@
230
231 /*
232 ** Activate the query authorizer
233 */
234 void report_restrict_sql(char **pzErr){
235 sqlite3_set_authorizer(g.db, report_query_authorizer, (void*)pzErr);
236 sqlite3_limit(g.db, SQLITE_LIMIT_VDBE_OP, 10000);
237 }
238 void report_unrestrict_sql(void){
239 sqlite3_set_authorizer(g.db, 0, 0);
240 }
241
242
243 /*
244 ** Check the given SQL to see if is a valid query that does not
@@ -680,11 +680,11 @@
680 */
681 if( pState->nCount==0 ){
682 /* Turn off the authorizer. It is no longer doing anything since the
683 ** query has already been prepared.
684 */
685 sqlite3_set_authorizer(g.db, 0, 0);
686
687 /* Figure out the number of columns, the column that determines background
688 ** color, and whether or not this row of data is represented by multiple
689 ** rows in the table.
690 */
691
--- src/report.c
+++ src/report.c
@@ -230,15 +230,15 @@
230
231 /*
232 ** Activate the query authorizer
233 */
234 void report_restrict_sql(char **pzErr){
235 db_set_authorizer(report_query_authorizer,(void*)pzErr,"Ticket-Report");
236 sqlite3_limit(g.db, SQLITE_LIMIT_VDBE_OP, 10000);
237 }
238 void report_unrestrict_sql(void){
239 db_clear_authorizer();
240 }
241
242
243 /*
244 ** Check the given SQL to see if is a valid query that does not
@@ -680,11 +680,11 @@
680 */
681 if( pState->nCount==0 ){
682 /* Turn off the authorizer. It is no longer doing anything since the
683 ** query has already been prepared.
684 */
685 db_clear_authorizer();
686
687 /* Figure out the number of columns, the column that determines background
688 ** color, and whether or not this row of data is represented by multiple
689 ** rows in the table.
690 */
691
--- src/stash.c
+++ src/stash.c
@@ -334,10 +334,12 @@
334334
blob_write_to_file(&delta, zNPath);
335335
file_setexe(zNPath, isExec);
336336
}else if( isRemoved ){
337337
fossil_print("DELETE %s\n", zOrig);
338338
file_delete(zOPath);
339
+ }else if( file_unsafe_in_tree_path(zNPath) ){
340
+ /* Ignore the unsafe path */
339341
}else{
340342
Blob a, b, out, disk;
341343
int isNewLink = file_islink(zOPath);
342344
db_ephemeral_blob(&q, 6, &delta);
343345
blob_read_from_file(&disk, zOPath, RepoFILE);
344346
--- src/stash.c
+++ src/stash.c
@@ -334,10 +334,12 @@
334 blob_write_to_file(&delta, zNPath);
335 file_setexe(zNPath, isExec);
336 }else if( isRemoved ){
337 fossil_print("DELETE %s\n", zOrig);
338 file_delete(zOPath);
 
 
339 }else{
340 Blob a, b, out, disk;
341 int isNewLink = file_islink(zOPath);
342 db_ephemeral_blob(&q, 6, &delta);
343 blob_read_from_file(&disk, zOPath, RepoFILE);
344
--- src/stash.c
+++ src/stash.c
@@ -334,10 +334,12 @@
334 blob_write_to_file(&delta, zNPath);
335 file_setexe(zNPath, isExec);
336 }else if( isRemoved ){
337 fossil_print("DELETE %s\n", zOrig);
338 file_delete(zOPath);
339 }else if( file_unsafe_in_tree_path(zNPath) ){
340 /* Ignore the unsafe path */
341 }else{
342 Blob a, b, out, disk;
343 int isNewLink = file_islink(zOPath);
344 db_ephemeral_blob(&q, 6, &delta);
345 blob_read_from_file(&disk, zOPath, RepoFILE);
346
+72
--- src/tkt.c
+++ src/tkt.c
@@ -370,10 +370,79 @@
370370
Th_FossilInit(TH_INIT_DEFAULT);
371371
Th_Store("uuid", zUuid);
372372
zConfig = ticket_change_code();
373373
return Th_Eval(g.interp, 0, zConfig, -1);
374374
}
375
+
376
+/*
377
+** An authorizer function for the SQL used to initialize the
378
+** schema for the ticketing system. Only allow CREATE TABLE and
379
+** CREATE INDEX for tables whose names begin with "ticket" and
380
+** changes to tables whose names begin with "ticket".
381
+*/
382
+static int ticket_schema_auth(
383
+ void *pNErr,
384
+ int eCode,
385
+ const char *z0,
386
+ const char *z1,
387
+ const char *z2,
388
+ const char *z3
389
+){
390
+ switch( eCode ){
391
+ case SQLITE_CREATE_TABLE: {
392
+ if( sqlite3_stricmp(z2,"main")!=0
393
+ && sqlite3_stricmp(z2,"repository")!=0
394
+ ){
395
+ goto ticket_schema_error;
396
+ }
397
+ if( sqlite3_strnicmp(z0,"ticket",6)!=0 ){
398
+ goto ticket_schema_error;
399
+ }
400
+ break;
401
+ }
402
+ case SQLITE_CREATE_INDEX: {
403
+ if( sqlite3_stricmp(z2,"main")!=0
404
+ && sqlite3_stricmp(z2,"repository")!=0
405
+ ){
406
+ goto ticket_schema_error;
407
+ }
408
+ if( sqlite3_strnicmp(z1,"ticket",6)!=0 ){
409
+ goto ticket_schema_error;
410
+ }
411
+ break;
412
+ }
413
+ case SQLITE_INSERT:
414
+ case SQLITE_UPDATE:
415
+ case SQLITE_DELETE: {
416
+ if( sqlite3_stricmp(z2,"main")!=0
417
+ && sqlite3_stricmp(z2,"repository")!=0
418
+ ){
419
+ goto ticket_schema_error;
420
+ }
421
+ if( sqlite3_strnicmp(z0,"ticket",6)!=0
422
+ && sqlite3_strnicmp(z0,"sqlite_",7)!=0
423
+ ){
424
+ goto ticket_schema_error;
425
+ }
426
+ break;
427
+ }
428
+ case SQLITE_REINDEX:
429
+ case SQLITE_TRANSACTION:
430
+ case SQLITE_READ: {
431
+ break;
432
+ }
433
+ default: {
434
+ goto ticket_schema_error;
435
+ }
436
+ }
437
+ return SQLITE_OK;
438
+
439
+ticket_schema_error:
440
+ if( pNErr ) *(int*)pNErr = 1;
441
+ return SQLITE_DENY;
442
+}
443
+
375444
376445
/*
377446
** Recreate the TICKET and TICKETCHNG tables.
378447
*/
379448
void ticket_create_table(int separateConnection){
@@ -384,14 +453,17 @@
384453
"DROP TABLE IF EXISTS ticketchng;"
385454
);
386455
zSql = ticket_table_schema();
387456
if( separateConnection ){
388457
if( db_transaction_nesting_depth() ) db_end_transaction(0);
458
+ db_set_authorizer(ticket_schema_auth,0,"Ticket-Schema");
389459
db_init_database(g.zRepositoryName, zSql, 0);
390460
}else{
461
+ db_set_authorizer(ticket_schema_auth,0,"Ticket-Schema");
391462
db_multi_exec("%s", zSql/*safe-for-%s*/);
392463
}
464
+ db_clear_authorizer();
393465
fossil_free(zSql);
394466
}
395467
396468
/*
397469
** Repopulate the TICKET and TICKETCHNG tables from scratch using all
398470
--- src/tkt.c
+++ src/tkt.c
@@ -370,10 +370,79 @@
370 Th_FossilInit(TH_INIT_DEFAULT);
371 Th_Store("uuid", zUuid);
372 zConfig = ticket_change_code();
373 return Th_Eval(g.interp, 0, zConfig, -1);
374 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
375
376 /*
377 ** Recreate the TICKET and TICKETCHNG tables.
378 */
379 void ticket_create_table(int separateConnection){
@@ -384,14 +453,17 @@
384 "DROP TABLE IF EXISTS ticketchng;"
385 );
386 zSql = ticket_table_schema();
387 if( separateConnection ){
388 if( db_transaction_nesting_depth() ) db_end_transaction(0);
 
389 db_init_database(g.zRepositoryName, zSql, 0);
390 }else{
 
391 db_multi_exec("%s", zSql/*safe-for-%s*/);
392 }
 
393 fossil_free(zSql);
394 }
395
396 /*
397 ** Repopulate the TICKET and TICKETCHNG tables from scratch using all
398
--- src/tkt.c
+++ src/tkt.c
@@ -370,10 +370,79 @@
370 Th_FossilInit(TH_INIT_DEFAULT);
371 Th_Store("uuid", zUuid);
372 zConfig = ticket_change_code();
373 return Th_Eval(g.interp, 0, zConfig, -1);
374 }
375
376 /*
377 ** An authorizer function for the SQL used to initialize the
378 ** schema for the ticketing system. Only allow CREATE TABLE and
379 ** CREATE INDEX for tables whose names begin with "ticket" and
380 ** changes to tables whose names begin with "ticket".
381 */
382 static int ticket_schema_auth(
383 void *pNErr,
384 int eCode,
385 const char *z0,
386 const char *z1,
387 const char *z2,
388 const char *z3
389 ){
390 switch( eCode ){
391 case SQLITE_CREATE_TABLE: {
392 if( sqlite3_stricmp(z2,"main")!=0
393 && sqlite3_stricmp(z2,"repository")!=0
394 ){
395 goto ticket_schema_error;
396 }
397 if( sqlite3_strnicmp(z0,"ticket",6)!=0 ){
398 goto ticket_schema_error;
399 }
400 break;
401 }
402 case SQLITE_CREATE_INDEX: {
403 if( sqlite3_stricmp(z2,"main")!=0
404 && sqlite3_stricmp(z2,"repository")!=0
405 ){
406 goto ticket_schema_error;
407 }
408 if( sqlite3_strnicmp(z1,"ticket",6)!=0 ){
409 goto ticket_schema_error;
410 }
411 break;
412 }
413 case SQLITE_INSERT:
414 case SQLITE_UPDATE:
415 case SQLITE_DELETE: {
416 if( sqlite3_stricmp(z2,"main")!=0
417 && sqlite3_stricmp(z2,"repository")!=0
418 ){
419 goto ticket_schema_error;
420 }
421 if( sqlite3_strnicmp(z0,"ticket",6)!=0
422 && sqlite3_strnicmp(z0,"sqlite_",7)!=0
423 ){
424 goto ticket_schema_error;
425 }
426 break;
427 }
428 case SQLITE_REINDEX:
429 case SQLITE_TRANSACTION:
430 case SQLITE_READ: {
431 break;
432 }
433 default: {
434 goto ticket_schema_error;
435 }
436 }
437 return SQLITE_OK;
438
439 ticket_schema_error:
440 if( pNErr ) *(int*)pNErr = 1;
441 return SQLITE_DENY;
442 }
443
444
445 /*
446 ** Recreate the TICKET and TICKETCHNG tables.
447 */
448 void ticket_create_table(int separateConnection){
@@ -384,14 +453,17 @@
453 "DROP TABLE IF EXISTS ticketchng;"
454 );
455 zSql = ticket_table_schema();
456 if( separateConnection ){
457 if( db_transaction_nesting_depth() ) db_end_transaction(0);
458 db_set_authorizer(ticket_schema_auth,0,"Ticket-Schema");
459 db_init_database(g.zRepositoryName, zSql, 0);
460 }else{
461 db_set_authorizer(ticket_schema_auth,0,"Ticket-Schema");
462 db_multi_exec("%s", zSql/*safe-for-%s*/);
463 }
464 db_clear_authorizer();
465 fossil_free(zSql);
466 }
467
468 /*
469 ** Repopulate the TICKET and TICKETCHNG tables from scratch using all
470
+4 -2
--- src/undo.c
+++ src/undo.c
@@ -52,11 +52,11 @@
5252
int new_exe;
5353
int new_link;
5454
int old_link;
5555
Blob current;
5656
Blob new;
57
- zFullname = mprintf("%s/%s", g.zLocalRoot, zPathname);
57
+ zFullname = mprintf("%s%s", g.zLocalRoot, zPathname);
5858
old_link = db_column_int(&q, 3);
5959
new_exists = file_size(zFullname, RepoFILE)>=0;
6060
new_link = file_islink(0);
6161
if( new_exists ){
6262
blob_read_from_file(&current, zFullname, RepoFILE);
@@ -69,11 +69,13 @@
6969
old_exists = db_column_int(&q, 1);
7070
old_exe = db_column_int(&q, 2);
7171
if( old_exists ){
7272
db_ephemeral_blob(&q, 0, &new);
7373
}
74
- if( old_exists ){
74
+ if( file_unsafe_in_tree_path(zFullname) ){
75
+ /* do nothign with this unsafe file */
76
+ }else if( old_exists ){
7577
if( new_exists ){
7678
fossil_print("%s %s\n", redoFlag ? "REDO" : "UNDO", zPathname);
7779
}else{
7880
fossil_print("NEW %s\n", zPathname);
7981
}
8082
--- src/undo.c
+++ src/undo.c
@@ -52,11 +52,11 @@
52 int new_exe;
53 int new_link;
54 int old_link;
55 Blob current;
56 Blob new;
57 zFullname = mprintf("%s/%s", g.zLocalRoot, zPathname);
58 old_link = db_column_int(&q, 3);
59 new_exists = file_size(zFullname, RepoFILE)>=0;
60 new_link = file_islink(0);
61 if( new_exists ){
62 blob_read_from_file(&current, zFullname, RepoFILE);
@@ -69,11 +69,13 @@
69 old_exists = db_column_int(&q, 1);
70 old_exe = db_column_int(&q, 2);
71 if( old_exists ){
72 db_ephemeral_blob(&q, 0, &new);
73 }
74 if( old_exists ){
 
 
75 if( new_exists ){
76 fossil_print("%s %s\n", redoFlag ? "REDO" : "UNDO", zPathname);
77 }else{
78 fossil_print("NEW %s\n", zPathname);
79 }
80
--- src/undo.c
+++ src/undo.c
@@ -52,11 +52,11 @@
52 int new_exe;
53 int new_link;
54 int old_link;
55 Blob current;
56 Blob new;
57 zFullname = mprintf("%s%s", g.zLocalRoot, zPathname);
58 old_link = db_column_int(&q, 3);
59 new_exists = file_size(zFullname, RepoFILE)>=0;
60 new_link = file_islink(0);
61 if( new_exists ){
62 blob_read_from_file(&current, zFullname, RepoFILE);
@@ -69,11 +69,13 @@
69 old_exists = db_column_int(&q, 1);
70 old_exe = db_column_int(&q, 2);
71 if( old_exists ){
72 db_ephemeral_blob(&q, 0, &new);
73 }
74 if( file_unsafe_in_tree_path(zFullname) ){
75 /* do nothign with this unsafe file */
76 }else if( old_exists ){
77 if( new_exists ){
78 fossil_print("%s %s\n", redoFlag ? "REDO" : "UNDO", zPathname);
79 }else{
80 fossil_print("NEW %s\n", zPathname);
81 }
82
--- src/update.c
+++ src/update.c
@@ -927,10 +927,12 @@
927927
" SET pathname=origname, origname=NULL"
928928
" WHERE pathname=%Q AND origname!=pathname;"
929929
"DELETE FROM vfile WHERE pathname=%Q",
930930
zFile, zFile
931931
);
932
+ }else if( file_unsafe_in_tree_path(zFull) ){
933
+ /* Ignore this file */
932934
}else{
933935
sqlite3_int64 mtime;
934936
int rvChnged = 0;
935937
int rvPerm = manifest_file_mperm(pRvFile);
936938
937939
--- src/update.c
+++ src/update.c
@@ -927,10 +927,12 @@
927 " SET pathname=origname, origname=NULL"
928 " WHERE pathname=%Q AND origname!=pathname;"
929 "DELETE FROM vfile WHERE pathname=%Q",
930 zFile, zFile
931 );
 
 
932 }else{
933 sqlite3_int64 mtime;
934 int rvChnged = 0;
935 int rvPerm = manifest_file_mperm(pRvFile);
936
937
--- src/update.c
+++ src/update.c
@@ -927,10 +927,12 @@
927 " SET pathname=origname, origname=NULL"
928 " WHERE pathname=%Q AND origname!=pathname;"
929 "DELETE FROM vfile WHERE pathname=%Q",
930 zFile, zFile
931 );
932 }else if( file_unsafe_in_tree_path(zFull) ){
933 /* Ignore this file */
934 }else{
935 sqlite3_int64 mtime;
936 int rvChnged = 0;
937 int rvPerm = manifest_file_mperm(pRvFile);
938
939
--- src/vfile.c
+++ src/vfile.c
@@ -313,10 +313,13 @@
313313
id = db_column_int(&q, 0);
314314
zName = db_column_text(&q, 1);
315315
rid = db_column_int(&q, 2);
316316
isExe = db_column_int(&q, 3);
317317
isLink = db_column_int(&q, 4);
318
+ if( file_unsafe_in_tree_path(zName) ){
319
+ continue;
320
+ }
318321
content_get(rid, &content);
319322
if( file_is_the_same(&content, zName) ){
320323
blob_reset(&content);
321324
if( file_setexe(zName, isExe) ){
322325
db_multi_exec("UPDATE vfile SET mtime=%lld WHERE id=%d",
323326
--- src/vfile.c
+++ src/vfile.c
@@ -313,10 +313,13 @@
313 id = db_column_int(&q, 0);
314 zName = db_column_text(&q, 1);
315 rid = db_column_int(&q, 2);
316 isExe = db_column_int(&q, 3);
317 isLink = db_column_int(&q, 4);
 
 
 
318 content_get(rid, &content);
319 if( file_is_the_same(&content, zName) ){
320 blob_reset(&content);
321 if( file_setexe(zName, isExe) ){
322 db_multi_exec("UPDATE vfile SET mtime=%lld WHERE id=%d",
323
--- src/vfile.c
+++ src/vfile.c
@@ -313,10 +313,13 @@
313 id = db_column_int(&q, 0);
314 zName = db_column_text(&q, 1);
315 rid = db_column_int(&q, 2);
316 isExe = db_column_int(&q, 3);
317 isLink = db_column_int(&q, 4);
318 if( file_unsafe_in_tree_path(zName) ){
319 continue;
320 }
321 content_get(rid, &content);
322 if( file_is_the_same(&content, zName) ){
323 blob_reset(&content);
324 if( file_setexe(zName, isExe) ){
325 db_multi_exec("UPDATE vfile SET mtime=%lld WHERE id=%d",
326

Keyboard Shortcuts

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