Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Merge additional symlink fixes. Back out comment-only changes from url.c. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | sec2020-2.12-patch |
| Files: | files | file ages | folders |
| SHA3-256: |
0ea17c2b11b5bc63f69aabc3a183419d |
| User & Date: | drh 2020-08-19 12:58:31.519 |
Context
|
2020-08-19
| ||
| 21:08 | The allow-symlinks setting is disabled by default and is not versionable, unless Fossil is compiled with the FOSSIL_LEGACY_ALLOW_SYMLINKS flag, in which case it follows the historic behavior. check-in: cdc90f0c3b user: drh tags: sec2020-2.12-patch | |
| 12:58 | Merge additional symlink fixes. Back out comment-only changes from url.c. check-in: 0ea17c2b11 user: drh tags: sec2020-2.12-patch | |
| 12:26 | Fix harmless compiler warnings. check-in: feef827504 user: drh tags: sec2020 | |
| 12:22 | Additional defenses against doing "fossil add" of files that are beneath symlinks. check-in: 928b023cb7 user: drh tags: sec2020 | |
| 12:08 | Improved detection of attempts to write through a symlink. Now also works for "revert", "stash", and "undo/redo". check-in: f63297b2c5 user: drh tags: sec2020 | |
| 01:07 | Cherrypick key fixes from the sec2020 branch in order to devise a minimal patch to get us to version 2.12.1. check-in: fe1264d35d user: drh tags: sec2020-2.12-patch | |
Changes
Changes to src/add.c.
| ︙ | ︙ | |||
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
**
** Omit any file whose name is pOmit.
*/
static int add_one_file(
const char *zPath, /* Tree-name of file to add. */
int vid /* Add to this VFILE */
){
if( !file_is_simple_pathname(zPath, 1) ){
fossil_warning("filename contains illegal characters: %s", zPath);
return 0;
}
if( db_exists("SELECT 1 FROM vfile"
" WHERE pathname=%Q %s", zPath, filename_collation()) ){
db_multi_exec("UPDATE vfile SET deleted=0"
" WHERE pathname=%Q %s AND deleted",
zPath, filename_collation());
}else{
char *zFullname = mprintf("%s%s", g.zLocalRoot, zPath);
int isExe = file_isexe(zFullname, RepoFILE);
| > > > > > | | | | > | | 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
**
** Omit any file whose name is pOmit.
*/
static int add_one_file(
const char *zPath, /* Tree-name of file to add. */
int vid /* Add to this VFILE */
){
int doSkip = 0;
if( !file_is_simple_pathname(zPath, 1) ){
fossil_warning("filename contains illegal characters: %s", zPath);
return 0;
}
if( db_exists("SELECT 1 FROM vfile"
" WHERE pathname=%Q %s", zPath, filename_collation()) ){
db_multi_exec("UPDATE vfile SET deleted=0"
" WHERE pathname=%Q %s AND deleted",
zPath, filename_collation());
}else{
char *zFullname = mprintf("%s%s", g.zLocalRoot, zPath);
int isExe = file_isexe(zFullname, RepoFILE);
if( file_nondir_objects_on_path(g.zLocalRoot, zFullname) ){
/* Do not add unsafe files to the vfile */
doSkip = 1;
}else{
db_multi_exec(
"INSERT INTO vfile(vid,deleted,rid,mrid,pathname,isexe,islink,mhash)"
"VALUES(%d,0,0,0,%Q,%d,%d,NULL)",
vid, zPath, isExe, file_islink(0));
}
fossil_free(zFullname);
}
if( db_changes() && !doSkip ){
fossil_print("ADDED %s\n", zPath);
return 1;
}else{
fossil_print("SKIP %s\n", zPath);
return 0;
}
}
|
| ︙ | ︙ |
Changes to src/file.c.
| ︙ | ︙ | |||
368 369 370 371 372 373 374 375 376 377 378 379 380 381 |
}
z[j] = '/';
i = j;
}
fossil_free(z);
return 0;
}
/*
** Return 1 if zFilename is a directory. Return 0 if zFilename
** does not exist. Return 2 if zFilename exists but is something
** other than a directory.
*/
int file_isdir(const char *zFilename, int eFType){
| > > > > > > > > > > > > > > > > > > > > > > > > > | 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 |
}
z[j] = '/';
i = j;
}
fossil_free(z);
return 0;
}
/*
** The file named zFile is suppose to be an in-tree file. Check to
** ensure that it will be safe to write to this file by verifying that
** there are no symlinks or other non-directory objects in between the
** root of the checkout and zFile.
**
** If a problem is found, print a warning message (using fossil_warning())
** and return non-zero. If everything is ok, return zero.
*/
int file_unsafe_in_tree_path(const char *zFile){
int n;
if( !file_is_absolute_path(zFile) ){
fossil_panic("%s is not an absolute pathname",zFile);
}
if( fossil_strnicmp(g.zLocalRoot, zFile, (int)strlen(g.zLocalRoot)) ){
fossil_panic("%s is not a prefix of %s", g.zLocalRoot, zFile);
}
n = file_nondir_objects_on_path(g.zLocalRoot, zFile);
if( n ){
fossil_warning("cannot write to %s because non-directory object %.*s"
" is in the way", zFile, n, zFile);
}
return n;
}
/*
** Return 1 if zFilename is a directory. Return 0 if zFilename
** does not exist. Return 2 if zFilename exists but is something
** other than a directory.
*/
int file_isdir(const char *zFilename, int eFType){
|
| ︙ | ︙ |
Changes to src/stash.c.
| ︙ | ︙ | |||
332 333 334 335 336 337 338 339 340 341 342 343 344 345 |
db_multi_exec("INSERT OR IGNORE INTO sfile(pathname) VALUES(%Q)", zNew);
db_ephemeral_blob(&q, 6, &delta);
blob_write_to_file(&delta, zNPath);
file_setexe(zNPath, isExec);
}else if( isRemoved ){
fossil_print("DELETE %s\n", zOrig);
file_delete(zOPath);
}else{
Blob a, b, out, disk;
int isNewLink = file_islink(zOPath);
db_ephemeral_blob(&q, 6, &delta);
blob_read_from_file(&disk, zOPath, RepoFILE);
content_get(rid, &a);
blob_delta_apply(&a, &delta, &b);
| > > | 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 |
db_multi_exec("INSERT OR IGNORE INTO sfile(pathname) VALUES(%Q)", zNew);
db_ephemeral_blob(&q, 6, &delta);
blob_write_to_file(&delta, zNPath);
file_setexe(zNPath, isExec);
}else if( isRemoved ){
fossil_print("DELETE %s\n", zOrig);
file_delete(zOPath);
}else if( file_unsafe_in_tree_path(zNPath) ){
/* Ignore the unsafe path */
}else{
Blob a, b, out, disk;
int isNewLink = file_islink(zOPath);
db_ephemeral_blob(&q, 6, &delta);
blob_read_from_file(&disk, zOPath, RepoFILE);
content_get(rid, &a);
blob_delta_apply(&a, &delta, &b);
|
| ︙ | ︙ |
Changes to src/undo.c.
| ︙ | ︙ | |||
50 51 52 53 54 55 56 |
int new_exists;
int old_exe;
int new_exe;
int new_link;
int old_link;
Blob current;
Blob new;
| | > > | | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
int new_exists;
int old_exe;
int new_exe;
int new_link;
int old_link;
Blob current;
Blob new;
zFullname = mprintf("%s%s", g.zLocalRoot, zPathname);
old_link = db_column_int(&q, 3);
new_exists = file_size(zFullname, RepoFILE)>=0;
new_link = file_islink(0);
if( new_exists ){
blob_read_from_file(¤t, zFullname, RepoFILE);
new_exe = file_isexe(0,0);
}else{
blob_zero(¤t);
new_exe = 0;
}
blob_zero(&new);
old_exists = db_column_int(&q, 1);
old_exe = db_column_int(&q, 2);
if( old_exists ){
db_ephemeral_blob(&q, 0, &new);
}
if( file_unsafe_in_tree_path(zFullname) ){
/* do nothign with this unsafe file */
}else if( old_exists ){
if( new_exists ){
fossil_print("%s %s\n", redoFlag ? "REDO" : "UNDO", zPathname);
}else{
fossil_print("NEW %s\n", zPathname);
}
if( new_exists && (new_link || old_link) ){
file_delete(zFullname);
|
| ︙ | ︙ |
Changes to src/update.c.
| ︙ | ︙ | |||
925 926 927 928 929 930 931 932 933 934 935 936 937 938 |
db_multi_exec(
"UPDATE OR REPLACE vfile"
" SET pathname=origname, origname=NULL"
" WHERE pathname=%Q AND origname!=pathname;"
"DELETE FROM vfile WHERE pathname=%Q",
zFile, zFile
);
}else{
sqlite3_int64 mtime;
int rvChnged = 0;
int rvPerm = manifest_file_mperm(pRvFile);
/* Determine if reverted-to file is different than checked out file. */
if( pCoManifest && (pCoFile = manifest_file_find(pCoManifest, zFile)) ){
| > > | 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 |
db_multi_exec(
"UPDATE OR REPLACE vfile"
" SET pathname=origname, origname=NULL"
" WHERE pathname=%Q AND origname!=pathname;"
"DELETE FROM vfile WHERE pathname=%Q",
zFile, zFile
);
}else if( file_unsafe_in_tree_path(zFull) ){
/* Ignore this file */
}else{
sqlite3_int64 mtime;
int rvChnged = 0;
int rvPerm = manifest_file_mperm(pRvFile);
/* Determine if reverted-to file is different than checked out file. */
if( pCoManifest && (pCoFile = manifest_file_find(pCoManifest, zFile)) ){
|
| ︙ | ︙ |
Changes to src/url.c.
| ︙ | ︙ | |||
48 49 50 51 52 53 54 |
struct UrlData {
int isFile; /* True if a "file:" url */
int isHttps; /* True if a "https:" url */
int isSsh; /* True if an "ssh:" url */
int isAlias; /* Input URL was an alias */
char *name; /* Hostname for http: or filename for file: */
char *hostname; /* The HOST: parameter on http headers */
| | | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
struct UrlData {
int isFile; /* True if a "file:" url */
int isHttps; /* True if a "https:" url */
int isSsh; /* True if an "ssh:" url */
int isAlias; /* Input URL was an alias */
char *name; /* Hostname for http: or filename for file: */
char *hostname; /* The HOST: parameter on http headers */
const char *protocol; /* "http" or "https" or "ssh" */
int port; /* TCP port number for http: or https: */
int dfltPort; /* The default port for the given protocol */
char *path; /* Pathname for http: */
char *user; /* User id for http: */
char *passwd; /* Password for http: */
char *canonical; /* Canonical representation of the URL */
char *proxyAuth; /* Proxy-Authorizer: string */
|
| ︙ | ︙ | |||
74 75 76 77 78 79 80 | ** last-sync-url setting using last-sync-pw as the password. Store ** the parser results in the pUrlData object. Populate members of pUrlData ** as follows: ** ** isFile True if FILE: ** isHttps True if HTTPS: ** isSsh True if SSH: | | | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | ** last-sync-url setting using last-sync-pw as the password. Store ** the parser results in the pUrlData object. Populate members of pUrlData ** as follows: ** ** isFile True if FILE: ** isHttps True if HTTPS: ** isSsh True if SSH: ** protocol "http" or "https" or "file" ** name Hostname for HTTP:, HTTPS:, SSH:. Filename for FILE: ** port TCP port number for HTTP or HTTPS. ** dfltPort Default TCP port number (80 or 443). ** path Path name for HTTP or HTTPS. ** user Userid. ** passwd Password. ** hostname HOST:PORT or just HOST if port is the default. |
| ︙ | ︙ | |||
303 304 305 306 307 308 309 | ** in the global "g.url" structure as shown below. If zUrl is NULL, then ** parse the URL given in the last-sync-url setting, taking the password ** form last-sync-pw. ** ** g.url.isFile True if FILE: ** g.url.isHttps True if HTTPS: ** g.url.isSsh True if SSH: | | | 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 | ** in the global "g.url" structure as shown below. If zUrl is NULL, then ** parse the URL given in the last-sync-url setting, taking the password ** form last-sync-pw. ** ** g.url.isFile True if FILE: ** g.url.isHttps True if HTTPS: ** g.url.isSsh True if SSH: ** g.url.protocol "http" or "https" or "file" ** g.url.name Hostname for HTTP:, HTTPS:, SSH:. Filename for FILE: ** g.url.port TCP port number for HTTP or HTTPS. ** g.url.dfltPort Default TCP port number (80 or 443). ** g.url.path Path name for HTTP or HTTPS. ** g.url.user Userid. ** g.url.passwd Password. ** g.url.hostname HOST:PORT or just HOST if port is the default. |
| ︙ | ︙ |
Changes to src/vfile.c.
| ︙ | ︙ | |||
305 306 307 308 309 310 311 |
" FROM vfile"
" WHERE id=%d AND mrid>0",
g.zLocalRoot, id);
}
while( db_step(&q)==SQLITE_ROW ){
int id, rid, isExe, isLink;
const char *zName;
| < > > > | 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 |
" FROM vfile"
" WHERE id=%d AND mrid>0",
g.zLocalRoot, id);
}
while( db_step(&q)==SQLITE_ROW ){
int id, rid, isExe, isLink;
const char *zName;
id = db_column_int(&q, 0);
zName = db_column_text(&q, 1);
rid = db_column_int(&q, 2);
isExe = db_column_int(&q, 3);
isLink = db_column_int(&q, 4);
if( file_unsafe_in_tree_path(zName) ){
continue;
}
content_get(rid, &content);
if( file_is_the_same(&content, zName) ){
blob_reset(&content);
if( file_setexe(zName, isExe) ){
db_multi_exec("UPDATE vfile SET mtime=%lld WHERE id=%d",
file_mtime(zName, RepoFILE), id);
}
|
| ︙ | ︙ | |||
338 339 340 341 342 343 344 |
promptFlag = 0;
} else if( cReply!='y' && cReply!='Y' ){
blob_reset(&content);
continue;
}
}
if( verbose ) fossil_print("%s\n", &zName[nRepos]);
| < < < < < < | 340 341 342 343 344 345 346 347 348 349 350 351 352 353 |
promptFlag = 0;
} else if( cReply!='y' && cReply!='Y' ){
blob_reset(&content);
continue;
}
}
if( verbose ) fossil_print("%s\n", &zName[nRepos]);
if( file_isdir(zName, RepoFILE)==1 ){
/*TODO(dchest): remove directories? */
fossil_fatal("%s is directory, cannot overwrite", zName);
}
if( file_size(zName, RepoFILE)>=0 && (isLink || file_islink(0)) ){
file_delete(zName);
}
|
| ︙ | ︙ |