Fossil SCM

Version 2.11.2

drh 2020-08-20 13:24 release
Commit c58877d6f2d88b684fdef15418467a60d6584b4620311df6fa7726e635a2685a
+1 -1
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1
-2.11.1
1
+2.11.2
22
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1 2.11.1
2
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1 2.11.2
2
+1 -1
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1
-2.11.1
1
+2.11.2
22
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1 2.11.1
2
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1 2.11.2
2
+30 -10
--- src/add.c
+++ src/add.c
@@ -174,10 +174,11 @@
174174
*/
175175
static int add_one_file(
176176
const char *zPath, /* Tree-name of file to add. */
177177
int vid /* Add to this VFILE */
178178
){
179
+ int doSkip = 0;
179180
if( !file_is_simple_pathname(zPath, 1) ){
180181
fossil_warning("filename contains illegal characters: %s", zPath);
181182
return 0;
182183
}
183184
if( db_exists("SELECT 1 FROM vfile"
@@ -186,17 +187,22 @@
186187
" WHERE pathname=%Q %s AND deleted",
187188
zPath, filename_collation());
188189
}else{
189190
char *zFullname = mprintf("%s%s", g.zLocalRoot, zPath);
190191
int isExe = file_isexe(zFullname, RepoFILE);
191
- db_multi_exec(
192
- "INSERT INTO vfile(vid,deleted,rid,mrid,pathname,isexe,islink,mhash)"
193
- "VALUES(%d,0,0,0,%Q,%d,%d,NULL)",
194
- vid, zPath, isExe, file_islink(0));
192
+ if( file_nondir_objects_on_path(g.zLocalRoot, zFullname) ){
193
+ /* Do not add unsafe files to the vfile */
194
+ doSkip = 1;
195
+ }else{
196
+ db_multi_exec(
197
+ "INSERT INTO vfile(vid,deleted,rid,mrid,pathname,isexe,islink,mhash)"
198
+ "VALUES(%d,0,0,0,%Q,%d,%d,NULL)",
199
+ vid, zPath, isExe, file_islink(0));
200
+ }
195201
fossil_free(zFullname);
196202
}
197
- if( db_changes() ){
203
+ if( db_changes() && !doSkip ){
198204
fossil_print("ADDED %s\n", zPath);
199205
return 1;
200206
}else{
201207
fossil_print("SKIP %s\n", zPath);
202208
return 0;
@@ -204,11 +210,13 @@
204210
}
205211
206212
/*
207213
** Add all files in the sfile temp table.
208214
**
209
-** Automatically exclude the repository file.
215
+** Automatically exclude the repository file and any other files
216
+** with reserved names. Also exclude files that are beneath an
217
+** existing symlink.
210218
*/
211219
static int add_files_in_sfile(int vid){
212220
const char *zRepo; /* Name of the repository database file */
213221
int nAdd = 0; /* Number of files added */
214222
int i; /* Loop counter */
@@ -226,18 +234,30 @@
226234
if( filenames_are_case_sensitive() ){
227235
xCmp = fossil_strcmp;
228236
}else{
229237
xCmp = fossil_stricmp;
230238
}
231
- db_prepare(&loop, "SELECT pathname FROM sfile ORDER BY pathname");
239
+ db_prepare(&loop,
240
+ "SELECT pathname FROM sfile"
241
+ " WHERE pathname NOT IN ("
242
+ "SELECT sfile.pathname FROM vfile, sfile"
243
+ " WHERE vfile.islink"
244
+ " AND NOT vfile.deleted"
245
+ " AND sfile.pathname>(vfile.pathname||'/')"
246
+ " AND sfile.pathname<(vfile.pathname||'0'))"
247
+ " ORDER BY pathname");
232248
while( db_step(&loop)==SQLITE_ROW ){
233249
const char *zToAdd = db_column_text(&loop, 0);
234250
if( fossil_strcmp(zToAdd, zRepo)==0 ) continue;
235
- for(i=0; (zReserved = fossil_reserved_name(i, 0))!=0; i++){
236
- if( xCmp(zToAdd, zReserved)==0 ) break;
251
+ if( strchr(zToAdd,'/') ){
252
+ if( file_is_reserved_name(zToAdd, -1) ) continue;
253
+ }else{
254
+ for(i=0; (zReserved = fossil_reserved_name(i, 0))!=0; i++){
255
+ if( xCmp(zToAdd, zReserved)==0 ) break;
256
+ }
257
+ if( zReserved ) continue;
237258
}
238
- if( zReserved ) continue;
239259
nAdd += add_one_file(zToAdd, vid);
240260
}
241261
db_finalize(&loop);
242262
blob_reset(&repoName);
243263
return nAdd;
244264
--- src/add.c
+++ src/add.c
@@ -174,10 +174,11 @@
174 */
175 static int add_one_file(
176 const char *zPath, /* Tree-name of file to add. */
177 int vid /* Add to this VFILE */
178 ){
 
179 if( !file_is_simple_pathname(zPath, 1) ){
180 fossil_warning("filename contains illegal characters: %s", zPath);
181 return 0;
182 }
183 if( db_exists("SELECT 1 FROM vfile"
@@ -186,17 +187,22 @@
186 " WHERE pathname=%Q %s AND deleted",
187 zPath, filename_collation());
188 }else{
189 char *zFullname = mprintf("%s%s", g.zLocalRoot, zPath);
190 int isExe = file_isexe(zFullname, RepoFILE);
191 db_multi_exec(
192 "INSERT INTO vfile(vid,deleted,rid,mrid,pathname,isexe,islink,mhash)"
193 "VALUES(%d,0,0,0,%Q,%d,%d,NULL)",
194 vid, zPath, isExe, file_islink(0));
 
 
 
 
 
195 fossil_free(zFullname);
196 }
197 if( db_changes() ){
198 fossil_print("ADDED %s\n", zPath);
199 return 1;
200 }else{
201 fossil_print("SKIP %s\n", zPath);
202 return 0;
@@ -204,11 +210,13 @@
204 }
205
206 /*
207 ** Add all files in the sfile temp table.
208 **
209 ** Automatically exclude the repository file.
 
 
210 */
211 static int add_files_in_sfile(int vid){
212 const char *zRepo; /* Name of the repository database file */
213 int nAdd = 0; /* Number of files added */
214 int i; /* Loop counter */
@@ -226,18 +234,30 @@
226 if( filenames_are_case_sensitive() ){
227 xCmp = fossil_strcmp;
228 }else{
229 xCmp = fossil_stricmp;
230 }
231 db_prepare(&loop, "SELECT pathname FROM sfile ORDER BY pathname");
 
 
 
 
 
 
 
 
232 while( db_step(&loop)==SQLITE_ROW ){
233 const char *zToAdd = db_column_text(&loop, 0);
234 if( fossil_strcmp(zToAdd, zRepo)==0 ) continue;
235 for(i=0; (zReserved = fossil_reserved_name(i, 0))!=0; i++){
236 if( xCmp(zToAdd, zReserved)==0 ) break;
 
 
 
 
 
237 }
238 if( zReserved ) continue;
239 nAdd += add_one_file(zToAdd, vid);
240 }
241 db_finalize(&loop);
242 blob_reset(&repoName);
243 return nAdd;
244
--- src/add.c
+++ src/add.c
@@ -174,10 +174,11 @@
174 */
175 static int add_one_file(
176 const char *zPath, /* Tree-name of file to add. */
177 int vid /* Add to this VFILE */
178 ){
179 int doSkip = 0;
180 if( !file_is_simple_pathname(zPath, 1) ){
181 fossil_warning("filename contains illegal characters: %s", zPath);
182 return 0;
183 }
184 if( db_exists("SELECT 1 FROM vfile"
@@ -186,17 +187,22 @@
187 " WHERE pathname=%Q %s AND deleted",
188 zPath, filename_collation());
189 }else{
190 char *zFullname = mprintf("%s%s", g.zLocalRoot, zPath);
191 int isExe = file_isexe(zFullname, RepoFILE);
192 if( file_nondir_objects_on_path(g.zLocalRoot, zFullname) ){
193 /* Do not add unsafe files to the vfile */
194 doSkip = 1;
195 }else{
196 db_multi_exec(
197 "INSERT INTO vfile(vid,deleted,rid,mrid,pathname,isexe,islink,mhash)"
198 "VALUES(%d,0,0,0,%Q,%d,%d,NULL)",
199 vid, zPath, isExe, file_islink(0));
200 }
201 fossil_free(zFullname);
202 }
203 if( db_changes() && !doSkip ){
204 fossil_print("ADDED %s\n", zPath);
205 return 1;
206 }else{
207 fossil_print("SKIP %s\n", zPath);
208 return 0;
@@ -204,11 +210,13 @@
210 }
211
212 /*
213 ** Add all files in the sfile temp table.
214 **
215 ** Automatically exclude the repository file and any other files
216 ** with reserved names. Also exclude files that are beneath an
217 ** existing symlink.
218 */
219 static int add_files_in_sfile(int vid){
220 const char *zRepo; /* Name of the repository database file */
221 int nAdd = 0; /* Number of files added */
222 int i; /* Loop counter */
@@ -226,18 +234,30 @@
234 if( filenames_are_case_sensitive() ){
235 xCmp = fossil_strcmp;
236 }else{
237 xCmp = fossil_stricmp;
238 }
239 db_prepare(&loop,
240 "SELECT pathname FROM sfile"
241 " WHERE pathname NOT IN ("
242 "SELECT sfile.pathname FROM vfile, sfile"
243 " WHERE vfile.islink"
244 " AND NOT vfile.deleted"
245 " AND sfile.pathname>(vfile.pathname||'/')"
246 " AND sfile.pathname<(vfile.pathname||'0'))"
247 " ORDER BY pathname");
248 while( db_step(&loop)==SQLITE_ROW ){
249 const char *zToAdd = db_column_text(&loop, 0);
250 if( fossil_strcmp(zToAdd, zRepo)==0 ) continue;
251 if( strchr(zToAdd,'/') ){
252 if( file_is_reserved_name(zToAdd, -1) ) continue;
253 }else{
254 for(i=0; (zReserved = fossil_reserved_name(i, 0))!=0; i++){
255 if( xCmp(zToAdd, zReserved)==0 ) break;
256 }
257 if( zReserved ) continue;
258 }
 
259 nAdd += add_one_file(zToAdd, vid);
260 }
261 db_finalize(&loop);
262 blob_reset(&repoName);
263 return nAdd;
264
+30 -10
--- src/add.c
+++ src/add.c
@@ -174,10 +174,11 @@
174174
*/
175175
static int add_one_file(
176176
const char *zPath, /* Tree-name of file to add. */
177177
int vid /* Add to this VFILE */
178178
){
179
+ int doSkip = 0;
179180
if( !file_is_simple_pathname(zPath, 1) ){
180181
fossil_warning("filename contains illegal characters: %s", zPath);
181182
return 0;
182183
}
183184
if( db_exists("SELECT 1 FROM vfile"
@@ -186,17 +187,22 @@
186187
" WHERE pathname=%Q %s AND deleted",
187188
zPath, filename_collation());
188189
}else{
189190
char *zFullname = mprintf("%s%s", g.zLocalRoot, zPath);
190191
int isExe = file_isexe(zFullname, RepoFILE);
191
- db_multi_exec(
192
- "INSERT INTO vfile(vid,deleted,rid,mrid,pathname,isexe,islink,mhash)"
193
- "VALUES(%d,0,0,0,%Q,%d,%d,NULL)",
194
- vid, zPath, isExe, file_islink(0));
192
+ if( file_nondir_objects_on_path(g.zLocalRoot, zFullname) ){
193
+ /* Do not add unsafe files to the vfile */
194
+ doSkip = 1;
195
+ }else{
196
+ db_multi_exec(
197
+ "INSERT INTO vfile(vid,deleted,rid,mrid,pathname,isexe,islink,mhash)"
198
+ "VALUES(%d,0,0,0,%Q,%d,%d,NULL)",
199
+ vid, zPath, isExe, file_islink(0));
200
+ }
195201
fossil_free(zFullname);
196202
}
197
- if( db_changes() ){
203
+ if( db_changes() && !doSkip ){
198204
fossil_print("ADDED %s\n", zPath);
199205
return 1;
200206
}else{
201207
fossil_print("SKIP %s\n", zPath);
202208
return 0;
@@ -204,11 +210,13 @@
204210
}
205211
206212
/*
207213
** Add all files in the sfile temp table.
208214
**
209
-** Automatically exclude the repository file.
215
+** Automatically exclude the repository file and any other files
216
+** with reserved names. Also exclude files that are beneath an
217
+** existing symlink.
210218
*/
211219
static int add_files_in_sfile(int vid){
212220
const char *zRepo; /* Name of the repository database file */
213221
int nAdd = 0; /* Number of files added */
214222
int i; /* Loop counter */
@@ -226,18 +234,30 @@
226234
if( filenames_are_case_sensitive() ){
227235
xCmp = fossil_strcmp;
228236
}else{
229237
xCmp = fossil_stricmp;
230238
}
231
- db_prepare(&loop, "SELECT pathname FROM sfile ORDER BY pathname");
239
+ db_prepare(&loop,
240
+ "SELECT pathname FROM sfile"
241
+ " WHERE pathname NOT IN ("
242
+ "SELECT sfile.pathname FROM vfile, sfile"
243
+ " WHERE vfile.islink"
244
+ " AND NOT vfile.deleted"
245
+ " AND sfile.pathname>(vfile.pathname||'/')"
246
+ " AND sfile.pathname<(vfile.pathname||'0'))"
247
+ " ORDER BY pathname");
232248
while( db_step(&loop)==SQLITE_ROW ){
233249
const char *zToAdd = db_column_text(&loop, 0);
234250
if( fossil_strcmp(zToAdd, zRepo)==0 ) continue;
235
- for(i=0; (zReserved = fossil_reserved_name(i, 0))!=0; i++){
236
- if( xCmp(zToAdd, zReserved)==0 ) break;
251
+ if( strchr(zToAdd,'/') ){
252
+ if( file_is_reserved_name(zToAdd, -1) ) continue;
253
+ }else{
254
+ for(i=0; (zReserved = fossil_reserved_name(i, 0))!=0; i++){
255
+ if( xCmp(zToAdd, zReserved)==0 ) break;
256
+ }
257
+ if( zReserved ) continue;
237258
}
238
- if( zReserved ) continue;
239259
nAdd += add_one_file(zToAdd, vid);
240260
}
241261
db_finalize(&loop);
242262
blob_reset(&repoName);
243263
return nAdd;
244264
--- src/add.c
+++ src/add.c
@@ -174,10 +174,11 @@
174 */
175 static int add_one_file(
176 const char *zPath, /* Tree-name of file to add. */
177 int vid /* Add to this VFILE */
178 ){
 
179 if( !file_is_simple_pathname(zPath, 1) ){
180 fossil_warning("filename contains illegal characters: %s", zPath);
181 return 0;
182 }
183 if( db_exists("SELECT 1 FROM vfile"
@@ -186,17 +187,22 @@
186 " WHERE pathname=%Q %s AND deleted",
187 zPath, filename_collation());
188 }else{
189 char *zFullname = mprintf("%s%s", g.zLocalRoot, zPath);
190 int isExe = file_isexe(zFullname, RepoFILE);
191 db_multi_exec(
192 "INSERT INTO vfile(vid,deleted,rid,mrid,pathname,isexe,islink,mhash)"
193 "VALUES(%d,0,0,0,%Q,%d,%d,NULL)",
194 vid, zPath, isExe, file_islink(0));
 
 
 
 
 
195 fossil_free(zFullname);
196 }
197 if( db_changes() ){
198 fossil_print("ADDED %s\n", zPath);
199 return 1;
200 }else{
201 fossil_print("SKIP %s\n", zPath);
202 return 0;
@@ -204,11 +210,13 @@
204 }
205
206 /*
207 ** Add all files in the sfile temp table.
208 **
209 ** Automatically exclude the repository file.
 
 
210 */
211 static int add_files_in_sfile(int vid){
212 const char *zRepo; /* Name of the repository database file */
213 int nAdd = 0; /* Number of files added */
214 int i; /* Loop counter */
@@ -226,18 +234,30 @@
226 if( filenames_are_case_sensitive() ){
227 xCmp = fossil_strcmp;
228 }else{
229 xCmp = fossil_stricmp;
230 }
231 db_prepare(&loop, "SELECT pathname FROM sfile ORDER BY pathname");
 
 
 
 
 
 
 
 
232 while( db_step(&loop)==SQLITE_ROW ){
233 const char *zToAdd = db_column_text(&loop, 0);
234 if( fossil_strcmp(zToAdd, zRepo)==0 ) continue;
235 for(i=0; (zReserved = fossil_reserved_name(i, 0))!=0; i++){
236 if( xCmp(zToAdd, zReserved)==0 ) break;
 
 
 
 
 
237 }
238 if( zReserved ) continue;
239 nAdd += add_one_file(zToAdd, vid);
240 }
241 db_finalize(&loop);
242 blob_reset(&repoName);
243 return nAdd;
244
--- src/add.c
+++ src/add.c
@@ -174,10 +174,11 @@
174 */
175 static int add_one_file(
176 const char *zPath, /* Tree-name of file to add. */
177 int vid /* Add to this VFILE */
178 ){
179 int doSkip = 0;
180 if( !file_is_simple_pathname(zPath, 1) ){
181 fossil_warning("filename contains illegal characters: %s", zPath);
182 return 0;
183 }
184 if( db_exists("SELECT 1 FROM vfile"
@@ -186,17 +187,22 @@
187 " WHERE pathname=%Q %s AND deleted",
188 zPath, filename_collation());
189 }else{
190 char *zFullname = mprintf("%s%s", g.zLocalRoot, zPath);
191 int isExe = file_isexe(zFullname, RepoFILE);
192 if( file_nondir_objects_on_path(g.zLocalRoot, zFullname) ){
193 /* Do not add unsafe files to the vfile */
194 doSkip = 1;
195 }else{
196 db_multi_exec(
197 "INSERT INTO vfile(vid,deleted,rid,mrid,pathname,isexe,islink,mhash)"
198 "VALUES(%d,0,0,0,%Q,%d,%d,NULL)",
199 vid, zPath, isExe, file_islink(0));
200 }
201 fossil_free(zFullname);
202 }
203 if( db_changes() && !doSkip ){
204 fossil_print("ADDED %s\n", zPath);
205 return 1;
206 }else{
207 fossil_print("SKIP %s\n", zPath);
208 return 0;
@@ -204,11 +210,13 @@
210 }
211
212 /*
213 ** Add all files in the sfile temp table.
214 **
215 ** Automatically exclude the repository file and any other files
216 ** with reserved names. Also exclude files that are beneath an
217 ** existing symlink.
218 */
219 static int add_files_in_sfile(int vid){
220 const char *zRepo; /* Name of the repository database file */
221 int nAdd = 0; /* Number of files added */
222 int i; /* Loop counter */
@@ -226,18 +234,30 @@
234 if( filenames_are_case_sensitive() ){
235 xCmp = fossil_strcmp;
236 }else{
237 xCmp = fossil_stricmp;
238 }
239 db_prepare(&loop,
240 "SELECT pathname FROM sfile"
241 " WHERE pathname NOT IN ("
242 "SELECT sfile.pathname FROM vfile, sfile"
243 " WHERE vfile.islink"
244 " AND NOT vfile.deleted"
245 " AND sfile.pathname>(vfile.pathname||'/')"
246 " AND sfile.pathname<(vfile.pathname||'0'))"
247 " ORDER BY pathname");
248 while( db_step(&loop)==SQLITE_ROW ){
249 const char *zToAdd = db_column_text(&loop, 0);
250 if( fossil_strcmp(zToAdd, zRepo)==0 ) continue;
251 if( strchr(zToAdd,'/') ){
252 if( file_is_reserved_name(zToAdd, -1) ) continue;
253 }else{
254 for(i=0; (zReserved = fossil_reserved_name(i, 0))!=0; i++){
255 if( xCmp(zToAdd, zReserved)==0 ) break;
256 }
257 if( zReserved ) continue;
258 }
 
259 nAdd += add_one_file(zToAdd, vid);
260 }
261 db_finalize(&loop);
262 blob_reset(&repoName);
263 return nAdd;
264
--- 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/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
@@ -140,11 +140,13 @@
140140
{ "keep-glob", CONFIGSET_PROJ },
141141
{ "crlf-glob", CONFIGSET_PROJ },
142142
{ "crnl-glob", CONFIGSET_PROJ },
143143
{ "encoding-glob", CONFIGSET_PROJ },
144144
{ "empty-dirs", CONFIGSET_PROJ },
145
+#ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
145146
{ "allow-symlinks", CONFIGSET_PROJ },
147
+#endif
146148
{ "dotfiles", CONFIGSET_PROJ },
147149
{ "parent-project-code", CONFIGSET_PROJ },
148150
{ "parent-project-name", CONFIGSET_PROJ },
149151
{ "hash-policy", CONFIGSET_PROJ },
150152
{ "comment-format", CONFIGSET_PROJ },
151153
--- src/configure.c
+++ src/configure.c
@@ -140,11 +140,13 @@
140 { "keep-glob", CONFIGSET_PROJ },
141 { "crlf-glob", CONFIGSET_PROJ },
142 { "crnl-glob", CONFIGSET_PROJ },
143 { "encoding-glob", CONFIGSET_PROJ },
144 { "empty-dirs", CONFIGSET_PROJ },
 
145 { "allow-symlinks", CONFIGSET_PROJ },
 
146 { "dotfiles", CONFIGSET_PROJ },
147 { "parent-project-code", CONFIGSET_PROJ },
148 { "parent-project-name", CONFIGSET_PROJ },
149 { "hash-policy", CONFIGSET_PROJ },
150 { "comment-format", CONFIGSET_PROJ },
151
--- src/configure.c
+++ src/configure.c
@@ -140,11 +140,13 @@
140 { "keep-glob", CONFIGSET_PROJ },
141 { "crlf-glob", CONFIGSET_PROJ },
142 { "crnl-glob", CONFIGSET_PROJ },
143 { "encoding-glob", CONFIGSET_PROJ },
144 { "empty-dirs", CONFIGSET_PROJ },
145 #ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
146 { "allow-symlinks", CONFIGSET_PROJ },
147 #endif
148 { "dotfiles", CONFIGSET_PROJ },
149 { "parent-project-code", CONFIGSET_PROJ },
150 { "parent-project-name", CONFIGSET_PROJ },
151 { "hash-policy", CONFIGSET_PROJ },
152 { "comment-format", CONFIGSET_PROJ },
153
--- src/configure.c
+++ src/configure.c
@@ -140,11 +140,13 @@
140140
{ "keep-glob", CONFIGSET_PROJ },
141141
{ "crlf-glob", CONFIGSET_PROJ },
142142
{ "crnl-glob", CONFIGSET_PROJ },
143143
{ "encoding-glob", CONFIGSET_PROJ },
144144
{ "empty-dirs", CONFIGSET_PROJ },
145
+#ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
145146
{ "allow-symlinks", CONFIGSET_PROJ },
147
+#endif
146148
{ "dotfiles", CONFIGSET_PROJ },
147149
{ "parent-project-code", CONFIGSET_PROJ },
148150
{ "parent-project-name", CONFIGSET_PROJ },
149151
{ "hash-policy", CONFIGSET_PROJ },
150152
{ "comment-format", CONFIGSET_PROJ },
151153
--- src/configure.c
+++ src/configure.c
@@ -140,11 +140,13 @@
140 { "keep-glob", CONFIGSET_PROJ },
141 { "crlf-glob", CONFIGSET_PROJ },
142 { "crnl-glob", CONFIGSET_PROJ },
143 { "encoding-glob", CONFIGSET_PROJ },
144 { "empty-dirs", CONFIGSET_PROJ },
 
145 { "allow-symlinks", CONFIGSET_PROJ },
 
146 { "dotfiles", CONFIGSET_PROJ },
147 { "parent-project-code", CONFIGSET_PROJ },
148 { "parent-project-name", CONFIGSET_PROJ },
149 { "hash-policy", CONFIGSET_PROJ },
150 { "comment-format", CONFIGSET_PROJ },
151
--- src/configure.c
+++ src/configure.c
@@ -140,11 +140,13 @@
140 { "keep-glob", CONFIGSET_PROJ },
141 { "crlf-glob", CONFIGSET_PROJ },
142 { "crnl-glob", CONFIGSET_PROJ },
143 { "encoding-glob", CONFIGSET_PROJ },
144 { "empty-dirs", CONFIGSET_PROJ },
145 #ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
146 { "allow-symlinks", CONFIGSET_PROJ },
147 #endif
148 { "dotfiles", CONFIGSET_PROJ },
149 { "parent-project-code", CONFIGSET_PROJ },
150 { "parent-project-name", CONFIGSET_PROJ },
151 { "hash-policy", CONFIGSET_PROJ },
152 { "comment-format", CONFIGSET_PROJ },
153
+80 -17
--- src/db.c
+++ src/db.c
@@ -123,10 +123,13 @@
123123
char *azBeforeCommit[5]; /* Commands to run prior to COMMIT */
124124
int nBeforeCommit; /* Number of entries in azBeforeCommit */
125125
int nPriorChanges; /* sqlite3_total_changes() at transaction start */
126126
const char *zStartFile; /* File in which transaction was started */
127127
int iStartLine; /* Line of zStartFile where transaction started */
128
+ int (*xAuth)(void*,int,const char*,const char*,const char*,const char*);
129
+ void *pAuthArg; /* Argument to the authorizer */
130
+ const char *zAuthName; /* Name of the authorizer */
128131
} db = {0, 0, 0, 0, 0, 0, };
129132
130133
/*
131134
** Arrange for the given file to be deleted on a failure.
132135
*/
@@ -307,10 +310,36 @@
307310
}
308311
db.aHook[db.nCommitHook].sequence = sequence;
309312
db.aHook[db.nCommitHook].xHook = x;
310313
db.nCommitHook++;
311314
}
315
+
316
+/*
317
+** Set or unset the query authorizer callback function
318
+*/
319
+void db_set_authorizer(
320
+ int(*xAuth)(void*,int,const char*,const char*,const char*,const char*),
321
+ void *pArg,
322
+ const char *zName /* for tracing */
323
+){
324
+ if( db.xAuth ){
325
+ fossil_panic("multiple active db_set_authorizer() calls");
326
+ }
327
+ if( g.db ) sqlite3_set_authorizer(g.db, xAuth, pArg);
328
+ db.xAuth = xAuth;
329
+ db.pAuthArg = pArg;
330
+ db.zAuthName = zName;
331
+ if( g.fSqlTrace ) fossil_trace("-- set authorizer %s\n", zName);
332
+}
333
+void db_clear_authorizer(void){
334
+ if( db.zAuthName && g.fSqlTrace ){
335
+ fossil_trace("-- discontinue authorizer %s\n", db.zAuthName);
336
+ }
337
+ if( g.db ) sqlite3_set_authorizer(g.db, 0, 0);
338
+ db.xAuth = 0;
339
+ db.pAuthArg = 0;
340
+}
312341
313342
#if INTERFACE
314343
/*
315344
** Possible flags to db_vprepare
316345
*/
@@ -835,34 +864,37 @@
835864
void db_init_database(
836865
const char *zFileName, /* Name of database file to create */
837866
const char *zSchema, /* First part of schema */
838867
... /* Additional SQL to run. Terminate with NULL. */
839868
){
840
- sqlite3 *db;
869
+ sqlite3 *xdb;
841870
int rc;
842871
const char *zSql;
843872
va_list ap;
844873
845
- db = db_open(zFileName ? zFileName : ":memory:");
846
- sqlite3_exec(db, "BEGIN EXCLUSIVE", 0, 0, 0);
847
- rc = sqlite3_exec(db, zSchema, 0, 0, 0);
874
+ xdb = db_open(zFileName ? zFileName : ":memory:");
875
+ sqlite3_exec(xdb, "BEGIN EXCLUSIVE", 0, 0, 0);
876
+ if( db.xAuth ){
877
+ sqlite3_set_authorizer(xdb, db.xAuth, db.pAuthArg);
878
+ }
879
+ rc = sqlite3_exec(xdb, zSchema, 0, 0, 0);
848880
if( rc!=SQLITE_OK ){
849
- db_err("%s", sqlite3_errmsg(db));
881
+ db_err("%s", sqlite3_errmsg(xdb));
850882
}
851883
va_start(ap, zSchema);
852884
while( (zSql = va_arg(ap, const char*))!=0 ){
853
- rc = sqlite3_exec(db, zSql, 0, 0, 0);
885
+ rc = sqlite3_exec(xdb, zSql, 0, 0, 0);
854886
if( rc!=SQLITE_OK ){
855
- db_err("%s", sqlite3_errmsg(db));
887
+ db_err("%s", sqlite3_errmsg(xdb));
856888
}
857889
}
858890
va_end(ap);
859
- sqlite3_exec(db, "COMMIT", 0, 0, 0);
891
+ sqlite3_exec(xdb, "COMMIT", 0, 0, 0);
860892
if( zFileName || g.db!=0 ){
861
- sqlite3_close(db);
893
+ sqlite3_close(xdb);
862894
}else{
863
- g.db = db;
895
+ g.db = xdb;
864896
}
865897
}
866898
867899
/*
868900
** Function to return the number of seconds since 1970. This is
@@ -1711,11 +1743,11 @@
17111743
/*
17121744
** Returns non-zero if the default value for the "allow-symlinks" setting
17131745
** is "on". When on Windows, this always returns false.
17141746
*/
17151747
int db_allow_symlinks_by_default(void){
1716
-#if defined(_WIN32)
1748
+#if defined(_WIN32) || !defined(FOSSIL_LEGACY_ALLOW_SYMLINKS)
17171749
return 0;
17181750
#else
17191751
return 1;
17201752
#endif
17211753
}
@@ -2004,10 +2036,11 @@
20042036
** argument is true. Ignore unfinalized statements when false.
20052037
*/
20062038
void db_close(int reportErrors){
20072039
sqlite3_stmt *pStmt;
20082040
if( g.db==0 ) return;
2041
+ sqlite3_set_authorizer(g.db, 0, 0);
20092042
if( g.fSqlStats ){
20102043
int cur, hiwtr;
20112044
sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_USED, &cur, &hiwtr, 0);
20122045
fprintf(stderr, "-- LOOKASIDE_USED %10d %10d\n", cur, hiwtr);
20132046
sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &cur, &hiwtr, 0);
@@ -2033,17 +2066,20 @@
20332066
fprintf(stderr, "-- prepared statements %10d\n", db.nPrepare);
20342067
}
20352068
while( db.pAllStmt ){
20362069
db_finalize(db.pAllStmt);
20372070
}
2038
- if( db.nBegin && reportErrors ){
2039
- fossil_warning("Transaction started at %s:%d never commits",
2040
- db.zStartFile, db.iStartLine);
2071
+ if( db.nBegin ){
2072
+ if( reportErrors ){
2073
+ fossil_warning("Transaction started at %s:%d never commits",
2074
+ db.zStartFile, db.iStartLine);
2075
+ }
20412076
db_end_transaction(1);
20422077
}
20432078
pStmt = 0;
2044
- g.dbIgnoreErrors++; /* Stop "database locked" warnings from PRAGMA optimize */
2079
+ sqlite3_busy_timeout(g.db, 0);
2080
+ g.dbIgnoreErrors++; /* Stop "database locked" warnings */
20452081
sqlite3_exec(g.db, "PRAGMA optimize", 0, 0, 0);
20462082
g.dbIgnoreErrors--;
20472083
db_close_config();
20482084
20492085
/* If the localdb has a lot of unused free space,
@@ -2083,10 +2119,11 @@
20832119
if( g.db ){
20842120
int rc;
20852121
sqlite3_wal_checkpoint(g.db, 0);
20862122
rc = sqlite3_close(g.db);
20872123
if( g.fSqlTrace ) fossil_trace("-- sqlite3_close(%d)\n", rc);
2124
+ db_clear_authorizer();
20882125
}
20892126
g.db = 0;
20902127
g.repositoryOpen = 0;
20912128
g.localOpen = 0;
20922129
}
@@ -2837,17 +2874,19 @@
28372874
dflt = 0;
28382875
}
28392876
fossil_free(zVal);
28402877
return dflt;
28412878
}
2879
+#ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
28422880
int db_get_versioned_boolean(const char *zName, int dflt){
28432881
char *zVal = db_get_versioned(zName, 0);
28442882
if( zVal==0 ) return dflt;
28452883
if( is_truth(zVal) ) return 1;
28462884
if( is_false(zVal) ) return 0;
28472885
return dflt;
28482886
}
2887
+#endif /* FOSSIL_LEGACY_ALLOW_SYMLINKS */
28492888
char *db_lget(const char *zName, const char *zDefault){
28502889
return db_text(zDefault,
28512890
"SELECT value FROM vvar WHERE name=%Q", zName);
28522891
}
28532892
void db_lset(const char *zName, const char *zValue){
@@ -3025,11 +3064,13 @@
30253064
void cmd_open(void){
30263065
int emptyFlag;
30273066
int keepFlag;
30283067
int forceMissingFlag;
30293068
int allowNested;
3069
+#ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
30303070
int allowSymlinks;
3071
+#endif
30313072
int setmtimeFlag; /* --setmtime. Set mtimes on files */
30323073
static char *azNewArgv[] = { 0, "checkout", "--prompt", 0, 0, 0, 0 };
30333074
30343075
url_proxy_options();
30353076
emptyFlag = find_option("empty",0,0)!=0;
@@ -3056,10 +3097,11 @@
30563097
}else if( db_exists("SELECT 1 FROM event WHERE type='ci'") ){
30573098
g.zOpenRevision = db_get("main-branch", 0);
30583099
}
30593100
}
30603101
3102
+#ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
30613103
if( g.zOpenRevision ){
30623104
/* Since the repository is open and we know the revision now,
30633105
** refresh the allow-symlinks flag. Since neither the local
30643106
** checkout nor the configuration database are open at this
30653107
** point, this should always return the versioned setting,
@@ -3069,10 +3111,11 @@
30693111
** repository or global configuration databases only. */
30703112
allowSymlinks = db_get_versioned_boolean("allow-symlinks", -1);
30713113
}else{
30723114
allowSymlinks = -1; /* Use non-versioned settings only. */
30733115
}
3116
+#endif
30743117
30753118
#if defined(_WIN32) || defined(__CYGWIN__)
30763119
# define LOCALDB_NAME "./_FOSSIL_"
30773120
#else
30783121
# define LOCALDB_NAME "./.fslckout"
@@ -3082,10 +3125,11 @@
30823125
"COMMIT; PRAGMA journal_mode=WAL; BEGIN;",
30833126
#endif
30843127
(char*)0);
30853128
db_delete_on_failure(LOCALDB_NAME);
30863129
db_open_local(0);
3130
+#ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
30873131
if( allowSymlinks>=0 ){
30883132
/* Use the value from the versioned setting, which was read
30893133
** prior to opening the local checkout (i.e. which is most
30903134
** likely empty and does not actually contain any versioned
30913135
** setting files yet). Normally, this value would be given
@@ -3098,10 +3142,11 @@
30983142
** point, this will probably be the setting value from the
30993143
** repository or global configuration databases. */
31003144
g.allowSymlinks = db_get_boolean("allow-symlinks",
31013145
db_allow_symlinks_by_default());
31023146
}
3147
+#endif /* FOSSIL_LEGACY_ALLOW_SYMLINKS */
31033148
db_lset("repository", g.argv[2]);
31043149
db_record_repository_filename(g.argv[2]);
31053150
db_set_checkout(0);
31063151
azNewArgv[0] = g.argv[0];
31073152
g.argv = azNewArgv;
@@ -3209,11 +3254,29 @@
32093254
** SETTING: admin-log boolean default=off
32103255
**
32113256
** When the admin-log setting is enabled, configuration changes are recorded
32123257
** in the "admin_log" table of the repository.
32133258
*/
3214
-#if defined(_WIN32)
3259
+#if !defined(FOSSIL_LEGACY_ALLOW_SYMLINKS)
3260
+/*
3261
+** SETTING: allow-symlinks boolean default=off
3262
+**
3263
+** When allow-symlinks is OFF (which is the default and recommended setting)
3264
+** symbolic links are treated like text files that contain a single line of
3265
+** content which is the name of their target. If allow-symlinks is ON,
3266
+** the symbolic links are actually followed.
3267
+**
3268
+** The use of symbolic links is dangerous. If you checkout a maliciously
3269
+** crafted checkin that contains symbolic links, it is possible that files
3270
+** outside of the working directory might be overwritten.
3271
+**
3272
+** Keep this setting OFF unless you have a very good reason to turn it
3273
+** on and you implicitly trust the integrity of the repositories you
3274
+** open.
3275
+*/
3276
+#endif
3277
+#if defined(_WIN32) && defined(FOSSIL_LEGACY_ALLOW_SYMLINKS)
32153278
/*
32163279
** SETTING: allow-symlinks boolean default=off versionable
32173280
**
32183281
** When allow-symlinks is OFF, symbolic links in the repository are followed
32193282
** and treated no differently from real files. When allow-symlinks is ON,
@@ -3220,11 +3283,11 @@
32203283
** the object to which the symbolic link points is ignored, and the content
32213284
** of the symbolic link that is stored in the repository is the name of the
32223285
** object to which the symbolic link points.
32233286
*/
32243287
#endif
3225
-#if !defined(_WIN32)
3288
+#if !defined(_WIN32) && defined(FOSSIL_LEGACY_ALLOW_SYMLINKS)
32263289
/*
32273290
** SETTING: allow-symlinks boolean default=on versionable
32283291
**
32293292
** When allow-symlinks is OFF, symbolic links in the repository are followed
32303293
** and treated no differently from real files. When allow-symlinks is ON,
32313294
--- src/db.c
+++ src/db.c
@@ -123,10 +123,13 @@
123 char *azBeforeCommit[5]; /* Commands to run prior to COMMIT */
124 int nBeforeCommit; /* Number of entries in azBeforeCommit */
125 int nPriorChanges; /* sqlite3_total_changes() at transaction start */
126 const char *zStartFile; /* File in which transaction was started */
127 int iStartLine; /* Line of zStartFile where transaction started */
 
 
 
128 } db = {0, 0, 0, 0, 0, 0, };
129
130 /*
131 ** Arrange for the given file to be deleted on a failure.
132 */
@@ -307,10 +310,36 @@
307 }
308 db.aHook[db.nCommitHook].sequence = sequence;
309 db.aHook[db.nCommitHook].xHook = x;
310 db.nCommitHook++;
311 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
312
313 #if INTERFACE
314 /*
315 ** Possible flags to db_vprepare
316 */
@@ -835,34 +864,37 @@
835 void db_init_database(
836 const char *zFileName, /* Name of database file to create */
837 const char *zSchema, /* First part of schema */
838 ... /* Additional SQL to run. Terminate with NULL. */
839 ){
840 sqlite3 *db;
841 int rc;
842 const char *zSql;
843 va_list ap;
844
845 db = db_open(zFileName ? zFileName : ":memory:");
846 sqlite3_exec(db, "BEGIN EXCLUSIVE", 0, 0, 0);
847 rc = sqlite3_exec(db, zSchema, 0, 0, 0);
 
 
 
848 if( rc!=SQLITE_OK ){
849 db_err("%s", sqlite3_errmsg(db));
850 }
851 va_start(ap, zSchema);
852 while( (zSql = va_arg(ap, const char*))!=0 ){
853 rc = sqlite3_exec(db, zSql, 0, 0, 0);
854 if( rc!=SQLITE_OK ){
855 db_err("%s", sqlite3_errmsg(db));
856 }
857 }
858 va_end(ap);
859 sqlite3_exec(db, "COMMIT", 0, 0, 0);
860 if( zFileName || g.db!=0 ){
861 sqlite3_close(db);
862 }else{
863 g.db = db;
864 }
865 }
866
867 /*
868 ** Function to return the number of seconds since 1970. This is
@@ -1711,11 +1743,11 @@
1711 /*
1712 ** Returns non-zero if the default value for the "allow-symlinks" setting
1713 ** is "on". When on Windows, this always returns false.
1714 */
1715 int db_allow_symlinks_by_default(void){
1716 #if defined(_WIN32)
1717 return 0;
1718 #else
1719 return 1;
1720 #endif
1721 }
@@ -2004,10 +2036,11 @@
2004 ** argument is true. Ignore unfinalized statements when false.
2005 */
2006 void db_close(int reportErrors){
2007 sqlite3_stmt *pStmt;
2008 if( g.db==0 ) return;
 
2009 if( g.fSqlStats ){
2010 int cur, hiwtr;
2011 sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_USED, &cur, &hiwtr, 0);
2012 fprintf(stderr, "-- LOOKASIDE_USED %10d %10d\n", cur, hiwtr);
2013 sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &cur, &hiwtr, 0);
@@ -2033,17 +2066,20 @@
2033 fprintf(stderr, "-- prepared statements %10d\n", db.nPrepare);
2034 }
2035 while( db.pAllStmt ){
2036 db_finalize(db.pAllStmt);
2037 }
2038 if( db.nBegin && reportErrors ){
2039 fossil_warning("Transaction started at %s:%d never commits",
2040 db.zStartFile, db.iStartLine);
 
 
2041 db_end_transaction(1);
2042 }
2043 pStmt = 0;
2044 g.dbIgnoreErrors++; /* Stop "database locked" warnings from PRAGMA optimize */
 
2045 sqlite3_exec(g.db, "PRAGMA optimize", 0, 0, 0);
2046 g.dbIgnoreErrors--;
2047 db_close_config();
2048
2049 /* If the localdb has a lot of unused free space,
@@ -2083,10 +2119,11 @@
2083 if( g.db ){
2084 int rc;
2085 sqlite3_wal_checkpoint(g.db, 0);
2086 rc = sqlite3_close(g.db);
2087 if( g.fSqlTrace ) fossil_trace("-- sqlite3_close(%d)\n", rc);
 
2088 }
2089 g.db = 0;
2090 g.repositoryOpen = 0;
2091 g.localOpen = 0;
2092 }
@@ -2837,17 +2874,19 @@
2837 dflt = 0;
2838 }
2839 fossil_free(zVal);
2840 return dflt;
2841 }
 
2842 int db_get_versioned_boolean(const char *zName, int dflt){
2843 char *zVal = db_get_versioned(zName, 0);
2844 if( zVal==0 ) return dflt;
2845 if( is_truth(zVal) ) return 1;
2846 if( is_false(zVal) ) return 0;
2847 return dflt;
2848 }
 
2849 char *db_lget(const char *zName, const char *zDefault){
2850 return db_text(zDefault,
2851 "SELECT value FROM vvar WHERE name=%Q", zName);
2852 }
2853 void db_lset(const char *zName, const char *zValue){
@@ -3025,11 +3064,13 @@
3025 void cmd_open(void){
3026 int emptyFlag;
3027 int keepFlag;
3028 int forceMissingFlag;
3029 int allowNested;
 
3030 int allowSymlinks;
 
3031 int setmtimeFlag; /* --setmtime. Set mtimes on files */
3032 static char *azNewArgv[] = { 0, "checkout", "--prompt", 0, 0, 0, 0 };
3033
3034 url_proxy_options();
3035 emptyFlag = find_option("empty",0,0)!=0;
@@ -3056,10 +3097,11 @@
3056 }else if( db_exists("SELECT 1 FROM event WHERE type='ci'") ){
3057 g.zOpenRevision = db_get("main-branch", 0);
3058 }
3059 }
3060
 
3061 if( g.zOpenRevision ){
3062 /* Since the repository is open and we know the revision now,
3063 ** refresh the allow-symlinks flag. Since neither the local
3064 ** checkout nor the configuration database are open at this
3065 ** point, this should always return the versioned setting,
@@ -3069,10 +3111,11 @@
3069 ** repository or global configuration databases only. */
3070 allowSymlinks = db_get_versioned_boolean("allow-symlinks", -1);
3071 }else{
3072 allowSymlinks = -1; /* Use non-versioned settings only. */
3073 }
 
3074
3075 #if defined(_WIN32) || defined(__CYGWIN__)
3076 # define LOCALDB_NAME "./_FOSSIL_"
3077 #else
3078 # define LOCALDB_NAME "./.fslckout"
@@ -3082,10 +3125,11 @@
3082 "COMMIT; PRAGMA journal_mode=WAL; BEGIN;",
3083 #endif
3084 (char*)0);
3085 db_delete_on_failure(LOCALDB_NAME);
3086 db_open_local(0);
 
3087 if( allowSymlinks>=0 ){
3088 /* Use the value from the versioned setting, which was read
3089 ** prior to opening the local checkout (i.e. which is most
3090 ** likely empty and does not actually contain any versioned
3091 ** setting files yet). Normally, this value would be given
@@ -3098,10 +3142,11 @@
3098 ** point, this will probably be the setting value from the
3099 ** repository or global configuration databases. */
3100 g.allowSymlinks = db_get_boolean("allow-symlinks",
3101 db_allow_symlinks_by_default());
3102 }
 
3103 db_lset("repository", g.argv[2]);
3104 db_record_repository_filename(g.argv[2]);
3105 db_set_checkout(0);
3106 azNewArgv[0] = g.argv[0];
3107 g.argv = azNewArgv;
@@ -3209,11 +3254,29 @@
3209 ** SETTING: admin-log boolean default=off
3210 **
3211 ** When the admin-log setting is enabled, configuration changes are recorded
3212 ** in the "admin_log" table of the repository.
3213 */
3214 #if defined(_WIN32)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3215 /*
3216 ** SETTING: allow-symlinks boolean default=off versionable
3217 **
3218 ** When allow-symlinks is OFF, symbolic links in the repository are followed
3219 ** and treated no differently from real files. When allow-symlinks is ON,
@@ -3220,11 +3283,11 @@
3220 ** the object to which the symbolic link points is ignored, and the content
3221 ** of the symbolic link that is stored in the repository is the name of the
3222 ** object to which the symbolic link points.
3223 */
3224 #endif
3225 #if !defined(_WIN32)
3226 /*
3227 ** SETTING: allow-symlinks boolean default=on versionable
3228 **
3229 ** When allow-symlinks is OFF, symbolic links in the repository are followed
3230 ** and treated no differently from real files. When allow-symlinks is ON,
3231
--- src/db.c
+++ src/db.c
@@ -123,10 +123,13 @@
123 char *azBeforeCommit[5]; /* Commands to run prior to COMMIT */
124 int nBeforeCommit; /* Number of entries in azBeforeCommit */
125 int nPriorChanges; /* sqlite3_total_changes() at transaction start */
126 const char *zStartFile; /* File in which transaction was started */
127 int iStartLine; /* Line of zStartFile where transaction started */
128 int (*xAuth)(void*,int,const char*,const char*,const char*,const char*);
129 void *pAuthArg; /* Argument to the authorizer */
130 const char *zAuthName; /* Name of the authorizer */
131 } db = {0, 0, 0, 0, 0, 0, };
132
133 /*
134 ** Arrange for the given file to be deleted on a failure.
135 */
@@ -307,10 +310,36 @@
310 }
311 db.aHook[db.nCommitHook].sequence = sequence;
312 db.aHook[db.nCommitHook].xHook = x;
313 db.nCommitHook++;
314 }
315
316 /*
317 ** Set or unset the query authorizer callback function
318 */
319 void db_set_authorizer(
320 int(*xAuth)(void*,int,const char*,const char*,const char*,const char*),
321 void *pArg,
322 const char *zName /* for tracing */
323 ){
324 if( db.xAuth ){
325 fossil_panic("multiple active db_set_authorizer() calls");
326 }
327 if( g.db ) sqlite3_set_authorizer(g.db, xAuth, pArg);
328 db.xAuth = xAuth;
329 db.pAuthArg = pArg;
330 db.zAuthName = zName;
331 if( g.fSqlTrace ) fossil_trace("-- set authorizer %s\n", zName);
332 }
333 void db_clear_authorizer(void){
334 if( db.zAuthName && g.fSqlTrace ){
335 fossil_trace("-- discontinue authorizer %s\n", db.zAuthName);
336 }
337 if( g.db ) sqlite3_set_authorizer(g.db, 0, 0);
338 db.xAuth = 0;
339 db.pAuthArg = 0;
340 }
341
342 #if INTERFACE
343 /*
344 ** Possible flags to db_vprepare
345 */
@@ -835,34 +864,37 @@
864 void db_init_database(
865 const char *zFileName, /* Name of database file to create */
866 const char *zSchema, /* First part of schema */
867 ... /* Additional SQL to run. Terminate with NULL. */
868 ){
869 sqlite3 *xdb;
870 int rc;
871 const char *zSql;
872 va_list ap;
873
874 xdb = db_open(zFileName ? zFileName : ":memory:");
875 sqlite3_exec(xdb, "BEGIN EXCLUSIVE", 0, 0, 0);
876 if( db.xAuth ){
877 sqlite3_set_authorizer(xdb, db.xAuth, db.pAuthArg);
878 }
879 rc = sqlite3_exec(xdb, zSchema, 0, 0, 0);
880 if( rc!=SQLITE_OK ){
881 db_err("%s", sqlite3_errmsg(xdb));
882 }
883 va_start(ap, zSchema);
884 while( (zSql = va_arg(ap, const char*))!=0 ){
885 rc = sqlite3_exec(xdb, zSql, 0, 0, 0);
886 if( rc!=SQLITE_OK ){
887 db_err("%s", sqlite3_errmsg(xdb));
888 }
889 }
890 va_end(ap);
891 sqlite3_exec(xdb, "COMMIT", 0, 0, 0);
892 if( zFileName || g.db!=0 ){
893 sqlite3_close(xdb);
894 }else{
895 g.db = xdb;
896 }
897 }
898
899 /*
900 ** Function to return the number of seconds since 1970. This is
@@ -1711,11 +1743,11 @@
1743 /*
1744 ** Returns non-zero if the default value for the "allow-symlinks" setting
1745 ** is "on". When on Windows, this always returns false.
1746 */
1747 int db_allow_symlinks_by_default(void){
1748 #if defined(_WIN32) || !defined(FOSSIL_LEGACY_ALLOW_SYMLINKS)
1749 return 0;
1750 #else
1751 return 1;
1752 #endif
1753 }
@@ -2004,10 +2036,11 @@
2036 ** argument is true. Ignore unfinalized statements when false.
2037 */
2038 void db_close(int reportErrors){
2039 sqlite3_stmt *pStmt;
2040 if( g.db==0 ) return;
2041 sqlite3_set_authorizer(g.db, 0, 0);
2042 if( g.fSqlStats ){
2043 int cur, hiwtr;
2044 sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_USED, &cur, &hiwtr, 0);
2045 fprintf(stderr, "-- LOOKASIDE_USED %10d %10d\n", cur, hiwtr);
2046 sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &cur, &hiwtr, 0);
@@ -2033,17 +2066,20 @@
2066 fprintf(stderr, "-- prepared statements %10d\n", db.nPrepare);
2067 }
2068 while( db.pAllStmt ){
2069 db_finalize(db.pAllStmt);
2070 }
2071 if( db.nBegin ){
2072 if( reportErrors ){
2073 fossil_warning("Transaction started at %s:%d never commits",
2074 db.zStartFile, db.iStartLine);
2075 }
2076 db_end_transaction(1);
2077 }
2078 pStmt = 0;
2079 sqlite3_busy_timeout(g.db, 0);
2080 g.dbIgnoreErrors++; /* Stop "database locked" warnings */
2081 sqlite3_exec(g.db, "PRAGMA optimize", 0, 0, 0);
2082 g.dbIgnoreErrors--;
2083 db_close_config();
2084
2085 /* If the localdb has a lot of unused free space,
@@ -2083,10 +2119,11 @@
2119 if( g.db ){
2120 int rc;
2121 sqlite3_wal_checkpoint(g.db, 0);
2122 rc = sqlite3_close(g.db);
2123 if( g.fSqlTrace ) fossil_trace("-- sqlite3_close(%d)\n", rc);
2124 db_clear_authorizer();
2125 }
2126 g.db = 0;
2127 g.repositoryOpen = 0;
2128 g.localOpen = 0;
2129 }
@@ -2837,17 +2874,19 @@
2874 dflt = 0;
2875 }
2876 fossil_free(zVal);
2877 return dflt;
2878 }
2879 #ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
2880 int db_get_versioned_boolean(const char *zName, int dflt){
2881 char *zVal = db_get_versioned(zName, 0);
2882 if( zVal==0 ) return dflt;
2883 if( is_truth(zVal) ) return 1;
2884 if( is_false(zVal) ) return 0;
2885 return dflt;
2886 }
2887 #endif /* FOSSIL_LEGACY_ALLOW_SYMLINKS */
2888 char *db_lget(const char *zName, const char *zDefault){
2889 return db_text(zDefault,
2890 "SELECT value FROM vvar WHERE name=%Q", zName);
2891 }
2892 void db_lset(const char *zName, const char *zValue){
@@ -3025,11 +3064,13 @@
3064 void cmd_open(void){
3065 int emptyFlag;
3066 int keepFlag;
3067 int forceMissingFlag;
3068 int allowNested;
3069 #ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
3070 int allowSymlinks;
3071 #endif
3072 int setmtimeFlag; /* --setmtime. Set mtimes on files */
3073 static char *azNewArgv[] = { 0, "checkout", "--prompt", 0, 0, 0, 0 };
3074
3075 url_proxy_options();
3076 emptyFlag = find_option("empty",0,0)!=0;
@@ -3056,10 +3097,11 @@
3097 }else if( db_exists("SELECT 1 FROM event WHERE type='ci'") ){
3098 g.zOpenRevision = db_get("main-branch", 0);
3099 }
3100 }
3101
3102 #ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
3103 if( g.zOpenRevision ){
3104 /* Since the repository is open and we know the revision now,
3105 ** refresh the allow-symlinks flag. Since neither the local
3106 ** checkout nor the configuration database are open at this
3107 ** point, this should always return the versioned setting,
@@ -3069,10 +3111,11 @@
3111 ** repository or global configuration databases only. */
3112 allowSymlinks = db_get_versioned_boolean("allow-symlinks", -1);
3113 }else{
3114 allowSymlinks = -1; /* Use non-versioned settings only. */
3115 }
3116 #endif
3117
3118 #if defined(_WIN32) || defined(__CYGWIN__)
3119 # define LOCALDB_NAME "./_FOSSIL_"
3120 #else
3121 # define LOCALDB_NAME "./.fslckout"
@@ -3082,10 +3125,11 @@
3125 "COMMIT; PRAGMA journal_mode=WAL; BEGIN;",
3126 #endif
3127 (char*)0);
3128 db_delete_on_failure(LOCALDB_NAME);
3129 db_open_local(0);
3130 #ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
3131 if( allowSymlinks>=0 ){
3132 /* Use the value from the versioned setting, which was read
3133 ** prior to opening the local checkout (i.e. which is most
3134 ** likely empty and does not actually contain any versioned
3135 ** setting files yet). Normally, this value would be given
@@ -3098,10 +3142,11 @@
3142 ** point, this will probably be the setting value from the
3143 ** repository or global configuration databases. */
3144 g.allowSymlinks = db_get_boolean("allow-symlinks",
3145 db_allow_symlinks_by_default());
3146 }
3147 #endif /* FOSSIL_LEGACY_ALLOW_SYMLINKS */
3148 db_lset("repository", g.argv[2]);
3149 db_record_repository_filename(g.argv[2]);
3150 db_set_checkout(0);
3151 azNewArgv[0] = g.argv[0];
3152 g.argv = azNewArgv;
@@ -3209,11 +3254,29 @@
3254 ** SETTING: admin-log boolean default=off
3255 **
3256 ** When the admin-log setting is enabled, configuration changes are recorded
3257 ** in the "admin_log" table of the repository.
3258 */
3259 #if !defined(FOSSIL_LEGACY_ALLOW_SYMLINKS)
3260 /*
3261 ** SETTING: allow-symlinks boolean default=off
3262 **
3263 ** When allow-symlinks is OFF (which is the default and recommended setting)
3264 ** symbolic links are treated like text files that contain a single line of
3265 ** content which is the name of their target. If allow-symlinks is ON,
3266 ** the symbolic links are actually followed.
3267 **
3268 ** The use of symbolic links is dangerous. If you checkout a maliciously
3269 ** crafted checkin that contains symbolic links, it is possible that files
3270 ** outside of the working directory might be overwritten.
3271 **
3272 ** Keep this setting OFF unless you have a very good reason to turn it
3273 ** on and you implicitly trust the integrity of the repositories you
3274 ** open.
3275 */
3276 #endif
3277 #if defined(_WIN32) && defined(FOSSIL_LEGACY_ALLOW_SYMLINKS)
3278 /*
3279 ** SETTING: allow-symlinks boolean default=off versionable
3280 **
3281 ** When allow-symlinks is OFF, symbolic links in the repository are followed
3282 ** and treated no differently from real files. When allow-symlinks is ON,
@@ -3220,11 +3283,11 @@
3283 ** the object to which the symbolic link points is ignored, and the content
3284 ** of the symbolic link that is stored in the repository is the name of the
3285 ** object to which the symbolic link points.
3286 */
3287 #endif
3288 #if !defined(_WIN32) && defined(FOSSIL_LEGACY_ALLOW_SYMLINKS)
3289 /*
3290 ** SETTING: allow-symlinks boolean default=on versionable
3291 **
3292 ** When allow-symlinks is OFF, symbolic links in the repository are followed
3293 ** and treated no differently from real files. When allow-symlinks is ON,
3294
+80 -17
--- src/db.c
+++ src/db.c
@@ -123,10 +123,13 @@
123123
char *azBeforeCommit[5]; /* Commands to run prior to COMMIT */
124124
int nBeforeCommit; /* Number of entries in azBeforeCommit */
125125
int nPriorChanges; /* sqlite3_total_changes() at transaction start */
126126
const char *zStartFile; /* File in which transaction was started */
127127
int iStartLine; /* Line of zStartFile where transaction started */
128
+ int (*xAuth)(void*,int,const char*,const char*,const char*,const char*);
129
+ void *pAuthArg; /* Argument to the authorizer */
130
+ const char *zAuthName; /* Name of the authorizer */
128131
} db = {0, 0, 0, 0, 0, 0, };
129132
130133
/*
131134
** Arrange for the given file to be deleted on a failure.
132135
*/
@@ -307,10 +310,36 @@
307310
}
308311
db.aHook[db.nCommitHook].sequence = sequence;
309312
db.aHook[db.nCommitHook].xHook = x;
310313
db.nCommitHook++;
311314
}
315
+
316
+/*
317
+** Set or unset the query authorizer callback function
318
+*/
319
+void db_set_authorizer(
320
+ int(*xAuth)(void*,int,const char*,const char*,const char*,const char*),
321
+ void *pArg,
322
+ const char *zName /* for tracing */
323
+){
324
+ if( db.xAuth ){
325
+ fossil_panic("multiple active db_set_authorizer() calls");
326
+ }
327
+ if( g.db ) sqlite3_set_authorizer(g.db, xAuth, pArg);
328
+ db.xAuth = xAuth;
329
+ db.pAuthArg = pArg;
330
+ db.zAuthName = zName;
331
+ if( g.fSqlTrace ) fossil_trace("-- set authorizer %s\n", zName);
332
+}
333
+void db_clear_authorizer(void){
334
+ if( db.zAuthName && g.fSqlTrace ){
335
+ fossil_trace("-- discontinue authorizer %s\n", db.zAuthName);
336
+ }
337
+ if( g.db ) sqlite3_set_authorizer(g.db, 0, 0);
338
+ db.xAuth = 0;
339
+ db.pAuthArg = 0;
340
+}
312341
313342
#if INTERFACE
314343
/*
315344
** Possible flags to db_vprepare
316345
*/
@@ -835,34 +864,37 @@
835864
void db_init_database(
836865
const char *zFileName, /* Name of database file to create */
837866
const char *zSchema, /* First part of schema */
838867
... /* Additional SQL to run. Terminate with NULL. */
839868
){
840
- sqlite3 *db;
869
+ sqlite3 *xdb;
841870
int rc;
842871
const char *zSql;
843872
va_list ap;
844873
845
- db = db_open(zFileName ? zFileName : ":memory:");
846
- sqlite3_exec(db, "BEGIN EXCLUSIVE", 0, 0, 0);
847
- rc = sqlite3_exec(db, zSchema, 0, 0, 0);
874
+ xdb = db_open(zFileName ? zFileName : ":memory:");
875
+ sqlite3_exec(xdb, "BEGIN EXCLUSIVE", 0, 0, 0);
876
+ if( db.xAuth ){
877
+ sqlite3_set_authorizer(xdb, db.xAuth, db.pAuthArg);
878
+ }
879
+ rc = sqlite3_exec(xdb, zSchema, 0, 0, 0);
848880
if( rc!=SQLITE_OK ){
849
- db_err("%s", sqlite3_errmsg(db));
881
+ db_err("%s", sqlite3_errmsg(xdb));
850882
}
851883
va_start(ap, zSchema);
852884
while( (zSql = va_arg(ap, const char*))!=0 ){
853
- rc = sqlite3_exec(db, zSql, 0, 0, 0);
885
+ rc = sqlite3_exec(xdb, zSql, 0, 0, 0);
854886
if( rc!=SQLITE_OK ){
855
- db_err("%s", sqlite3_errmsg(db));
887
+ db_err("%s", sqlite3_errmsg(xdb));
856888
}
857889
}
858890
va_end(ap);
859
- sqlite3_exec(db, "COMMIT", 0, 0, 0);
891
+ sqlite3_exec(xdb, "COMMIT", 0, 0, 0);
860892
if( zFileName || g.db!=0 ){
861
- sqlite3_close(db);
893
+ sqlite3_close(xdb);
862894
}else{
863
- g.db = db;
895
+ g.db = xdb;
864896
}
865897
}
866898
867899
/*
868900
** Function to return the number of seconds since 1970. This is
@@ -1711,11 +1743,11 @@
17111743
/*
17121744
** Returns non-zero if the default value for the "allow-symlinks" setting
17131745
** is "on". When on Windows, this always returns false.
17141746
*/
17151747
int db_allow_symlinks_by_default(void){
1716
-#if defined(_WIN32)
1748
+#if defined(_WIN32) || !defined(FOSSIL_LEGACY_ALLOW_SYMLINKS)
17171749
return 0;
17181750
#else
17191751
return 1;
17201752
#endif
17211753
}
@@ -2004,10 +2036,11 @@
20042036
** argument is true. Ignore unfinalized statements when false.
20052037
*/
20062038
void db_close(int reportErrors){
20072039
sqlite3_stmt *pStmt;
20082040
if( g.db==0 ) return;
2041
+ sqlite3_set_authorizer(g.db, 0, 0);
20092042
if( g.fSqlStats ){
20102043
int cur, hiwtr;
20112044
sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_USED, &cur, &hiwtr, 0);
20122045
fprintf(stderr, "-- LOOKASIDE_USED %10d %10d\n", cur, hiwtr);
20132046
sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &cur, &hiwtr, 0);
@@ -2033,17 +2066,20 @@
20332066
fprintf(stderr, "-- prepared statements %10d\n", db.nPrepare);
20342067
}
20352068
while( db.pAllStmt ){
20362069
db_finalize(db.pAllStmt);
20372070
}
2038
- if( db.nBegin && reportErrors ){
2039
- fossil_warning("Transaction started at %s:%d never commits",
2040
- db.zStartFile, db.iStartLine);
2071
+ if( db.nBegin ){
2072
+ if( reportErrors ){
2073
+ fossil_warning("Transaction started at %s:%d never commits",
2074
+ db.zStartFile, db.iStartLine);
2075
+ }
20412076
db_end_transaction(1);
20422077
}
20432078
pStmt = 0;
2044
- g.dbIgnoreErrors++; /* Stop "database locked" warnings from PRAGMA optimize */
2079
+ sqlite3_busy_timeout(g.db, 0);
2080
+ g.dbIgnoreErrors++; /* Stop "database locked" warnings */
20452081
sqlite3_exec(g.db, "PRAGMA optimize", 0, 0, 0);
20462082
g.dbIgnoreErrors--;
20472083
db_close_config();
20482084
20492085
/* If the localdb has a lot of unused free space,
@@ -2083,10 +2119,11 @@
20832119
if( g.db ){
20842120
int rc;
20852121
sqlite3_wal_checkpoint(g.db, 0);
20862122
rc = sqlite3_close(g.db);
20872123
if( g.fSqlTrace ) fossil_trace("-- sqlite3_close(%d)\n", rc);
2124
+ db_clear_authorizer();
20882125
}
20892126
g.db = 0;
20902127
g.repositoryOpen = 0;
20912128
g.localOpen = 0;
20922129
}
@@ -2837,17 +2874,19 @@
28372874
dflt = 0;
28382875
}
28392876
fossil_free(zVal);
28402877
return dflt;
28412878
}
2879
+#ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
28422880
int db_get_versioned_boolean(const char *zName, int dflt){
28432881
char *zVal = db_get_versioned(zName, 0);
28442882
if( zVal==0 ) return dflt;
28452883
if( is_truth(zVal) ) return 1;
28462884
if( is_false(zVal) ) return 0;
28472885
return dflt;
28482886
}
2887
+#endif /* FOSSIL_LEGACY_ALLOW_SYMLINKS */
28492888
char *db_lget(const char *zName, const char *zDefault){
28502889
return db_text(zDefault,
28512890
"SELECT value FROM vvar WHERE name=%Q", zName);
28522891
}
28532892
void db_lset(const char *zName, const char *zValue){
@@ -3025,11 +3064,13 @@
30253064
void cmd_open(void){
30263065
int emptyFlag;
30273066
int keepFlag;
30283067
int forceMissingFlag;
30293068
int allowNested;
3069
+#ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
30303070
int allowSymlinks;
3071
+#endif
30313072
int setmtimeFlag; /* --setmtime. Set mtimes on files */
30323073
static char *azNewArgv[] = { 0, "checkout", "--prompt", 0, 0, 0, 0 };
30333074
30343075
url_proxy_options();
30353076
emptyFlag = find_option("empty",0,0)!=0;
@@ -3056,10 +3097,11 @@
30563097
}else if( db_exists("SELECT 1 FROM event WHERE type='ci'") ){
30573098
g.zOpenRevision = db_get("main-branch", 0);
30583099
}
30593100
}
30603101
3102
+#ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
30613103
if( g.zOpenRevision ){
30623104
/* Since the repository is open and we know the revision now,
30633105
** refresh the allow-symlinks flag. Since neither the local
30643106
** checkout nor the configuration database are open at this
30653107
** point, this should always return the versioned setting,
@@ -3069,10 +3111,11 @@
30693111
** repository or global configuration databases only. */
30703112
allowSymlinks = db_get_versioned_boolean("allow-symlinks", -1);
30713113
}else{
30723114
allowSymlinks = -1; /* Use non-versioned settings only. */
30733115
}
3116
+#endif
30743117
30753118
#if defined(_WIN32) || defined(__CYGWIN__)
30763119
# define LOCALDB_NAME "./_FOSSIL_"
30773120
#else
30783121
# define LOCALDB_NAME "./.fslckout"
@@ -3082,10 +3125,11 @@
30823125
"COMMIT; PRAGMA journal_mode=WAL; BEGIN;",
30833126
#endif
30843127
(char*)0);
30853128
db_delete_on_failure(LOCALDB_NAME);
30863129
db_open_local(0);
3130
+#ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
30873131
if( allowSymlinks>=0 ){
30883132
/* Use the value from the versioned setting, which was read
30893133
** prior to opening the local checkout (i.e. which is most
30903134
** likely empty and does not actually contain any versioned
30913135
** setting files yet). Normally, this value would be given
@@ -3098,10 +3142,11 @@
30983142
** point, this will probably be the setting value from the
30993143
** repository or global configuration databases. */
31003144
g.allowSymlinks = db_get_boolean("allow-symlinks",
31013145
db_allow_symlinks_by_default());
31023146
}
3147
+#endif /* FOSSIL_LEGACY_ALLOW_SYMLINKS */
31033148
db_lset("repository", g.argv[2]);
31043149
db_record_repository_filename(g.argv[2]);
31053150
db_set_checkout(0);
31063151
azNewArgv[0] = g.argv[0];
31073152
g.argv = azNewArgv;
@@ -3209,11 +3254,29 @@
32093254
** SETTING: admin-log boolean default=off
32103255
**
32113256
** When the admin-log setting is enabled, configuration changes are recorded
32123257
** in the "admin_log" table of the repository.
32133258
*/
3214
-#if defined(_WIN32)
3259
+#if !defined(FOSSIL_LEGACY_ALLOW_SYMLINKS)
3260
+/*
3261
+** SETTING: allow-symlinks boolean default=off
3262
+**
3263
+** When allow-symlinks is OFF (which is the default and recommended setting)
3264
+** symbolic links are treated like text files that contain a single line of
3265
+** content which is the name of their target. If allow-symlinks is ON,
3266
+** the symbolic links are actually followed.
3267
+**
3268
+** The use of symbolic links is dangerous. If you checkout a maliciously
3269
+** crafted checkin that contains symbolic links, it is possible that files
3270
+** outside of the working directory might be overwritten.
3271
+**
3272
+** Keep this setting OFF unless you have a very good reason to turn it
3273
+** on and you implicitly trust the integrity of the repositories you
3274
+** open.
3275
+*/
3276
+#endif
3277
+#if defined(_WIN32) && defined(FOSSIL_LEGACY_ALLOW_SYMLINKS)
32153278
/*
32163279
** SETTING: allow-symlinks boolean default=off versionable
32173280
**
32183281
** When allow-symlinks is OFF, symbolic links in the repository are followed
32193282
** and treated no differently from real files. When allow-symlinks is ON,
@@ -3220,11 +3283,11 @@
32203283
** the object to which the symbolic link points is ignored, and the content
32213284
** of the symbolic link that is stored in the repository is the name of the
32223285
** object to which the symbolic link points.
32233286
*/
32243287
#endif
3225
-#if !defined(_WIN32)
3288
+#if !defined(_WIN32) && defined(FOSSIL_LEGACY_ALLOW_SYMLINKS)
32263289
/*
32273290
** SETTING: allow-symlinks boolean default=on versionable
32283291
**
32293292
** When allow-symlinks is OFF, symbolic links in the repository are followed
32303293
** and treated no differently from real files. When allow-symlinks is ON,
32313294
--- src/db.c
+++ src/db.c
@@ -123,10 +123,13 @@
123 char *azBeforeCommit[5]; /* Commands to run prior to COMMIT */
124 int nBeforeCommit; /* Number of entries in azBeforeCommit */
125 int nPriorChanges; /* sqlite3_total_changes() at transaction start */
126 const char *zStartFile; /* File in which transaction was started */
127 int iStartLine; /* Line of zStartFile where transaction started */
 
 
 
128 } db = {0, 0, 0, 0, 0, 0, };
129
130 /*
131 ** Arrange for the given file to be deleted on a failure.
132 */
@@ -307,10 +310,36 @@
307 }
308 db.aHook[db.nCommitHook].sequence = sequence;
309 db.aHook[db.nCommitHook].xHook = x;
310 db.nCommitHook++;
311 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
312
313 #if INTERFACE
314 /*
315 ** Possible flags to db_vprepare
316 */
@@ -835,34 +864,37 @@
835 void db_init_database(
836 const char *zFileName, /* Name of database file to create */
837 const char *zSchema, /* First part of schema */
838 ... /* Additional SQL to run. Terminate with NULL. */
839 ){
840 sqlite3 *db;
841 int rc;
842 const char *zSql;
843 va_list ap;
844
845 db = db_open(zFileName ? zFileName : ":memory:");
846 sqlite3_exec(db, "BEGIN EXCLUSIVE", 0, 0, 0);
847 rc = sqlite3_exec(db, zSchema, 0, 0, 0);
 
 
 
848 if( rc!=SQLITE_OK ){
849 db_err("%s", sqlite3_errmsg(db));
850 }
851 va_start(ap, zSchema);
852 while( (zSql = va_arg(ap, const char*))!=0 ){
853 rc = sqlite3_exec(db, zSql, 0, 0, 0);
854 if( rc!=SQLITE_OK ){
855 db_err("%s", sqlite3_errmsg(db));
856 }
857 }
858 va_end(ap);
859 sqlite3_exec(db, "COMMIT", 0, 0, 0);
860 if( zFileName || g.db!=0 ){
861 sqlite3_close(db);
862 }else{
863 g.db = db;
864 }
865 }
866
867 /*
868 ** Function to return the number of seconds since 1970. This is
@@ -1711,11 +1743,11 @@
1711 /*
1712 ** Returns non-zero if the default value for the "allow-symlinks" setting
1713 ** is "on". When on Windows, this always returns false.
1714 */
1715 int db_allow_symlinks_by_default(void){
1716 #if defined(_WIN32)
1717 return 0;
1718 #else
1719 return 1;
1720 #endif
1721 }
@@ -2004,10 +2036,11 @@
2004 ** argument is true. Ignore unfinalized statements when false.
2005 */
2006 void db_close(int reportErrors){
2007 sqlite3_stmt *pStmt;
2008 if( g.db==0 ) return;
 
2009 if( g.fSqlStats ){
2010 int cur, hiwtr;
2011 sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_USED, &cur, &hiwtr, 0);
2012 fprintf(stderr, "-- LOOKASIDE_USED %10d %10d\n", cur, hiwtr);
2013 sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &cur, &hiwtr, 0);
@@ -2033,17 +2066,20 @@
2033 fprintf(stderr, "-- prepared statements %10d\n", db.nPrepare);
2034 }
2035 while( db.pAllStmt ){
2036 db_finalize(db.pAllStmt);
2037 }
2038 if( db.nBegin && reportErrors ){
2039 fossil_warning("Transaction started at %s:%d never commits",
2040 db.zStartFile, db.iStartLine);
 
 
2041 db_end_transaction(1);
2042 }
2043 pStmt = 0;
2044 g.dbIgnoreErrors++; /* Stop "database locked" warnings from PRAGMA optimize */
 
2045 sqlite3_exec(g.db, "PRAGMA optimize", 0, 0, 0);
2046 g.dbIgnoreErrors--;
2047 db_close_config();
2048
2049 /* If the localdb has a lot of unused free space,
@@ -2083,10 +2119,11 @@
2083 if( g.db ){
2084 int rc;
2085 sqlite3_wal_checkpoint(g.db, 0);
2086 rc = sqlite3_close(g.db);
2087 if( g.fSqlTrace ) fossil_trace("-- sqlite3_close(%d)\n", rc);
 
2088 }
2089 g.db = 0;
2090 g.repositoryOpen = 0;
2091 g.localOpen = 0;
2092 }
@@ -2837,17 +2874,19 @@
2837 dflt = 0;
2838 }
2839 fossil_free(zVal);
2840 return dflt;
2841 }
 
2842 int db_get_versioned_boolean(const char *zName, int dflt){
2843 char *zVal = db_get_versioned(zName, 0);
2844 if( zVal==0 ) return dflt;
2845 if( is_truth(zVal) ) return 1;
2846 if( is_false(zVal) ) return 0;
2847 return dflt;
2848 }
 
2849 char *db_lget(const char *zName, const char *zDefault){
2850 return db_text(zDefault,
2851 "SELECT value FROM vvar WHERE name=%Q", zName);
2852 }
2853 void db_lset(const char *zName, const char *zValue){
@@ -3025,11 +3064,13 @@
3025 void cmd_open(void){
3026 int emptyFlag;
3027 int keepFlag;
3028 int forceMissingFlag;
3029 int allowNested;
 
3030 int allowSymlinks;
 
3031 int setmtimeFlag; /* --setmtime. Set mtimes on files */
3032 static char *azNewArgv[] = { 0, "checkout", "--prompt", 0, 0, 0, 0 };
3033
3034 url_proxy_options();
3035 emptyFlag = find_option("empty",0,0)!=0;
@@ -3056,10 +3097,11 @@
3056 }else if( db_exists("SELECT 1 FROM event WHERE type='ci'") ){
3057 g.zOpenRevision = db_get("main-branch", 0);
3058 }
3059 }
3060
 
3061 if( g.zOpenRevision ){
3062 /* Since the repository is open and we know the revision now,
3063 ** refresh the allow-symlinks flag. Since neither the local
3064 ** checkout nor the configuration database are open at this
3065 ** point, this should always return the versioned setting,
@@ -3069,10 +3111,11 @@
3069 ** repository or global configuration databases only. */
3070 allowSymlinks = db_get_versioned_boolean("allow-symlinks", -1);
3071 }else{
3072 allowSymlinks = -1; /* Use non-versioned settings only. */
3073 }
 
3074
3075 #if defined(_WIN32) || defined(__CYGWIN__)
3076 # define LOCALDB_NAME "./_FOSSIL_"
3077 #else
3078 # define LOCALDB_NAME "./.fslckout"
@@ -3082,10 +3125,11 @@
3082 "COMMIT; PRAGMA journal_mode=WAL; BEGIN;",
3083 #endif
3084 (char*)0);
3085 db_delete_on_failure(LOCALDB_NAME);
3086 db_open_local(0);
 
3087 if( allowSymlinks>=0 ){
3088 /* Use the value from the versioned setting, which was read
3089 ** prior to opening the local checkout (i.e. which is most
3090 ** likely empty and does not actually contain any versioned
3091 ** setting files yet). Normally, this value would be given
@@ -3098,10 +3142,11 @@
3098 ** point, this will probably be the setting value from the
3099 ** repository or global configuration databases. */
3100 g.allowSymlinks = db_get_boolean("allow-symlinks",
3101 db_allow_symlinks_by_default());
3102 }
 
3103 db_lset("repository", g.argv[2]);
3104 db_record_repository_filename(g.argv[2]);
3105 db_set_checkout(0);
3106 azNewArgv[0] = g.argv[0];
3107 g.argv = azNewArgv;
@@ -3209,11 +3254,29 @@
3209 ** SETTING: admin-log boolean default=off
3210 **
3211 ** When the admin-log setting is enabled, configuration changes are recorded
3212 ** in the "admin_log" table of the repository.
3213 */
3214 #if defined(_WIN32)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3215 /*
3216 ** SETTING: allow-symlinks boolean default=off versionable
3217 **
3218 ** When allow-symlinks is OFF, symbolic links in the repository are followed
3219 ** and treated no differently from real files. When allow-symlinks is ON,
@@ -3220,11 +3283,11 @@
3220 ** the object to which the symbolic link points is ignored, and the content
3221 ** of the symbolic link that is stored in the repository is the name of the
3222 ** object to which the symbolic link points.
3223 */
3224 #endif
3225 #if !defined(_WIN32)
3226 /*
3227 ** SETTING: allow-symlinks boolean default=on versionable
3228 **
3229 ** When allow-symlinks is OFF, symbolic links in the repository are followed
3230 ** and treated no differently from real files. When allow-symlinks is ON,
3231
--- src/db.c
+++ src/db.c
@@ -123,10 +123,13 @@
123 char *azBeforeCommit[5]; /* Commands to run prior to COMMIT */
124 int nBeforeCommit; /* Number of entries in azBeforeCommit */
125 int nPriorChanges; /* sqlite3_total_changes() at transaction start */
126 const char *zStartFile; /* File in which transaction was started */
127 int iStartLine; /* Line of zStartFile where transaction started */
128 int (*xAuth)(void*,int,const char*,const char*,const char*,const char*);
129 void *pAuthArg; /* Argument to the authorizer */
130 const char *zAuthName; /* Name of the authorizer */
131 } db = {0, 0, 0, 0, 0, 0, };
132
133 /*
134 ** Arrange for the given file to be deleted on a failure.
135 */
@@ -307,10 +310,36 @@
310 }
311 db.aHook[db.nCommitHook].sequence = sequence;
312 db.aHook[db.nCommitHook].xHook = x;
313 db.nCommitHook++;
314 }
315
316 /*
317 ** Set or unset the query authorizer callback function
318 */
319 void db_set_authorizer(
320 int(*xAuth)(void*,int,const char*,const char*,const char*,const char*),
321 void *pArg,
322 const char *zName /* for tracing */
323 ){
324 if( db.xAuth ){
325 fossil_panic("multiple active db_set_authorizer() calls");
326 }
327 if( g.db ) sqlite3_set_authorizer(g.db, xAuth, pArg);
328 db.xAuth = xAuth;
329 db.pAuthArg = pArg;
330 db.zAuthName = zName;
331 if( g.fSqlTrace ) fossil_trace("-- set authorizer %s\n", zName);
332 }
333 void db_clear_authorizer(void){
334 if( db.zAuthName && g.fSqlTrace ){
335 fossil_trace("-- discontinue authorizer %s\n", db.zAuthName);
336 }
337 if( g.db ) sqlite3_set_authorizer(g.db, 0, 0);
338 db.xAuth = 0;
339 db.pAuthArg = 0;
340 }
341
342 #if INTERFACE
343 /*
344 ** Possible flags to db_vprepare
345 */
@@ -835,34 +864,37 @@
864 void db_init_database(
865 const char *zFileName, /* Name of database file to create */
866 const char *zSchema, /* First part of schema */
867 ... /* Additional SQL to run. Terminate with NULL. */
868 ){
869 sqlite3 *xdb;
870 int rc;
871 const char *zSql;
872 va_list ap;
873
874 xdb = db_open(zFileName ? zFileName : ":memory:");
875 sqlite3_exec(xdb, "BEGIN EXCLUSIVE", 0, 0, 0);
876 if( db.xAuth ){
877 sqlite3_set_authorizer(xdb, db.xAuth, db.pAuthArg);
878 }
879 rc = sqlite3_exec(xdb, zSchema, 0, 0, 0);
880 if( rc!=SQLITE_OK ){
881 db_err("%s", sqlite3_errmsg(xdb));
882 }
883 va_start(ap, zSchema);
884 while( (zSql = va_arg(ap, const char*))!=0 ){
885 rc = sqlite3_exec(xdb, zSql, 0, 0, 0);
886 if( rc!=SQLITE_OK ){
887 db_err("%s", sqlite3_errmsg(xdb));
888 }
889 }
890 va_end(ap);
891 sqlite3_exec(xdb, "COMMIT", 0, 0, 0);
892 if( zFileName || g.db!=0 ){
893 sqlite3_close(xdb);
894 }else{
895 g.db = xdb;
896 }
897 }
898
899 /*
900 ** Function to return the number of seconds since 1970. This is
@@ -1711,11 +1743,11 @@
1743 /*
1744 ** Returns non-zero if the default value for the "allow-symlinks" setting
1745 ** is "on". When on Windows, this always returns false.
1746 */
1747 int db_allow_symlinks_by_default(void){
1748 #if defined(_WIN32) || !defined(FOSSIL_LEGACY_ALLOW_SYMLINKS)
1749 return 0;
1750 #else
1751 return 1;
1752 #endif
1753 }
@@ -2004,10 +2036,11 @@
2036 ** argument is true. Ignore unfinalized statements when false.
2037 */
2038 void db_close(int reportErrors){
2039 sqlite3_stmt *pStmt;
2040 if( g.db==0 ) return;
2041 sqlite3_set_authorizer(g.db, 0, 0);
2042 if( g.fSqlStats ){
2043 int cur, hiwtr;
2044 sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_USED, &cur, &hiwtr, 0);
2045 fprintf(stderr, "-- LOOKASIDE_USED %10d %10d\n", cur, hiwtr);
2046 sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &cur, &hiwtr, 0);
@@ -2033,17 +2066,20 @@
2066 fprintf(stderr, "-- prepared statements %10d\n", db.nPrepare);
2067 }
2068 while( db.pAllStmt ){
2069 db_finalize(db.pAllStmt);
2070 }
2071 if( db.nBegin ){
2072 if( reportErrors ){
2073 fossil_warning("Transaction started at %s:%d never commits",
2074 db.zStartFile, db.iStartLine);
2075 }
2076 db_end_transaction(1);
2077 }
2078 pStmt = 0;
2079 sqlite3_busy_timeout(g.db, 0);
2080 g.dbIgnoreErrors++; /* Stop "database locked" warnings */
2081 sqlite3_exec(g.db, "PRAGMA optimize", 0, 0, 0);
2082 g.dbIgnoreErrors--;
2083 db_close_config();
2084
2085 /* If the localdb has a lot of unused free space,
@@ -2083,10 +2119,11 @@
2119 if( g.db ){
2120 int rc;
2121 sqlite3_wal_checkpoint(g.db, 0);
2122 rc = sqlite3_close(g.db);
2123 if( g.fSqlTrace ) fossil_trace("-- sqlite3_close(%d)\n", rc);
2124 db_clear_authorizer();
2125 }
2126 g.db = 0;
2127 g.repositoryOpen = 0;
2128 g.localOpen = 0;
2129 }
@@ -2837,17 +2874,19 @@
2874 dflt = 0;
2875 }
2876 fossil_free(zVal);
2877 return dflt;
2878 }
2879 #ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
2880 int db_get_versioned_boolean(const char *zName, int dflt){
2881 char *zVal = db_get_versioned(zName, 0);
2882 if( zVal==0 ) return dflt;
2883 if( is_truth(zVal) ) return 1;
2884 if( is_false(zVal) ) return 0;
2885 return dflt;
2886 }
2887 #endif /* FOSSIL_LEGACY_ALLOW_SYMLINKS */
2888 char *db_lget(const char *zName, const char *zDefault){
2889 return db_text(zDefault,
2890 "SELECT value FROM vvar WHERE name=%Q", zName);
2891 }
2892 void db_lset(const char *zName, const char *zValue){
@@ -3025,11 +3064,13 @@
3064 void cmd_open(void){
3065 int emptyFlag;
3066 int keepFlag;
3067 int forceMissingFlag;
3068 int allowNested;
3069 #ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
3070 int allowSymlinks;
3071 #endif
3072 int setmtimeFlag; /* --setmtime. Set mtimes on files */
3073 static char *azNewArgv[] = { 0, "checkout", "--prompt", 0, 0, 0, 0 };
3074
3075 url_proxy_options();
3076 emptyFlag = find_option("empty",0,0)!=0;
@@ -3056,10 +3097,11 @@
3097 }else if( db_exists("SELECT 1 FROM event WHERE type='ci'") ){
3098 g.zOpenRevision = db_get("main-branch", 0);
3099 }
3100 }
3101
3102 #ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
3103 if( g.zOpenRevision ){
3104 /* Since the repository is open and we know the revision now,
3105 ** refresh the allow-symlinks flag. Since neither the local
3106 ** checkout nor the configuration database are open at this
3107 ** point, this should always return the versioned setting,
@@ -3069,10 +3111,11 @@
3111 ** repository or global configuration databases only. */
3112 allowSymlinks = db_get_versioned_boolean("allow-symlinks", -1);
3113 }else{
3114 allowSymlinks = -1; /* Use non-versioned settings only. */
3115 }
3116 #endif
3117
3118 #if defined(_WIN32) || defined(__CYGWIN__)
3119 # define LOCALDB_NAME "./_FOSSIL_"
3120 #else
3121 # define LOCALDB_NAME "./.fslckout"
@@ -3082,10 +3125,11 @@
3125 "COMMIT; PRAGMA journal_mode=WAL; BEGIN;",
3126 #endif
3127 (char*)0);
3128 db_delete_on_failure(LOCALDB_NAME);
3129 db_open_local(0);
3130 #ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
3131 if( allowSymlinks>=0 ){
3132 /* Use the value from the versioned setting, which was read
3133 ** prior to opening the local checkout (i.e. which is most
3134 ** likely empty and does not actually contain any versioned
3135 ** setting files yet). Normally, this value would be given
@@ -3098,10 +3142,11 @@
3142 ** point, this will probably be the setting value from the
3143 ** repository or global configuration databases. */
3144 g.allowSymlinks = db_get_boolean("allow-symlinks",
3145 db_allow_symlinks_by_default());
3146 }
3147 #endif /* FOSSIL_LEGACY_ALLOW_SYMLINKS */
3148 db_lset("repository", g.argv[2]);
3149 db_record_repository_filename(g.argv[2]);
3150 db_set_checkout(0);
3151 azNewArgv[0] = g.argv[0];
3152 g.argv = azNewArgv;
@@ -3209,11 +3254,29 @@
3254 ** SETTING: admin-log boolean default=off
3255 **
3256 ** When the admin-log setting is enabled, configuration changes are recorded
3257 ** in the "admin_log" table of the repository.
3258 */
3259 #if !defined(FOSSIL_LEGACY_ALLOW_SYMLINKS)
3260 /*
3261 ** SETTING: allow-symlinks boolean default=off
3262 **
3263 ** When allow-symlinks is OFF (which is the default and recommended setting)
3264 ** symbolic links are treated like text files that contain a single line of
3265 ** content which is the name of their target. If allow-symlinks is ON,
3266 ** the symbolic links are actually followed.
3267 **
3268 ** The use of symbolic links is dangerous. If you checkout a maliciously
3269 ** crafted checkin that contains symbolic links, it is possible that files
3270 ** outside of the working directory might be overwritten.
3271 **
3272 ** Keep this setting OFF unless you have a very good reason to turn it
3273 ** on and you implicitly trust the integrity of the repositories you
3274 ** open.
3275 */
3276 #endif
3277 #if defined(_WIN32) && defined(FOSSIL_LEGACY_ALLOW_SYMLINKS)
3278 /*
3279 ** SETTING: allow-symlinks boolean default=off versionable
3280 **
3281 ** When allow-symlinks is OFF, symbolic links in the repository are followed
3282 ** and treated no differently from real files. When allow-symlinks is ON,
@@ -3220,11 +3283,11 @@
3283 ** the object to which the symbolic link points is ignored, and the content
3284 ** of the symbolic link that is stored in the repository is the name of the
3285 ** object to which the symbolic link points.
3286 */
3287 #endif
3288 #if !defined(_WIN32) && defined(FOSSIL_LEGACY_ALLOW_SYMLINKS)
3289 /*
3290 ** SETTING: allow-symlinks boolean default=on versionable
3291 **
3292 ** When allow-symlinks is OFF, symbolic links in the repository are followed
3293 ** and treated no differently from real files. When allow-symlinks is ON,
3294
+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 ){
@@ -2379,5 +2454,88 @@
23792454
changeCount);
23802455
}else{
23812456
fossil_print("Touched %d file(s)\n", changeCount);
23822457
}
23832458
}
2459
+
2460
+/*
2461
+** Returns non-zero if the specified file name ends with any reserved name,
2462
+** e.g.: _FOSSIL_ or .fslckout. Specifically, it returns 1 for exact match
2463
+** or 2 for a tail match on a longer file name.
2464
+**
2465
+** For the sake of efficiency, zFilename must be a canonical name, e.g. an
2466
+** absolute path using only forward slash ('/') as a directory separator.
2467
+**
2468
+** nFilename must be the length of zFilename. When negative, strlen() will
2469
+** be used to calculate it.
2470
+*/
2471
+int file_is_reserved_name(const char *zFilename, int nFilename){
2472
+ const char *zEnd; /* one-after-the-end of zFilename */
2473
+ int gotSuffix = 0; /* length of suffix (-wal, -shm, -journal) */
2474
+
2475
+ assert( zFilename && "API misuse" );
2476
+ if( nFilename<0 ) nFilename = (int)strlen(zFilename);
2477
+ if( nFilename<8 ) return 0; /* strlen("_FOSSIL_") */
2478
+ zEnd = zFilename + nFilename;
2479
+ if( nFilename>=12 ){ /* strlen("_FOSSIL_-(shm|wal)") */
2480
+ /* Check for (-wal, -shm, -journal) suffixes, with an eye towards
2481
+ ** runtime speed. */
2482
+ if( zEnd[-4]=='-' ){
2483
+ if( fossil_strnicmp("wal", &zEnd[-3], 3)
2484
+ && fossil_strnicmp("shm", &zEnd[-3], 3) ){
2485
+ return 0;
2486
+ }
2487
+ gotSuffix = 4;
2488
+ }else if( nFilename>=16 && zEnd[-8]=='-' ){ /*strlen(_FOSSIL_-journal) */
2489
+ if( fossil_strnicmp("journal", &zEnd[-7], 7) ) return 0;
2490
+ gotSuffix = 8;
2491
+ }
2492
+ if( gotSuffix ){
2493
+ assert( 4==gotSuffix || 8==gotSuffix );
2494
+ zEnd -= gotSuffix;
2495
+ nFilename -= gotSuffix;
2496
+ gotSuffix = 1;
2497
+ }
2498
+ assert( nFilename>=8 && "strlen(_FOSSIL_)" );
2499
+ assert( gotSuffix==0 || gotSuffix==1 );
2500
+ }
2501
+ switch( zEnd[-1] ){
2502
+ case '_':{
2503
+ if( fossil_strnicmp("_FOSSIL_", &zEnd[-8], 8) ) return 0;
2504
+ if( 8==nFilename ) return 1;
2505
+ return zEnd[-9]=='/' ? 2 : gotSuffix;
2506
+ }
2507
+ case 'T':
2508
+ case 't':{
2509
+ if( nFilename<9 || zEnd[-9]!='.'
2510
+ || fossil_strnicmp(".fslckout", &zEnd[-9], 9) ){
2511
+ return 0;
2512
+ }
2513
+ if( 9==nFilename ) return 1;
2514
+ return zEnd[-10]=='/' ? 2 : gotSuffix;
2515
+ }
2516
+ default:{
2517
+ return 0;
2518
+ }
2519
+ }
2520
+}
2521
+
2522
+/*
2523
+** COMMAND: test-is-reserved-name
2524
+**
2525
+** Usage: %fossil test-is-ckout-db FILENAMES...
2526
+**
2527
+** Passes each given name to file_is_reserved_name() and outputs one
2528
+** line per file: the result value of that function followed by the
2529
+** name.
2530
+*/
2531
+void test_is_reserved_name_cmd(void){
2532
+ int i;
2533
+
2534
+ if(g.argc<3){
2535
+ usage("FILENAME_1 [...FILENAME_N]");
2536
+ }
2537
+ for( i = 2; i < g.argc; ++i ){
2538
+ const int check = file_is_reserved_name(g.argv[i], -1);
2539
+ fossil_print("%d %s\n", check, g.argv[i]);
2540
+ }
2541
+}
23842542
--- 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 ){
@@ -2379,5 +2454,88 @@
2379 changeCount);
2380 }else{
2381 fossil_print("Touched %d file(s)\n", changeCount);
2382 }
2383 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2384
--- 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 ){
@@ -2379,5 +2454,88 @@
2454 changeCount);
2455 }else{
2456 fossil_print("Touched %d file(s)\n", changeCount);
2457 }
2458 }
2459
2460 /*
2461 ** Returns non-zero if the specified file name ends with any reserved name,
2462 ** e.g.: _FOSSIL_ or .fslckout. Specifically, it returns 1 for exact match
2463 ** or 2 for a tail match on a longer file name.
2464 **
2465 ** For the sake of efficiency, zFilename must be a canonical name, e.g. an
2466 ** absolute path using only forward slash ('/') as a directory separator.
2467 **
2468 ** nFilename must be the length of zFilename. When negative, strlen() will
2469 ** be used to calculate it.
2470 */
2471 int file_is_reserved_name(const char *zFilename, int nFilename){
2472 const char *zEnd; /* one-after-the-end of zFilename */
2473 int gotSuffix = 0; /* length of suffix (-wal, -shm, -journal) */
2474
2475 assert( zFilename && "API misuse" );
2476 if( nFilename<0 ) nFilename = (int)strlen(zFilename);
2477 if( nFilename<8 ) return 0; /* strlen("_FOSSIL_") */
2478 zEnd = zFilename + nFilename;
2479 if( nFilename>=12 ){ /* strlen("_FOSSIL_-(shm|wal)") */
2480 /* Check for (-wal, -shm, -journal) suffixes, with an eye towards
2481 ** runtime speed. */
2482 if( zEnd[-4]=='-' ){
2483 if( fossil_strnicmp("wal", &zEnd[-3], 3)
2484 && fossil_strnicmp("shm", &zEnd[-3], 3) ){
2485 return 0;
2486 }
2487 gotSuffix = 4;
2488 }else if( nFilename>=16 && zEnd[-8]=='-' ){ /*strlen(_FOSSIL_-journal) */
2489 if( fossil_strnicmp("journal", &zEnd[-7], 7) ) return 0;
2490 gotSuffix = 8;
2491 }
2492 if( gotSuffix ){
2493 assert( 4==gotSuffix || 8==gotSuffix );
2494 zEnd -= gotSuffix;
2495 nFilename -= gotSuffix;
2496 gotSuffix = 1;
2497 }
2498 assert( nFilename>=8 && "strlen(_FOSSIL_)" );
2499 assert( gotSuffix==0 || gotSuffix==1 );
2500 }
2501 switch( zEnd[-1] ){
2502 case '_':{
2503 if( fossil_strnicmp("_FOSSIL_", &zEnd[-8], 8) ) return 0;
2504 if( 8==nFilename ) return 1;
2505 return zEnd[-9]=='/' ? 2 : gotSuffix;
2506 }
2507 case 'T':
2508 case 't':{
2509 if( nFilename<9 || zEnd[-9]!='.'
2510 || fossil_strnicmp(".fslckout", &zEnd[-9], 9) ){
2511 return 0;
2512 }
2513 if( 9==nFilename ) return 1;
2514 return zEnd[-10]=='/' ? 2 : gotSuffix;
2515 }
2516 default:{
2517 return 0;
2518 }
2519 }
2520 }
2521
2522 /*
2523 ** COMMAND: test-is-reserved-name
2524 **
2525 ** Usage: %fossil test-is-ckout-db FILENAMES...
2526 **
2527 ** Passes each given name to file_is_reserved_name() and outputs one
2528 ** line per file: the result value of that function followed by the
2529 ** name.
2530 */
2531 void test_is_reserved_name_cmd(void){
2532 int i;
2533
2534 if(g.argc<3){
2535 usage("FILENAME_1 [...FILENAME_N]");
2536 }
2537 for( i = 2; i < g.argc; ++i ){
2538 const int check = file_is_reserved_name(g.argv[i], -1);
2539 fossil_print("%d %s\n", check, g.argv[i]);
2540 }
2541 }
2542
+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 ){
@@ -2379,5 +2454,88 @@
23792454
changeCount);
23802455
}else{
23812456
fossil_print("Touched %d file(s)\n", changeCount);
23822457
}
23832458
}
2459
+
2460
+/*
2461
+** Returns non-zero if the specified file name ends with any reserved name,
2462
+** e.g.: _FOSSIL_ or .fslckout. Specifically, it returns 1 for exact match
2463
+** or 2 for a tail match on a longer file name.
2464
+**
2465
+** For the sake of efficiency, zFilename must be a canonical name, e.g. an
2466
+** absolute path using only forward slash ('/') as a directory separator.
2467
+**
2468
+** nFilename must be the length of zFilename. When negative, strlen() will
2469
+** be used to calculate it.
2470
+*/
2471
+int file_is_reserved_name(const char *zFilename, int nFilename){
2472
+ const char *zEnd; /* one-after-the-end of zFilename */
2473
+ int gotSuffix = 0; /* length of suffix (-wal, -shm, -journal) */
2474
+
2475
+ assert( zFilename && "API misuse" );
2476
+ if( nFilename<0 ) nFilename = (int)strlen(zFilename);
2477
+ if( nFilename<8 ) return 0; /* strlen("_FOSSIL_") */
2478
+ zEnd = zFilename + nFilename;
2479
+ if( nFilename>=12 ){ /* strlen("_FOSSIL_-(shm|wal)") */
2480
+ /* Check for (-wal, -shm, -journal) suffixes, with an eye towards
2481
+ ** runtime speed. */
2482
+ if( zEnd[-4]=='-' ){
2483
+ if( fossil_strnicmp("wal", &zEnd[-3], 3)
2484
+ && fossil_strnicmp("shm", &zEnd[-3], 3) ){
2485
+ return 0;
2486
+ }
2487
+ gotSuffix = 4;
2488
+ }else if( nFilename>=16 && zEnd[-8]=='-' ){ /*strlen(_FOSSIL_-journal) */
2489
+ if( fossil_strnicmp("journal", &zEnd[-7], 7) ) return 0;
2490
+ gotSuffix = 8;
2491
+ }
2492
+ if( gotSuffix ){
2493
+ assert( 4==gotSuffix || 8==gotSuffix );
2494
+ zEnd -= gotSuffix;
2495
+ nFilename -= gotSuffix;
2496
+ gotSuffix = 1;
2497
+ }
2498
+ assert( nFilename>=8 && "strlen(_FOSSIL_)" );
2499
+ assert( gotSuffix==0 || gotSuffix==1 );
2500
+ }
2501
+ switch( zEnd[-1] ){
2502
+ case '_':{
2503
+ if( fossil_strnicmp("_FOSSIL_", &zEnd[-8], 8) ) return 0;
2504
+ if( 8==nFilename ) return 1;
2505
+ return zEnd[-9]=='/' ? 2 : gotSuffix;
2506
+ }
2507
+ case 'T':
2508
+ case 't':{
2509
+ if( nFilename<9 || zEnd[-9]!='.'
2510
+ || fossil_strnicmp(".fslckout", &zEnd[-9], 9) ){
2511
+ return 0;
2512
+ }
2513
+ if( 9==nFilename ) return 1;
2514
+ return zEnd[-10]=='/' ? 2 : gotSuffix;
2515
+ }
2516
+ default:{
2517
+ return 0;
2518
+ }
2519
+ }
2520
+}
2521
+
2522
+/*
2523
+** COMMAND: test-is-reserved-name
2524
+**
2525
+** Usage: %fossil test-is-ckout-db FILENAMES...
2526
+**
2527
+** Passes each given name to file_is_reserved_name() and outputs one
2528
+** line per file: the result value of that function followed by the
2529
+** name.
2530
+*/
2531
+void test_is_reserved_name_cmd(void){
2532
+ int i;
2533
+
2534
+ if(g.argc<3){
2535
+ usage("FILENAME_1 [...FILENAME_N]");
2536
+ }
2537
+ for( i = 2; i < g.argc; ++i ){
2538
+ const int check = file_is_reserved_name(g.argv[i], -1);
2539
+ fossil_print("%d %s\n", check, g.argv[i]);
2540
+ }
2541
+}
23842542
--- 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 ){
@@ -2379,5 +2454,88 @@
2379 changeCount);
2380 }else{
2381 fossil_print("Touched %d file(s)\n", changeCount);
2382 }
2383 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2384
--- 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 ){
@@ -2379,5 +2454,88 @@
2454 changeCount);
2455 }else{
2456 fossil_print("Touched %d file(s)\n", changeCount);
2457 }
2458 }
2459
2460 /*
2461 ** Returns non-zero if the specified file name ends with any reserved name,
2462 ** e.g.: _FOSSIL_ or .fslckout. Specifically, it returns 1 for exact match
2463 ** or 2 for a tail match on a longer file name.
2464 **
2465 ** For the sake of efficiency, zFilename must be a canonical name, e.g. an
2466 ** absolute path using only forward slash ('/') as a directory separator.
2467 **
2468 ** nFilename must be the length of zFilename. When negative, strlen() will
2469 ** be used to calculate it.
2470 */
2471 int file_is_reserved_name(const char *zFilename, int nFilename){
2472 const char *zEnd; /* one-after-the-end of zFilename */
2473 int gotSuffix = 0; /* length of suffix (-wal, -shm, -journal) */
2474
2475 assert( zFilename && "API misuse" );
2476 if( nFilename<0 ) nFilename = (int)strlen(zFilename);
2477 if( nFilename<8 ) return 0; /* strlen("_FOSSIL_") */
2478 zEnd = zFilename + nFilename;
2479 if( nFilename>=12 ){ /* strlen("_FOSSIL_-(shm|wal)") */
2480 /* Check for (-wal, -shm, -journal) suffixes, with an eye towards
2481 ** runtime speed. */
2482 if( zEnd[-4]=='-' ){
2483 if( fossil_strnicmp("wal", &zEnd[-3], 3)
2484 && fossil_strnicmp("shm", &zEnd[-3], 3) ){
2485 return 0;
2486 }
2487 gotSuffix = 4;
2488 }else if( nFilename>=16 && zEnd[-8]=='-' ){ /*strlen(_FOSSIL_-journal) */
2489 if( fossil_strnicmp("journal", &zEnd[-7], 7) ) return 0;
2490 gotSuffix = 8;
2491 }
2492 if( gotSuffix ){
2493 assert( 4==gotSuffix || 8==gotSuffix );
2494 zEnd -= gotSuffix;
2495 nFilename -= gotSuffix;
2496 gotSuffix = 1;
2497 }
2498 assert( nFilename>=8 && "strlen(_FOSSIL_)" );
2499 assert( gotSuffix==0 || gotSuffix==1 );
2500 }
2501 switch( zEnd[-1] ){
2502 case '_':{
2503 if( fossil_strnicmp("_FOSSIL_", &zEnd[-8], 8) ) return 0;
2504 if( 8==nFilename ) return 1;
2505 return zEnd[-9]=='/' ? 2 : gotSuffix;
2506 }
2507 case 'T':
2508 case 't':{
2509 if( nFilename<9 || zEnd[-9]!='.'
2510 || fossil_strnicmp(".fslckout", &zEnd[-9], 9) ){
2511 return 0;
2512 }
2513 if( 9==nFilename ) return 1;
2514 return zEnd[-10]=='/' ? 2 : gotSuffix;
2515 }
2516 default:{
2517 return 0;
2518 }
2519 }
2520 }
2521
2522 /*
2523 ** COMMAND: test-is-reserved-name
2524 **
2525 ** Usage: %fossil test-is-ckout-db FILENAMES...
2526 **
2527 ** Passes each given name to file_is_reserved_name() and outputs one
2528 ** line per file: the result value of that function followed by the
2529 ** name.
2530 */
2531 void test_is_reserved_name_cmd(void){
2532 int i;
2533
2534 if(g.argc<3){
2535 usage("FILENAME_1 [...FILENAME_N]");
2536 }
2537 for( i = 2; i < g.argc; ++i ){
2538 const int check = file_is_reserved_name(g.argv[i], -1);
2539 fossil_print("%d %s\n", check, g.argv[i]);
2540 }
2541 }
2542
+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
@@ -81,11 +81,13 @@
8181
{ "keep-glob", CONFIGSET_PROJ },
8282
{ "crlf-glob", CONFIGSET_PROJ },
8383
{ "crnl-glob", CONFIGSET_PROJ },
8484
{ "encoding-glob", CONFIGSET_PROJ },
8585
{ "empty-dirs", CONFIGSET_PROJ },
86
+#ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
8687
{ "allow-symlinks", CONFIGSET_PROJ },
88
+#endif
8789
{ "dotfiles", CONFIGSET_PROJ },
8890
8991
{ "ticket-table", CONFIGSET_TKT },
9092
{ "ticket-common", CONFIGSET_TKT },
9193
{ "ticket-change", CONFIGSET_TKT },
9294
--- src/json_config.c
+++ src/json_config.c
@@ -81,11 +81,13 @@
81 { "keep-glob", CONFIGSET_PROJ },
82 { "crlf-glob", CONFIGSET_PROJ },
83 { "crnl-glob", CONFIGSET_PROJ },
84 { "encoding-glob", CONFIGSET_PROJ },
85 { "empty-dirs", CONFIGSET_PROJ },
 
86 { "allow-symlinks", CONFIGSET_PROJ },
 
87 { "dotfiles", CONFIGSET_PROJ },
88
89 { "ticket-table", CONFIGSET_TKT },
90 { "ticket-common", CONFIGSET_TKT },
91 { "ticket-change", CONFIGSET_TKT },
92
--- src/json_config.c
+++ src/json_config.c
@@ -81,11 +81,13 @@
81 { "keep-glob", CONFIGSET_PROJ },
82 { "crlf-glob", CONFIGSET_PROJ },
83 { "crnl-glob", CONFIGSET_PROJ },
84 { "encoding-glob", CONFIGSET_PROJ },
85 { "empty-dirs", CONFIGSET_PROJ },
86 #ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
87 { "allow-symlinks", CONFIGSET_PROJ },
88 #endif
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
@@ -81,11 +81,13 @@
8181
{ "keep-glob", CONFIGSET_PROJ },
8282
{ "crlf-glob", CONFIGSET_PROJ },
8383
{ "crnl-glob", CONFIGSET_PROJ },
8484
{ "encoding-glob", CONFIGSET_PROJ },
8585
{ "empty-dirs", CONFIGSET_PROJ },
86
+#ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
8687
{ "allow-symlinks", CONFIGSET_PROJ },
88
+#endif
8789
{ "dotfiles", CONFIGSET_PROJ },
8890
8991
{ "ticket-table", CONFIGSET_TKT },
9092
{ "ticket-common", CONFIGSET_TKT },
9193
{ "ticket-change", CONFIGSET_TKT },
9294
--- src/json_config.c
+++ src/json_config.c
@@ -81,11 +81,13 @@
81 { "keep-glob", CONFIGSET_PROJ },
82 { "crlf-glob", CONFIGSET_PROJ },
83 { "crnl-glob", CONFIGSET_PROJ },
84 { "encoding-glob", CONFIGSET_PROJ },
85 { "empty-dirs", CONFIGSET_PROJ },
 
86 { "allow-symlinks", CONFIGSET_PROJ },
 
87 { "dotfiles", CONFIGSET_PROJ },
88
89 { "ticket-table", CONFIGSET_TKT },
90 { "ticket-common", CONFIGSET_TKT },
91 { "ticket-change", CONFIGSET_TKT },
92
--- src/json_config.c
+++ src/json_config.c
@@ -81,11 +81,13 @@
81 { "keep-glob", CONFIGSET_PROJ },
82 { "crlf-glob", CONFIGSET_PROJ },
83 { "crnl-glob", CONFIGSET_PROJ },
84 { "encoding-glob", CONFIGSET_PROJ },
85 { "empty-dirs", CONFIGSET_PROJ },
86 #ifdef FOSSIL_LEGACY_ALLOW_SYMLINKS
87 { "allow-symlinks", CONFIGSET_PROJ },
88 #endif
89 { "dotfiles", CONFIGSET_PROJ },
90
91 { "ticket-table", CONFIGSET_TKT },
92 { "ticket-common", CONFIGSET_TKT },
93 { "ticket-change", CONFIGSET_TKT },
94
+3
--- src/main.c
+++ src/main.c
@@ -1198,10 +1198,13 @@
11981198
#if defined(FOSSIL_DYNAMIC_BUILD)
11991199
blob_append(pOut, "FOSSIL_DYNAMIC_BUILD\n", -1);
12001200
#else
12011201
blob_append(pOut, "FOSSIL_STATIC_BUILD\n", -1);
12021202
#endif
1203
+#if defined(FOSSIL_LEGACY_ALLOW_SYMLINKS)
1204
+ blob_append(pOut, "FOSSIL_LEGACY_ALLOW_SYMLINKS\n", -1);
1205
+#endif
12031206
#if defined(HAVE_PLEDGE)
12041207
blob_append(pOut, "HAVE_PLEDGE\n", -1);
12051208
#endif
12061209
#if defined(USE_MMAN_H)
12071210
blob_append(pOut, "USE_MMAN_H\n", -1);
12081211
--- src/main.c
+++ src/main.c
@@ -1198,10 +1198,13 @@
1198 #if defined(FOSSIL_DYNAMIC_BUILD)
1199 blob_append(pOut, "FOSSIL_DYNAMIC_BUILD\n", -1);
1200 #else
1201 blob_append(pOut, "FOSSIL_STATIC_BUILD\n", -1);
1202 #endif
 
 
 
1203 #if defined(HAVE_PLEDGE)
1204 blob_append(pOut, "HAVE_PLEDGE\n", -1);
1205 #endif
1206 #if defined(USE_MMAN_H)
1207 blob_append(pOut, "USE_MMAN_H\n", -1);
1208
--- src/main.c
+++ src/main.c
@@ -1198,10 +1198,13 @@
1198 #if defined(FOSSIL_DYNAMIC_BUILD)
1199 blob_append(pOut, "FOSSIL_DYNAMIC_BUILD\n", -1);
1200 #else
1201 blob_append(pOut, "FOSSIL_STATIC_BUILD\n", -1);
1202 #endif
1203 #if defined(FOSSIL_LEGACY_ALLOW_SYMLINKS)
1204 blob_append(pOut, "FOSSIL_LEGACY_ALLOW_SYMLINKS\n", -1);
1205 #endif
1206 #if defined(HAVE_PLEDGE)
1207 blob_append(pOut, "HAVE_PLEDGE\n", -1);
1208 #endif
1209 #if defined(USE_MMAN_H)
1210 blob_append(pOut, "USE_MMAN_H\n", -1);
1211
+3
--- src/main.c
+++ src/main.c
@@ -1198,10 +1198,13 @@
11981198
#if defined(FOSSIL_DYNAMIC_BUILD)
11991199
blob_append(pOut, "FOSSIL_DYNAMIC_BUILD\n", -1);
12001200
#else
12011201
blob_append(pOut, "FOSSIL_STATIC_BUILD\n", -1);
12021202
#endif
1203
+#if defined(FOSSIL_LEGACY_ALLOW_SYMLINKS)
1204
+ blob_append(pOut, "FOSSIL_LEGACY_ALLOW_SYMLINKS\n", -1);
1205
+#endif
12031206
#if defined(HAVE_PLEDGE)
12041207
blob_append(pOut, "HAVE_PLEDGE\n", -1);
12051208
#endif
12061209
#if defined(USE_MMAN_H)
12071210
blob_append(pOut, "USE_MMAN_H\n", -1);
12081211
--- src/main.c
+++ src/main.c
@@ -1198,10 +1198,13 @@
1198 #if defined(FOSSIL_DYNAMIC_BUILD)
1199 blob_append(pOut, "FOSSIL_DYNAMIC_BUILD\n", -1);
1200 #else
1201 blob_append(pOut, "FOSSIL_STATIC_BUILD\n", -1);
1202 #endif
 
 
 
1203 #if defined(HAVE_PLEDGE)
1204 blob_append(pOut, "HAVE_PLEDGE\n", -1);
1205 #endif
1206 #if defined(USE_MMAN_H)
1207 blob_append(pOut, "USE_MMAN_H\n", -1);
1208
--- src/main.c
+++ src/main.c
@@ -1198,10 +1198,13 @@
1198 #if defined(FOSSIL_DYNAMIC_BUILD)
1199 blob_append(pOut, "FOSSIL_DYNAMIC_BUILD\n", -1);
1200 #else
1201 blob_append(pOut, "FOSSIL_STATIC_BUILD\n", -1);
1202 #endif
1203 #if defined(FOSSIL_LEGACY_ALLOW_SYMLINKS)
1204 blob_append(pOut, "FOSSIL_LEGACY_ALLOW_SYMLINKS\n", -1);
1205 #endif
1206 #if defined(HAVE_PLEDGE)
1207 blob_append(pOut, "HAVE_PLEDGE\n", -1);
1208 #endif
1209 #if defined(USE_MMAN_H)
1210 blob_append(pOut, "USE_MMAN_H\n", -1);
1211
+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
+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
@@ -229,15 +229,15 @@
229229
230230
/*
231231
** Activate the query authorizer
232232
*/
233233
void report_restrict_sql(char **pzErr){
234
- sqlite3_set_authorizer(g.db, report_query_authorizer, (void*)pzErr);
234
+ db_set_authorizer(report_query_authorizer,(void*)pzErr,"Ticket-Report");
235235
sqlite3_limit(g.db, SQLITE_LIMIT_VDBE_OP, 10000);
236236
}
237237
void report_unrestrict_sql(void){
238
- sqlite3_set_authorizer(g.db, 0, 0);
238
+ db_clear_authorizer();
239239
}
240240
241241
242242
/*
243243
** Check the given SQL to see if is a valid query that does not
@@ -679,11 +679,11 @@
679679
*/
680680
if( pState->nCount==0 ){
681681
/* Turn off the authorizer. It is no longer doing anything since the
682682
** query has already been prepared.
683683
*/
684
- sqlite3_set_authorizer(g.db, 0, 0);
684
+ db_clear_authorizer();
685685
686686
/* Figure out the number of columns, the column that determines background
687687
** color, and whether or not this row of data is represented by multiple
688688
** rows in the table.
689689
*/
690690
--- src/report.c
+++ src/report.c
@@ -229,15 +229,15 @@
229
230 /*
231 ** Activate the query authorizer
232 */
233 void report_restrict_sql(char **pzErr){
234 sqlite3_set_authorizer(g.db, report_query_authorizer, (void*)pzErr);
235 sqlite3_limit(g.db, SQLITE_LIMIT_VDBE_OP, 10000);
236 }
237 void report_unrestrict_sql(void){
238 sqlite3_set_authorizer(g.db, 0, 0);
239 }
240
241
242 /*
243 ** Check the given SQL to see if is a valid query that does not
@@ -679,11 +679,11 @@
679 */
680 if( pState->nCount==0 ){
681 /* Turn off the authorizer. It is no longer doing anything since the
682 ** query has already been prepared.
683 */
684 sqlite3_set_authorizer(g.db, 0, 0);
685
686 /* Figure out the number of columns, the column that determines background
687 ** color, and whether or not this row of data is represented by multiple
688 ** rows in the table.
689 */
690
--- src/report.c
+++ src/report.c
@@ -229,15 +229,15 @@
229
230 /*
231 ** Activate the query authorizer
232 */
233 void report_restrict_sql(char **pzErr){
234 db_set_authorizer(report_query_authorizer,(void*)pzErr,"Ticket-Report");
235 sqlite3_limit(g.db, SQLITE_LIMIT_VDBE_OP, 10000);
236 }
237 void report_unrestrict_sql(void){
238 db_clear_authorizer();
239 }
240
241
242 /*
243 ** Check the given SQL to see if is a valid query that does not
@@ -679,11 +679,11 @@
679 */
680 if( pState->nCount==0 ){
681 /* Turn off the authorizer. It is no longer doing anything since the
682 ** query has already been prepared.
683 */
684 db_clear_authorizer();
685
686 /* Figure out the number of columns, the column that determines background
687 ** color, and whether or not this row of data is represented by multiple
688 ** rows in the table.
689 */
690
+3 -3
--- src/report.c
+++ src/report.c
@@ -229,15 +229,15 @@
229229
230230
/*
231231
** Activate the query authorizer
232232
*/
233233
void report_restrict_sql(char **pzErr){
234
- sqlite3_set_authorizer(g.db, report_query_authorizer, (void*)pzErr);
234
+ db_set_authorizer(report_query_authorizer,(void*)pzErr,"Ticket-Report");
235235
sqlite3_limit(g.db, SQLITE_LIMIT_VDBE_OP, 10000);
236236
}
237237
void report_unrestrict_sql(void){
238
- sqlite3_set_authorizer(g.db, 0, 0);
238
+ db_clear_authorizer();
239239
}
240240
241241
242242
/*
243243
** Check the given SQL to see if is a valid query that does not
@@ -679,11 +679,11 @@
679679
*/
680680
if( pState->nCount==0 ){
681681
/* Turn off the authorizer. It is no longer doing anything since the
682682
** query has already been prepared.
683683
*/
684
- sqlite3_set_authorizer(g.db, 0, 0);
684
+ db_clear_authorizer();
685685
686686
/* Figure out the number of columns, the column that determines background
687687
** color, and whether or not this row of data is represented by multiple
688688
** rows in the table.
689689
*/
690690
--- src/report.c
+++ src/report.c
@@ -229,15 +229,15 @@
229
230 /*
231 ** Activate the query authorizer
232 */
233 void report_restrict_sql(char **pzErr){
234 sqlite3_set_authorizer(g.db, report_query_authorizer, (void*)pzErr);
235 sqlite3_limit(g.db, SQLITE_LIMIT_VDBE_OP, 10000);
236 }
237 void report_unrestrict_sql(void){
238 sqlite3_set_authorizer(g.db, 0, 0);
239 }
240
241
242 /*
243 ** Check the given SQL to see if is a valid query that does not
@@ -679,11 +679,11 @@
679 */
680 if( pState->nCount==0 ){
681 /* Turn off the authorizer. It is no longer doing anything since the
682 ** query has already been prepared.
683 */
684 sqlite3_set_authorizer(g.db, 0, 0);
685
686 /* Figure out the number of columns, the column that determines background
687 ** color, and whether or not this row of data is represented by multiple
688 ** rows in the table.
689 */
690
--- src/report.c
+++ src/report.c
@@ -229,15 +229,15 @@
229
230 /*
231 ** Activate the query authorizer
232 */
233 void report_restrict_sql(char **pzErr){
234 db_set_authorizer(report_query_authorizer,(void*)pzErr,"Ticket-Report");
235 sqlite3_limit(g.db, SQLITE_LIMIT_VDBE_OP, 10000);
236 }
237 void report_unrestrict_sql(void){
238 db_clear_authorizer();
239 }
240
241
242 /*
243 ** Check the given SQL to see if is a valid query that does not
@@ -679,11 +679,11 @@
679 */
680 if( pState->nCount==0 ){
681 /* Turn off the authorizer. It is no longer doing anything since the
682 ** query has already been prepared.
683 */
684 db_clear_authorizer();
685
686 /* Figure out the number of columns, the column that determines background
687 ** color, and whether or not this row of data is represented by multiple
688 ** rows in the table.
689 */
690
--- 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
--- 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
+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
+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
@@ -876,10 +876,12 @@
876876
" SET pathname=origname, origname=NULL"
877877
" WHERE pathname=%Q AND origname!=pathname;"
878878
"DELETE FROM vfile WHERE pathname=%Q",
879879
zFile, zFile
880880
);
881
+ }else if( file_unsafe_in_tree_path(zFull) ){
882
+ /* Ignore this file */
881883
}else{
882884
sqlite3_int64 mtime;
883885
int rvChnged = 0;
884886
int rvPerm = manifest_file_mperm(pRvFile);
885887
886888
--- src/update.c
+++ src/update.c
@@ -876,10 +876,12 @@
876 " SET pathname=origname, origname=NULL"
877 " WHERE pathname=%Q AND origname!=pathname;"
878 "DELETE FROM vfile WHERE pathname=%Q",
879 zFile, zFile
880 );
 
 
881 }else{
882 sqlite3_int64 mtime;
883 int rvChnged = 0;
884 int rvPerm = manifest_file_mperm(pRvFile);
885
886
--- src/update.c
+++ src/update.c
@@ -876,10 +876,12 @@
876 " SET pathname=origname, origname=NULL"
877 " WHERE pathname=%Q AND origname!=pathname;"
878 "DELETE FROM vfile WHERE pathname=%Q",
879 zFile, zFile
880 );
881 }else if( file_unsafe_in_tree_path(zFull) ){
882 /* Ignore this file */
883 }else{
884 sqlite3_int64 mtime;
885 int rvChnged = 0;
886 int rvPerm = manifest_file_mperm(pRvFile);
887
888
--- src/update.c
+++ src/update.c
@@ -876,10 +876,12 @@
876876
" SET pathname=origname, origname=NULL"
877877
" WHERE pathname=%Q AND origname!=pathname;"
878878
"DELETE FROM vfile WHERE pathname=%Q",
879879
zFile, zFile
880880
);
881
+ }else if( file_unsafe_in_tree_path(zFull) ){
882
+ /* Ignore this file */
881883
}else{
882884
sqlite3_int64 mtime;
883885
int rvChnged = 0;
884886
int rvPerm = manifest_file_mperm(pRvFile);
885887
886888
--- src/update.c
+++ src/update.c
@@ -876,10 +876,12 @@
876 " SET pathname=origname, origname=NULL"
877 " WHERE pathname=%Q AND origname!=pathname;"
878 "DELETE FROM vfile WHERE pathname=%Q",
879 zFile, zFile
880 );
 
 
881 }else{
882 sqlite3_int64 mtime;
883 int rvChnged = 0;
884 int rvPerm = manifest_file_mperm(pRvFile);
885
886
--- src/update.c
+++ src/update.c
@@ -876,10 +876,12 @@
876 " SET pathname=origname, origname=NULL"
877 " WHERE pathname=%Q AND origname!=pathname;"
878 "DELETE FROM vfile WHERE pathname=%Q",
879 zFile, zFile
880 );
881 }else if( file_unsafe_in_tree_path(zFull) ){
882 /* Ignore this file */
883 }else{
884 sqlite3_int64 mtime;
885 int rvChnged = 0;
886 int rvPerm = manifest_file_mperm(pRvFile);
887
888
--- 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