Fossil SCM
Add the new file_skip_userhost() function that will find an skip over a "USER@HOST:" prefix on a filename, if it exists. Use this to extract the USER@HOST prefix from names in the "fossil patch push/pull" commands.
Commit
89a85888539021dd76093725e299199da8f7af6cb76cf243284aff710671952f
Parent
9ec744ed79ab513…
2 files changed
+53
-2
+2
-3
+53
-2
| --- src/file.c | ||
| +++ src/file.c | ||
| @@ -909,10 +909,49 @@ | ||
| 909 | 909 | }else{ |
| 910 | 910 | rc = file_rmdir(zName); |
| 911 | 911 | } |
| 912 | 912 | sqlite3_result_int(context, rc); |
| 913 | 913 | } |
| 914 | + | |
| 915 | +/* | |
| 916 | +** Check the input argument to see if it looks like it has an prefix that | |
| 917 | +** indicates a remote file. If so, return the tail of the specification, | |
| 918 | +** which is the name of the file on the remote system. | |
| 919 | +** | |
| 920 | +** If the input argument does not have a prefix that makes it look like | |
| 921 | +** a remote file reference, then return NULL. | |
| 922 | +** | |
| 923 | +** Remote files look like: "HOST:PATH" or "USER@HOST:PATH". Host must | |
| 924 | +** be a valid hostname, meaning it must follow these rules: | |
| 925 | +** | |
| 926 | +** * Only characters [-.a-zA-Z0-9]. No spaces or other punctuation | |
| 927 | +** * Does not begin or end with - | |
| 928 | +** | |
| 929 | +** The USER section, it it exists, must not contain the '@' character. | |
| 930 | +*/ | |
| 931 | +const char *file_skip_userhost(const char *zIn){ | |
| 932 | + const char *zTail; | |
| 933 | + int n, i; | |
| 934 | + if( zIn[0]==':' ) return 0; | |
| 935 | + zTail = strchr(zIn, ':'); | |
| 936 | + if( zTail==0 ) return 0; | |
| 937 | + if( zTail - zIn > 10000 ) return 0; | |
| 938 | + n = (int)(zTail - zIn); | |
| 939 | + if( zIn[n-1]=='-' || zIn[n-1]=='.' ) return 0; | |
| 940 | + for(i=n-1; i>0 && zIn[i-1]!='@'; i--){ | |
| 941 | + if( !fossil_isalnum(zIn[i]) && zIn[i]!='-' && zIn[i]!='.' ) return 0; | |
| 942 | + } | |
| 943 | + if( zIn[i]=='-' || zIn[i]=='.' || i==1 ) return 0; | |
| 944 | + if( i>1 ){ | |
| 945 | + i -= 2; | |
| 946 | + while( i>=0 ){ | |
| 947 | + if( zIn[i]=='@' ) return 0; | |
| 948 | + i--; | |
| 949 | + } | |
| 950 | + } | |
| 951 | + return zTail+1; | |
| 952 | +} | |
| 914 | 953 | |
| 915 | 954 | /* |
| 916 | 955 | ** Return true if the filename given is a valid filename for |
| 917 | 956 | ** a file in a repository. Valid filenames follow all of the |
| 918 | 957 | ** following rules: |
| @@ -1113,17 +1152,29 @@ | ||
| 1113 | 1152 | /* |
| 1114 | 1153 | ** COMMAND: test-simplify-name |
| 1115 | 1154 | ** |
| 1116 | 1155 | ** Usage: %fossil test-simplify-name FILENAME... |
| 1117 | 1156 | ** |
| 1118 | -** Print the simplified versions of each FILENAME. | |
| 1157 | +** Print the simplified versions of each FILENAME. This is used to test | |
| 1158 | +** the file_simplify_name() routine. | |
| 1159 | +** | |
| 1160 | +** If FILENAME is of the form "HOST:PATH" or "USER@HOST:PATH", then remove | |
| 1161 | +** and print the remote host prefix first. This is used to test the | |
| 1162 | +** file_skip_userhost() interface. | |
| 1119 | 1163 | */ |
| 1120 | 1164 | void cmd_test_simplify_name(void){ |
| 1121 | 1165 | int i; |
| 1122 | 1166 | char *z; |
| 1167 | + const char *zTail; | |
| 1123 | 1168 | for(i=2; i<g.argc; i++){ |
| 1124 | - z = mprintf("%s", g.argv[i]); | |
| 1169 | + zTail = file_skip_userhost(g.argv[i]); | |
| 1170 | + if( zTail ){ | |
| 1171 | + fossil_print("... ON REMOTE: %.*s\n", (int)(zTail-g.argv[i]), g.argv[i]); | |
| 1172 | + z = mprintf("%s", zTail); | |
| 1173 | + }else{ | |
| 1174 | + z = mprintf("%s", g.argv[i]); | |
| 1175 | + } | |
| 1125 | 1176 | fossil_print("[%s] -> ", z); |
| 1126 | 1177 | file_simplify_name(z, -1, 0); |
| 1127 | 1178 | fossil_print("[%s]\n", z); |
| 1128 | 1179 | fossil_free(z); |
| 1129 | 1180 | } |
| 1130 | 1181 |
| --- src/file.c | |
| +++ src/file.c | |
| @@ -909,10 +909,49 @@ | |
| 909 | }else{ |
| 910 | rc = file_rmdir(zName); |
| 911 | } |
| 912 | sqlite3_result_int(context, rc); |
| 913 | } |
| 914 | |
| 915 | /* |
| 916 | ** Return true if the filename given is a valid filename for |
| 917 | ** a file in a repository. Valid filenames follow all of the |
| 918 | ** following rules: |
| @@ -1113,17 +1152,29 @@ | |
| 1113 | /* |
| 1114 | ** COMMAND: test-simplify-name |
| 1115 | ** |
| 1116 | ** Usage: %fossil test-simplify-name FILENAME... |
| 1117 | ** |
| 1118 | ** Print the simplified versions of each FILENAME. |
| 1119 | */ |
| 1120 | void cmd_test_simplify_name(void){ |
| 1121 | int i; |
| 1122 | char *z; |
| 1123 | for(i=2; i<g.argc; i++){ |
| 1124 | z = mprintf("%s", g.argv[i]); |
| 1125 | fossil_print("[%s] -> ", z); |
| 1126 | file_simplify_name(z, -1, 0); |
| 1127 | fossil_print("[%s]\n", z); |
| 1128 | fossil_free(z); |
| 1129 | } |
| 1130 |
| --- src/file.c | |
| +++ src/file.c | |
| @@ -909,10 +909,49 @@ | |
| 909 | }else{ |
| 910 | rc = file_rmdir(zName); |
| 911 | } |
| 912 | sqlite3_result_int(context, rc); |
| 913 | } |
| 914 | |
| 915 | /* |
| 916 | ** Check the input argument to see if it looks like it has an prefix that |
| 917 | ** indicates a remote file. If so, return the tail of the specification, |
| 918 | ** which is the name of the file on the remote system. |
| 919 | ** |
| 920 | ** If the input argument does not have a prefix that makes it look like |
| 921 | ** a remote file reference, then return NULL. |
| 922 | ** |
| 923 | ** Remote files look like: "HOST:PATH" or "USER@HOST:PATH". Host must |
| 924 | ** be a valid hostname, meaning it must follow these rules: |
| 925 | ** |
| 926 | ** * Only characters [-.a-zA-Z0-9]. No spaces or other punctuation |
| 927 | ** * Does not begin or end with - |
| 928 | ** |
| 929 | ** The USER section, it it exists, must not contain the '@' character. |
| 930 | */ |
| 931 | const char *file_skip_userhost(const char *zIn){ |
| 932 | const char *zTail; |
| 933 | int n, i; |
| 934 | if( zIn[0]==':' ) return 0; |
| 935 | zTail = strchr(zIn, ':'); |
| 936 | if( zTail==0 ) return 0; |
| 937 | if( zTail - zIn > 10000 ) return 0; |
| 938 | n = (int)(zTail - zIn); |
| 939 | if( zIn[n-1]=='-' || zIn[n-1]=='.' ) return 0; |
| 940 | for(i=n-1; i>0 && zIn[i-1]!='@'; i--){ |
| 941 | if( !fossil_isalnum(zIn[i]) && zIn[i]!='-' && zIn[i]!='.' ) return 0; |
| 942 | } |
| 943 | if( zIn[i]=='-' || zIn[i]=='.' || i==1 ) return 0; |
| 944 | if( i>1 ){ |
| 945 | i -= 2; |
| 946 | while( i>=0 ){ |
| 947 | if( zIn[i]=='@' ) return 0; |
| 948 | i--; |
| 949 | } |
| 950 | } |
| 951 | return zTail+1; |
| 952 | } |
| 953 | |
| 954 | /* |
| 955 | ** Return true if the filename given is a valid filename for |
| 956 | ** a file in a repository. Valid filenames follow all of the |
| 957 | ** following rules: |
| @@ -1113,17 +1152,29 @@ | |
| 1152 | /* |
| 1153 | ** COMMAND: test-simplify-name |
| 1154 | ** |
| 1155 | ** Usage: %fossil test-simplify-name FILENAME... |
| 1156 | ** |
| 1157 | ** Print the simplified versions of each FILENAME. This is used to test |
| 1158 | ** the file_simplify_name() routine. |
| 1159 | ** |
| 1160 | ** If FILENAME is of the form "HOST:PATH" or "USER@HOST:PATH", then remove |
| 1161 | ** and print the remote host prefix first. This is used to test the |
| 1162 | ** file_skip_userhost() interface. |
| 1163 | */ |
| 1164 | void cmd_test_simplify_name(void){ |
| 1165 | int i; |
| 1166 | char *z; |
| 1167 | const char *zTail; |
| 1168 | for(i=2; i<g.argc; i++){ |
| 1169 | zTail = file_skip_userhost(g.argv[i]); |
| 1170 | if( zTail ){ |
| 1171 | fossil_print("... ON REMOTE: %.*s\n", (int)(zTail-g.argv[i]), g.argv[i]); |
| 1172 | z = mprintf("%s", zTail); |
| 1173 | }else{ |
| 1174 | z = mprintf("%s", g.argv[i]); |
| 1175 | } |
| 1176 | fossil_print("[%s] -> ", z); |
| 1177 | file_simplify_name(z, -1, 0); |
| 1178 | fossil_print("[%s]\n", z); |
| 1179 | fossil_free(z); |
| 1180 | } |
| 1181 |
+2
-3
| --- src/patch.c | ||
| +++ src/patch.c | ||
| @@ -669,20 +669,19 @@ | ||
| 669 | 669 | const char *zForce = (mFlags & PATCH_FORCE)!=0 ? " -f" : ""; |
| 670 | 670 | if( g.argc!=4 ){ |
| 671 | 671 | usage(mprintf("%s [USER@]HOST:DIRECTORY", zThisCmd)); |
| 672 | 672 | } |
| 673 | 673 | zRemote = fossil_strdup(g.argv[3]); |
| 674 | - zDir = strchr(zRemote,':'); | |
| 674 | + zDir = (char*)file_skip_userhost(zRemote); | |
| 675 | 675 | if( zDir==0 ){ |
| 676 | 676 | zDir = zRemote; |
| 677 | 677 | blob_init(&cmd, 0, 0); |
| 678 | 678 | blob_append_escaped_arg(&cmd, g.nameOfExe, 1); |
| 679 | 679 | blob_appendf(&cmd, " patch %s%s %$ -", zRemoteCmd, zForce, zDir); |
| 680 | 680 | }else{ |
| 681 | 681 | Blob remote; |
| 682 | - zDir[0] = 0; | |
| 683 | - zDir++; | |
| 682 | + *(char*)(zDir-1) = 0; | |
| 684 | 683 | transport_ssh_command(&cmd); |
| 685 | 684 | blob_append_escaped_arg(&cmd, zRemote, 0); |
| 686 | 685 | blob_init(&remote, 0, 0); |
| 687 | 686 | blob_appendf(&remote, "fossil patch %s%s --dir64 %z -", |
| 688 | 687 | zRemoteCmd, zForce, encode64(zDir, -1)); |
| 689 | 688 |
| --- src/patch.c | |
| +++ src/patch.c | |
| @@ -669,20 +669,19 @@ | |
| 669 | const char *zForce = (mFlags & PATCH_FORCE)!=0 ? " -f" : ""; |
| 670 | if( g.argc!=4 ){ |
| 671 | usage(mprintf("%s [USER@]HOST:DIRECTORY", zThisCmd)); |
| 672 | } |
| 673 | zRemote = fossil_strdup(g.argv[3]); |
| 674 | zDir = strchr(zRemote,':'); |
| 675 | if( zDir==0 ){ |
| 676 | zDir = zRemote; |
| 677 | blob_init(&cmd, 0, 0); |
| 678 | blob_append_escaped_arg(&cmd, g.nameOfExe, 1); |
| 679 | blob_appendf(&cmd, " patch %s%s %$ -", zRemoteCmd, zForce, zDir); |
| 680 | }else{ |
| 681 | Blob remote; |
| 682 | zDir[0] = 0; |
| 683 | zDir++; |
| 684 | transport_ssh_command(&cmd); |
| 685 | blob_append_escaped_arg(&cmd, zRemote, 0); |
| 686 | blob_init(&remote, 0, 0); |
| 687 | blob_appendf(&remote, "fossil patch %s%s --dir64 %z -", |
| 688 | zRemoteCmd, zForce, encode64(zDir, -1)); |
| 689 |
| --- src/patch.c | |
| +++ src/patch.c | |
| @@ -669,20 +669,19 @@ | |
| 669 | const char *zForce = (mFlags & PATCH_FORCE)!=0 ? " -f" : ""; |
| 670 | if( g.argc!=4 ){ |
| 671 | usage(mprintf("%s [USER@]HOST:DIRECTORY", zThisCmd)); |
| 672 | } |
| 673 | zRemote = fossil_strdup(g.argv[3]); |
| 674 | zDir = (char*)file_skip_userhost(zRemote); |
| 675 | if( zDir==0 ){ |
| 676 | zDir = zRemote; |
| 677 | blob_init(&cmd, 0, 0); |
| 678 | blob_append_escaped_arg(&cmd, g.nameOfExe, 1); |
| 679 | blob_appendf(&cmd, " patch %s%s %$ -", zRemoteCmd, zForce, zDir); |
| 680 | }else{ |
| 681 | Blob remote; |
| 682 | *(char*)(zDir-1) = 0; |
| 683 | transport_ssh_command(&cmd); |
| 684 | blob_append_escaped_arg(&cmd, zRemote, 0); |
| 685 | blob_init(&remote, 0, 0); |
| 686 | blob_appendf(&remote, "fossil patch %s%s --dir64 %z -", |
| 687 | zRemoteCmd, zForce, encode64(zDir, -1)); |
| 688 |