Fossil SCM
Fix some remaining corner cases when having a checkout on '/'.. - update was asserting when localroot is '/' - fix file_canonical_name() so it doesn't return '.' path must be '/' and avoid the double '/' on beginning in some case. - refactor file_canonical_name() function to avoid some duplicated code. - fix file_relative_name() so it handle properly relative path when working on '/'.
Commit
89ad123f5ceec73d44d24925313ef9700dd80f96
Parent
84abd455338f32e…
2 files changed
+31
-24
+1
-1
+31
-24
| --- src/file.c | ||
| +++ src/file.c | ||
| @@ -703,11 +703,11 @@ | ||
| 703 | 703 | } |
| 704 | 704 | } |
| 705 | 705 | if( j>=0 ) z[j] = z[i]; |
| 706 | 706 | j++; |
| 707 | 707 | } |
| 708 | - if( j==0 ) z[j++] = '.'; | |
| 708 | + if( j==0 ) z[j++] = '/'; | |
| 709 | 709 | z[j] = 0; |
| 710 | 710 | return j; |
| 711 | 711 | } |
| 712 | 712 | |
| 713 | 713 | /* |
| @@ -777,39 +777,40 @@ | ||
| 777 | 777 | ** Convert /A/../ to just / |
| 778 | 778 | ** If the slash parameter is non-zero, the trailing slash, if any, |
| 779 | 779 | ** is retained. |
| 780 | 780 | */ |
| 781 | 781 | void file_canonical_name(const char *zOrigName, Blob *pOut, int slash){ |
| 782 | + blob_zero(pOut); | |
| 782 | 783 | if( file_is_absolute_path(zOrigName) ){ |
| 783 | -#if defined(_WIN32) || defined(__CYGWIN__) | |
| 784 | - char *zOut; | |
| 785 | -#endif | |
| 786 | - blob_set(pOut, zOrigName); | |
| 787 | - blob_materialize(pOut); | |
| 784 | + blob_appendf(pOut, "%/", zOrigName); | |
| 785 | + }else{ | |
| 786 | + char zPwd[2000]; | |
| 787 | + file_getcwd(zPwd, sizeof(zPwd)-strlen(zOrigName)); | |
| 788 | + if( zPwd[0]=='/' && strlen(zPwd)==1 ){ | |
| 789 | + // when on '/', don't add an extra '/' | |
| 790 | + if( zOrigName[0]=='.' && strlen(zOrigName)==1 ){ | |
| 791 | + // '.' when on '/' mean '/' | |
| 792 | + blob_appendf(pOut, "%/", zPwd); | |
| 793 | + }else{ | |
| 794 | + blob_appendf(pOut, "%/%/", zPwd, zOrigName); | |
| 795 | + } | |
| 796 | + }else{ | |
| 797 | + blob_appendf(pOut, "%//%/", zPwd, zOrigName); | |
| 798 | + } | |
| 799 | + } | |
| 788 | 800 | #if defined(_WIN32) || defined(__CYGWIN__) |
| 801 | + { | |
| 802 | + char *zOut; | |
| 789 | 803 | /* |
| 790 | 804 | ** On Windows/cygwin, normalize the drive letter to upper case. |
| 791 | 805 | */ |
| 792 | 806 | zOut = blob_str(pOut); |
| 793 | - if( fossil_islower(zOut[0]) && zOut[1]==':' ){ | |
| 807 | + if( fossil_islower(zOut[0]) && zOut[1]==':' && zOut[2]=='/' ){ | |
| 794 | 808 | zOut[0] = fossil_toupper(zOut[0]); |
| 795 | 809 | } |
| 796 | -#endif | |
| 797 | - }else{ | |
| 798 | - char zPwd[2000]; | |
| 799 | - file_getcwd(zPwd, sizeof(zPwd)-strlen(zOrigName)); | |
| 800 | -#if defined(_WIN32) | |
| 801 | - /* | |
| 802 | - ** On Windows, normalize the drive letter to upper case. | |
| 803 | - */ | |
| 804 | - if( fossil_islower(zPwd[0]) && zPwd[1]==':' ){ | |
| 805 | - zPwd[0] = fossil_toupper(zPwd[0]); | |
| 806 | - } | |
| 807 | -#endif | |
| 808 | - blob_zero(pOut); | |
| 809 | - blob_appendf(pOut, "%//%/", zPwd, zOrigName); | |
| 810 | - } | |
| 810 | + } | |
| 811 | +#endif | |
| 811 | 812 | blob_resize(pOut, file_simplify_name(blob_buffer(pOut), |
| 812 | 813 | blob_size(pOut), slash)); |
| 813 | 814 | } |
| 814 | 815 | |
| 815 | 816 | /* |
| @@ -928,11 +929,16 @@ | ||
| 928 | 929 | blob_append(pOut, &zPath[i+1], -1); |
| 929 | 930 | blob_reset(&tmp); |
| 930 | 931 | return; |
| 931 | 932 | } |
| 932 | 933 | while( zPath[i-1]!='/' ){ i--; } |
| 933 | - blob_set(&tmp, "../"); | |
| 934 | + if( zPwd[0]=='/' && strlen(zPwd)==1 ){ | |
| 935 | + // If on '/', don't go to higher level | |
| 936 | + blob_zero(&tmp); | |
| 937 | + }else{ | |
| 938 | + blob_set(&tmp, "../"); | |
| 939 | + } | |
| 934 | 940 | for(j=i; zPwd[j]; j++){ |
| 935 | 941 | if( zPwd[j]=='/' ){ |
| 936 | 942 | blob_append(&tmp, "../", 3); |
| 937 | 943 | } |
| 938 | 944 | } |
| @@ -990,11 +996,12 @@ | ||
| 990 | 996 | }else{ |
| 991 | 997 | xCmp = fossil_strnicmp; |
| 992 | 998 | } |
| 993 | 999 | |
| 994 | 1000 | /* Special case. zOrigName refers to g.zLocalRoot directory. */ |
| 995 | - if( nFull==nLocalRoot-1 && xCmp(zLocalRoot, zFull, nFull)==0 ){ | |
| 1001 | + if( nFull==nLocalRoot-1 && xCmp(zLocalRoot, zFull, nFull)==0 | |
| 1002 | + || (nFull==1 && zFull[0]=='/' && nLocalRoot==1 && zLocalRoot[0]=='/') ){ | |
| 996 | 1003 | blob_append(pOut, ".", 1); |
| 997 | 1004 | blob_reset(&localRoot); |
| 998 | 1005 | blob_reset(&full); |
| 999 | 1006 | return 1; |
| 1000 | 1007 | } |
| 1001 | 1008 |
| --- src/file.c | |
| +++ src/file.c | |
| @@ -703,11 +703,11 @@ | |
| 703 | } |
| 704 | } |
| 705 | if( j>=0 ) z[j] = z[i]; |
| 706 | j++; |
| 707 | } |
| 708 | if( j==0 ) z[j++] = '.'; |
| 709 | z[j] = 0; |
| 710 | return j; |
| 711 | } |
| 712 | |
| 713 | /* |
| @@ -777,39 +777,40 @@ | |
| 777 | ** Convert /A/../ to just / |
| 778 | ** If the slash parameter is non-zero, the trailing slash, if any, |
| 779 | ** is retained. |
| 780 | */ |
| 781 | void file_canonical_name(const char *zOrigName, Blob *pOut, int slash){ |
| 782 | if( file_is_absolute_path(zOrigName) ){ |
| 783 | #if defined(_WIN32) || defined(__CYGWIN__) |
| 784 | char *zOut; |
| 785 | #endif |
| 786 | blob_set(pOut, zOrigName); |
| 787 | blob_materialize(pOut); |
| 788 | #if defined(_WIN32) || defined(__CYGWIN__) |
| 789 | /* |
| 790 | ** On Windows/cygwin, normalize the drive letter to upper case. |
| 791 | */ |
| 792 | zOut = blob_str(pOut); |
| 793 | if( fossil_islower(zOut[0]) && zOut[1]==':' ){ |
| 794 | zOut[0] = fossil_toupper(zOut[0]); |
| 795 | } |
| 796 | #endif |
| 797 | }else{ |
| 798 | char zPwd[2000]; |
| 799 | file_getcwd(zPwd, sizeof(zPwd)-strlen(zOrigName)); |
| 800 | #if defined(_WIN32) |
| 801 | /* |
| 802 | ** On Windows, normalize the drive letter to upper case. |
| 803 | */ |
| 804 | if( fossil_islower(zPwd[0]) && zPwd[1]==':' ){ |
| 805 | zPwd[0] = fossil_toupper(zPwd[0]); |
| 806 | } |
| 807 | #endif |
| 808 | blob_zero(pOut); |
| 809 | blob_appendf(pOut, "%//%/", zPwd, zOrigName); |
| 810 | } |
| 811 | blob_resize(pOut, file_simplify_name(blob_buffer(pOut), |
| 812 | blob_size(pOut), slash)); |
| 813 | } |
| 814 | |
| 815 | /* |
| @@ -928,11 +929,16 @@ | |
| 928 | blob_append(pOut, &zPath[i+1], -1); |
| 929 | blob_reset(&tmp); |
| 930 | return; |
| 931 | } |
| 932 | while( zPath[i-1]!='/' ){ i--; } |
| 933 | blob_set(&tmp, "../"); |
| 934 | for(j=i; zPwd[j]; j++){ |
| 935 | if( zPwd[j]=='/' ){ |
| 936 | blob_append(&tmp, "../", 3); |
| 937 | } |
| 938 | } |
| @@ -990,11 +996,12 @@ | |
| 990 | }else{ |
| 991 | xCmp = fossil_strnicmp; |
| 992 | } |
| 993 | |
| 994 | /* Special case. zOrigName refers to g.zLocalRoot directory. */ |
| 995 | if( nFull==nLocalRoot-1 && xCmp(zLocalRoot, zFull, nFull)==0 ){ |
| 996 | blob_append(pOut, ".", 1); |
| 997 | blob_reset(&localRoot); |
| 998 | blob_reset(&full); |
| 999 | return 1; |
| 1000 | } |
| 1001 |
| --- src/file.c | |
| +++ src/file.c | |
| @@ -703,11 +703,11 @@ | |
| 703 | } |
| 704 | } |
| 705 | if( j>=0 ) z[j] = z[i]; |
| 706 | j++; |
| 707 | } |
| 708 | if( j==0 ) z[j++] = '/'; |
| 709 | z[j] = 0; |
| 710 | return j; |
| 711 | } |
| 712 | |
| 713 | /* |
| @@ -777,39 +777,40 @@ | |
| 777 | ** Convert /A/../ to just / |
| 778 | ** If the slash parameter is non-zero, the trailing slash, if any, |
| 779 | ** is retained. |
| 780 | */ |
| 781 | void file_canonical_name(const char *zOrigName, Blob *pOut, int slash){ |
| 782 | blob_zero(pOut); |
| 783 | if( file_is_absolute_path(zOrigName) ){ |
| 784 | blob_appendf(pOut, "%/", zOrigName); |
| 785 | }else{ |
| 786 | char zPwd[2000]; |
| 787 | file_getcwd(zPwd, sizeof(zPwd)-strlen(zOrigName)); |
| 788 | if( zPwd[0]=='/' && strlen(zPwd)==1 ){ |
| 789 | // when on '/', don't add an extra '/' |
| 790 | if( zOrigName[0]=='.' && strlen(zOrigName)==1 ){ |
| 791 | // '.' when on '/' mean '/' |
| 792 | blob_appendf(pOut, "%/", zPwd); |
| 793 | }else{ |
| 794 | blob_appendf(pOut, "%/%/", zPwd, zOrigName); |
| 795 | } |
| 796 | }else{ |
| 797 | blob_appendf(pOut, "%//%/", zPwd, zOrigName); |
| 798 | } |
| 799 | } |
| 800 | #if defined(_WIN32) || defined(__CYGWIN__) |
| 801 | { |
| 802 | char *zOut; |
| 803 | /* |
| 804 | ** On Windows/cygwin, normalize the drive letter to upper case. |
| 805 | */ |
| 806 | zOut = blob_str(pOut); |
| 807 | if( fossil_islower(zOut[0]) && zOut[1]==':' && zOut[2]=='/' ){ |
| 808 | zOut[0] = fossil_toupper(zOut[0]); |
| 809 | } |
| 810 | } |
| 811 | #endif |
| 812 | blob_resize(pOut, file_simplify_name(blob_buffer(pOut), |
| 813 | blob_size(pOut), slash)); |
| 814 | } |
| 815 | |
| 816 | /* |
| @@ -928,11 +929,16 @@ | |
| 929 | blob_append(pOut, &zPath[i+1], -1); |
| 930 | blob_reset(&tmp); |
| 931 | return; |
| 932 | } |
| 933 | while( zPath[i-1]!='/' ){ i--; } |
| 934 | if( zPwd[0]=='/' && strlen(zPwd)==1 ){ |
| 935 | // If on '/', don't go to higher level |
| 936 | blob_zero(&tmp); |
| 937 | }else{ |
| 938 | blob_set(&tmp, "../"); |
| 939 | } |
| 940 | for(j=i; zPwd[j]; j++){ |
| 941 | if( zPwd[j]=='/' ){ |
| 942 | blob_append(&tmp, "../", 3); |
| 943 | } |
| 944 | } |
| @@ -990,11 +996,12 @@ | |
| 996 | }else{ |
| 997 | xCmp = fossil_strnicmp; |
| 998 | } |
| 999 | |
| 1000 | /* Special case. zOrigName refers to g.zLocalRoot directory. */ |
| 1001 | if( nFull==nLocalRoot-1 && xCmp(zLocalRoot, zFull, nFull)==0 |
| 1002 | || (nFull==1 && zFull[0]=='/' && nLocalRoot==1 && zLocalRoot[0]=='/') ){ |
| 1003 | blob_append(pOut, ".", 1); |
| 1004 | blob_reset(&localRoot); |
| 1005 | blob_reset(&full); |
| 1006 | return 1; |
| 1007 | } |
| 1008 |
+1
-1
| --- src/update.c | ||
| +++ src/update.c | ||
| @@ -353,11 +353,11 @@ | ||
| 353 | 353 | db_prepare(&mtimeXfer, |
| 354 | 354 | "UPDATE vfile SET mtime=(SELECT mtime FROM vfile WHERE id=:idv)" |
| 355 | 355 | " WHERE id=:idt" |
| 356 | 356 | ); |
| 357 | 357 | assert( g.zLocalRoot!=0 ); |
| 358 | - assert( strlen(g.zLocalRoot)>1 ); | |
| 358 | + assert( strlen(g.zLocalRoot)>0 ); | |
| 359 | 359 | assert( g.zLocalRoot[strlen(g.zLocalRoot)-1]=='/' ); |
| 360 | 360 | while( db_step(&q)==SQLITE_ROW ){ |
| 361 | 361 | const char *zName = db_column_text(&q, 0); /* The filename from root */ |
| 362 | 362 | int idv = db_column_int(&q, 1); /* VFILE entry for current */ |
| 363 | 363 | int ridv = db_column_int(&q, 2); /* RecordID for current */ |
| 364 | 364 |
| --- src/update.c | |
| +++ src/update.c | |
| @@ -353,11 +353,11 @@ | |
| 353 | db_prepare(&mtimeXfer, |
| 354 | "UPDATE vfile SET mtime=(SELECT mtime FROM vfile WHERE id=:idv)" |
| 355 | " WHERE id=:idt" |
| 356 | ); |
| 357 | assert( g.zLocalRoot!=0 ); |
| 358 | assert( strlen(g.zLocalRoot)>1 ); |
| 359 | assert( g.zLocalRoot[strlen(g.zLocalRoot)-1]=='/' ); |
| 360 | while( db_step(&q)==SQLITE_ROW ){ |
| 361 | const char *zName = db_column_text(&q, 0); /* The filename from root */ |
| 362 | int idv = db_column_int(&q, 1); /* VFILE entry for current */ |
| 363 | int ridv = db_column_int(&q, 2); /* RecordID for current */ |
| 364 |
| --- src/update.c | |
| +++ src/update.c | |
| @@ -353,11 +353,11 @@ | |
| 353 | db_prepare(&mtimeXfer, |
| 354 | "UPDATE vfile SET mtime=(SELECT mtime FROM vfile WHERE id=:idv)" |
| 355 | " WHERE id=:idt" |
| 356 | ); |
| 357 | assert( g.zLocalRoot!=0 ); |
| 358 | assert( strlen(g.zLocalRoot)>0 ); |
| 359 | assert( g.zLocalRoot[strlen(g.zLocalRoot)-1]=='/' ); |
| 360 | while( db_step(&q)==SQLITE_ROW ){ |
| 361 | const char *zName = db_column_text(&q, 0); /* The filename from root */ |
| 362 | int idv = db_column_int(&q, 1); /* VFILE entry for current */ |
| 363 | int ridv = db_column_int(&q, 2); /* RecordID for current */ |
| 364 |