Fossil SCM

Improved error message and response when trying to manifest a check-out that contains a file beneath a symbolic link directory.

drh 2020-08-18 20:19 sec2020
Commit 20d90dd4825ce5f7eb1168bdb62f75bed3447707bbb77f5720bda517e8bd4b76
2 files changed +11 -5 +7 -1
+11 -5
--- src/file.c
+++ src/file.c
@@ -327,12 +327,13 @@
327327
}
328328
329329
/*
330330
** Check every sub-directory of zRoot along the path to zFile.
331331
** 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.
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.
334335
**
335336
** Example: Given inputs
336337
**
337338
** zRoot = /home/alice/project1
338339
** zFile = /home/alice/project1/main/src/js/fileA.js
@@ -342,13 +343,14 @@
342343
** /home/alice/project/main
343344
** /home/alice/project/main/src
344345
** /home/alice/project/main/src/js
345346
**
346347
** If any of those objects exist and are something other than a directory
347
-** then delete the object and return.
348
+** then return the length of the name of the first non-directory object
349
+** seen.
348350
*/
349
-void file_delete_objects_on_path(const char *zRoot, const char *zFile){
351
+int file_nondir_objects_on_path(const char *zRoot, const char *zFile){
350352
int i = (int)strlen(zRoot);
351353
char *z = fossil_strdup(zFile);
352354
assert( fossil_strnicmp(zRoot, z, i)==0 );
353355
if( i && zRoot[i-1]=='/' ) i--;
354356
while( z[i]=='/' ){
@@ -356,17 +358,21 @@
356358
for(j=i+1; z[j] && z[j]!='/'; j++){}
357359
if( z[j]!='/' ) break;
358360
z[j] = 0;
359361
rc = file_isdir(z, SymFILE);
360362
if( rc!=1 ){
361
- if( rc==2 ) file_delete(z);
363
+ if( rc==2 ){
364
+ fossil_free(z);
365
+ return j;
366
+ }
362367
break;
363368
}
364369
z[j] = '/';
365370
i = j;
366371
}
367372
fossil_free(z);
373
+ return 0;
368374
}
369375
370376
/*
371377
** Return 1 if zFilename is a directory. Return 0 if zFilename
372378
** does not exist. Return 2 if zFilename exists but is something
373379
--- src/file.c
+++ src/file.c
@@ -327,12 +327,13 @@
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
@@ -342,13 +343,14 @@
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]=='/' ){
@@ -356,17 +358,21 @@
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
--- src/file.c
+++ src/file.c
@@ -327,12 +327,13 @@
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
@@ -342,13 +343,14 @@
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]=='/' ){
@@ -356,17 +358,21 @@
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 ** Return 1 if zFilename is a directory. Return 0 if zFilename
378 ** does not exist. Return 2 if zFilename exists but is something
379
+7 -1
--- src/vfile.c
+++ src/vfile.c
@@ -307,10 +307,11 @@
307307
g.zLocalRoot, id);
308308
}
309309
while( db_step(&q)==SQLITE_ROW ){
310310
int id, rid, isExe, isLink;
311311
const char *zName;
312
+ int n;
312313
313314
id = db_column_int(&q, 0);
314315
zName = db_column_text(&q, 1);
315316
rid = db_column_int(&q, 2);
316317
isExe = db_column_int(&q, 3);
@@ -339,11 +340,16 @@
339340
blob_reset(&content);
340341
continue;
341342
}
342343
}
343344
if( verbose ) fossil_print("%s\n", &zName[nRepos]);
344
- file_delete_objects_on_path(g.zLocalRoot, zName);
345
+ n = file_nondir_objects_on_path(g.zLocalRoot, zName);
346
+ if( n ){
347
+ fossil_fatal("cannot write %s because "
348
+ "non-directory object %.*s is in the way",
349
+ zName, n, zName);
350
+ }
345351
if( file_isdir(zName, RepoFILE)==1 ){
346352
/*TODO(dchest): remove directories? */
347353
fossil_fatal("%s is directory, cannot overwrite", zName);
348354
}
349355
if( file_size(zName, RepoFILE)>=0 && (isLink || file_islink(0)) ){
350356
--- src/vfile.c
+++ src/vfile.c
@@ -307,10 +307,11 @@
307 g.zLocalRoot, id);
308 }
309 while( db_step(&q)==SQLITE_ROW ){
310 int id, rid, isExe, isLink;
311 const char *zName;
 
312
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);
@@ -339,11 +340,16 @@
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
--- src/vfile.c
+++ src/vfile.c
@@ -307,10 +307,11 @@
307 g.zLocalRoot, id);
308 }
309 while( db_step(&q)==SQLITE_ROW ){
310 int id, rid, isExe, isLink;
311 const char *zName;
312 int n;
313
314 id = db_column_int(&q, 0);
315 zName = db_column_text(&q, 1);
316 rid = db_column_int(&q, 2);
317 isExe = db_column_int(&q, 3);
@@ -339,11 +340,16 @@
340 blob_reset(&content);
341 continue;
342 }
343 }
344 if( verbose ) fossil_print("%s\n", &zName[nRepos]);
345 n = file_nondir_objects_on_path(g.zLocalRoot, zName);
346 if( n ){
347 fossil_fatal("cannot write %s because "
348 "non-directory object %.*s is in the way",
349 zName, n, zName);
350 }
351 if( file_isdir(zName, RepoFILE)==1 ){
352 /*TODO(dchest): remove directories? */
353 fossil_fatal("%s is directory, cannot overwrite", zName);
354 }
355 if( file_size(zName, RepoFILE)>=0 && (isLink || file_islink(0)) ){
356

Keyboard Shortcuts

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