Fossil SCM

When writing files to disk for a check-out, refuse to write through a symbolic link to a directory. Ticket [f9831fdef1d4edcc].

drh 2020-08-18 12:17 sec2020
Commit a64e384f0c53ddce4cc0b1f46a671c07917bf30d2367dbcede6101a76d0ce9d4
2 files changed +45 -1 +1
+45 -1
--- src/file.c
+++ src/file.c
@@ -323,10 +323,51 @@
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
+** then delete that object. The inputs are expected to be full
333
+** pathnames.
334
+**
335
+** Example: Given inputs
336
+**
337
+** zRoot = /home/alice/project1
338
+** zFile = /home/alice/project1/main/src/js/fileA.js
339
+**
340
+** Look for objects in the following order:
341
+**
342
+** /home/alice/project/main
343
+** /home/alice/project/main/src
344
+** /home/alice/project/main/src/js
345
+**
346
+** If any of those objects exist and are something other than a directory
347
+** then delete the object and return.
348
+*/
349
+void file_delete_objects_on_path(const char *zRoot, const char *zFile){
350
+ int i = (int)strlen(zRoot);
351
+ char *z = fossil_strdup(zFile);
352
+ assert( fossil_strnicmp(zRoot, z, i)==0 );
353
+ if( i && zRoot[i-1]=='/' ) i--;
354
+ while( z[i]=='/' ){
355
+ int j, rc;
356
+ for(j=i+1; z[j] && z[j]!='/'; j++){}
357
+ if( z[j]!='/' ) break;
358
+ z[j] = 0;
359
+ rc = file_isdir(z, SymFILE);
360
+ if( rc!=1 ){
361
+ if( rc==2 ) file_delete(z);
362
+ break;
363
+ }
364
+ z[j] = '/';
365
+ i = j;
366
+ }
367
+ fossil_free(z);
368
+}
328369
329370
/*
330371
** Return 1 if zFilename is a directory. Return 0 if zFilename
331372
** does not exist. Return 2 if zFilename exists but is something
332373
** other than a directory.
@@ -570,11 +611,14 @@
570611
*/
571612
int file_setexe(const char *zFilename, int onoff){
572613
int rc = 0;
573614
#if !defined(_WIN32)
574615
struct stat buf;
575
- if( fossil_stat(zFilename, &buf, RepoFILE)!=0 || S_ISLNK(buf.st_mode) ){
616
+ if( fossil_stat(zFilename, &buf, RepoFILE)!=0
617
+ || S_ISLNK(buf.st_mode)
618
+ || S_ISDIR(buf.st_mode)
619
+ ){
576620
return 0;
577621
}
578622
if( onoff ){
579623
int targetMode = (buf.st_mode & 0444)>>2;
580624
if( (buf.st_mode & 0100)==0 ){
581625
--- src/file.c
+++ src/file.c
@@ -323,10 +323,51 @@
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 +611,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 ){
581
--- src/file.c
+++ src/file.c
@@ -323,10 +323,51 @@
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 ** then delete that object. The inputs are expected to be full
333 ** pathnames.
334 **
335 ** Example: Given inputs
336 **
337 ** zRoot = /home/alice/project1
338 ** zFile = /home/alice/project1/main/src/js/fileA.js
339 **
340 ** Look for objects in the following order:
341 **
342 ** /home/alice/project/main
343 ** /home/alice/project/main/src
344 ** /home/alice/project/main/src/js
345 **
346 ** If any of those objects exist and are something other than a directory
347 ** then delete the object and return.
348 */
349 void file_delete_objects_on_path(const char *zRoot, const char *zFile){
350 int i = (int)strlen(zRoot);
351 char *z = fossil_strdup(zFile);
352 assert( fossil_strnicmp(zRoot, z, i)==0 );
353 if( i && zRoot[i-1]=='/' ) i--;
354 while( z[i]=='/' ){
355 int j, rc;
356 for(j=i+1; z[j] && z[j]!='/'; j++){}
357 if( z[j]!='/' ) break;
358 z[j] = 0;
359 rc = file_isdir(z, SymFILE);
360 if( rc!=1 ){
361 if( rc==2 ) file_delete(z);
362 break;
363 }
364 z[j] = '/';
365 i = j;
366 }
367 fossil_free(z);
368 }
369
370 /*
371 ** Return 1 if zFilename is a directory. Return 0 if zFilename
372 ** does not exist. Return 2 if zFilename exists but is something
373 ** other than a directory.
@@ -570,11 +611,14 @@
611 */
612 int file_setexe(const char *zFilename, int onoff){
613 int rc = 0;
614 #if !defined(_WIN32)
615 struct stat buf;
616 if( fossil_stat(zFilename, &buf, RepoFILE)!=0
617 || S_ISLNK(buf.st_mode)
618 || S_ISDIR(buf.st_mode)
619 ){
620 return 0;
621 }
622 if( onoff ){
623 int targetMode = (buf.st_mode & 0444)>>2;
624 if( (buf.st_mode & 0100)==0 ){
625
--- src/vfile.c
+++ src/vfile.c
@@ -339,10 +339,11 @@
339339
blob_reset(&content);
340340
continue;
341341
}
342342
}
343343
if( verbose ) fossil_print("%s\n", &zName[nRepos]);
344
+ file_delete_objects_on_path(g.zLocalRoot, zName);
344345
if( file_isdir(zName, RepoFILE)==1 ){
345346
/*TODO(dchest): remove directories? */
346347
fossil_fatal("%s is directory, cannot overwrite", zName);
347348
}
348349
if( file_size(zName, RepoFILE)>=0 && (isLink || file_islink(0)) ){
349350
--- src/vfile.c
+++ src/vfile.c
@@ -339,10 +339,11 @@
339 blob_reset(&content);
340 continue;
341 }
342 }
343 if( verbose ) fossil_print("%s\n", &zName[nRepos]);
 
344 if( file_isdir(zName, RepoFILE)==1 ){
345 /*TODO(dchest): remove directories? */
346 fossil_fatal("%s is directory, cannot overwrite", zName);
347 }
348 if( file_size(zName, RepoFILE)>=0 && (isLink || file_islink(0)) ){
349
--- src/vfile.c
+++ src/vfile.c
@@ -339,10 +339,11 @@
339 blob_reset(&content);
340 continue;
341 }
342 }
343 if( verbose ) fossil_print("%s\n", &zName[nRepos]);
344 file_delete_objects_on_path(g.zLocalRoot, zName);
345 if( file_isdir(zName, RepoFILE)==1 ){
346 /*TODO(dchest): remove directories? */
347 fossil_fatal("%s is directory, cannot overwrite", zName);
348 }
349 if( file_size(zName, RepoFILE)>=0 && (isLink || file_islink(0)) ){
350

Keyboard Shortcuts

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