| | @@ -113,11 +113,16 @@ |
| 113 | 113 | ** be initialized to an empty string. |
| 114 | 114 | ** |
| 115 | 115 | ** Any artifact successfully received by this routine is considered to |
| 116 | 116 | ** be public and is therefore removed from the "private" table. |
| 117 | 117 | */ |
| 118 | | -static void xfer_accept_file(Xfer *pXfer, int cloneFlag){ |
| 118 | +static void xfer_accept_file( |
| 119 | + Xfer *pXfer, |
| 120 | + int cloneFlag, |
| 121 | + char **pzUuidList, |
| 122 | + int *pnUuidList |
| 123 | +){ |
| 119 | 124 | int n; |
| 120 | 125 | int rid; |
| 121 | 126 | int srcid = 0; |
| 122 | 127 | Blob content, hash; |
| 123 | 128 | int isPriv; |
| | @@ -155,10 +160,12 @@ |
| 155 | 160 | srcid = 0; |
| 156 | 161 | pXfer->nFileRcvd++; |
| 157 | 162 | } |
| 158 | 163 | rid = content_put_ex(&content, blob_str(&pXfer->aToken[1]), srcid, |
| 159 | 164 | 0, isPriv); |
| 165 | + Th_AppendToList(pzUuidList, pnUuidList, blob_str(&pXfer->aToken[1]), |
| 166 | + blob_size(&pXfer->aToken[1])); |
| 160 | 167 | remote_has(rid); |
| 161 | 168 | blob_reset(&content); |
| 162 | 169 | return; |
| 163 | 170 | } |
| 164 | 171 | if( pXfer->nToken==4 ){ |
| | @@ -165,10 +172,12 @@ |
| 165 | 172 | Blob src, next; |
| 166 | 173 | srcid = rid_from_uuid(&pXfer->aToken[2], 1, isPriv); |
| 167 | 174 | if( content_get(srcid, &src)==0 ){ |
| 168 | 175 | rid = content_put_ex(&content, blob_str(&pXfer->aToken[1]), srcid, |
| 169 | 176 | 0, isPriv); |
| 177 | + Th_AppendToList(pzUuidList, pnUuidList, blob_str(&pXfer->aToken[1]), |
| 178 | + blob_size(&pXfer->aToken[1])); |
| 170 | 179 | pXfer->nDanglingFile++; |
| 171 | 180 | db_multi_exec("DELETE FROM phantom WHERE rid=%d", rid); |
| 172 | 181 | if( !isPriv ) content_make_public(rid); |
| 173 | 182 | blob_reset(&src); |
| 174 | 183 | blob_reset(&content); |
| | @@ -185,10 +194,11 @@ |
| 185 | 194 | sha1sum_blob(&content, &hash); |
| 186 | 195 | if( !blob_eq_str(&pXfer->aToken[1], blob_str(&hash), -1) ){ |
| 187 | 196 | blob_appendf(&pXfer->err, "content does not match sha1 hash"); |
| 188 | 197 | } |
| 189 | 198 | rid = content_put_ex(&content, blob_str(&hash), 0, 0, isPriv); |
| 199 | + Th_AppendToList(pzUuidList, pnUuidList, blob_str(&hash), blob_size(&hash)); |
| 190 | 200 | blob_reset(&hash); |
| 191 | 201 | if( rid==0 ){ |
| 192 | 202 | blob_appendf(&pXfer->err, "%s", g.zErrMsg); |
| 193 | 203 | blob_reset(&content); |
| 194 | 204 | }else{ |
| | @@ -220,11 +230,15 @@ |
| 220 | 230 | ** be initialized to an empty string. |
| 221 | 231 | ** |
| 222 | 232 | ** Any artifact successfully received by this routine is considered to |
| 223 | 233 | ** be public and is therefore removed from the "private" table. |
| 224 | 234 | */ |
| 225 | | -static void xfer_accept_compressed_file(Xfer *pXfer){ |
| 235 | +static void xfer_accept_compressed_file( |
| 236 | + Xfer *pXfer, |
| 237 | + char **pzUuidList, |
| 238 | + int *pnUuidList |
| 239 | +){ |
| 226 | 240 | int szC; /* CSIZE */ |
| 227 | 241 | int szU; /* USIZE */ |
| 228 | 242 | int rid; |
| 229 | 243 | int srcid = 0; |
| 230 | 244 | Blob content; |
| | @@ -261,10 +275,12 @@ |
| 261 | 275 | srcid = 0; |
| 262 | 276 | pXfer->nFileRcvd++; |
| 263 | 277 | } |
| 264 | 278 | rid = content_put_ex(&content, blob_str(&pXfer->aToken[1]), srcid, |
| 265 | 279 | szC, isPriv); |
| 280 | + Th_AppendToList(pzUuidList, pnUuidList, blob_str(&pXfer->aToken[1]), |
| 281 | + blob_size(&pXfer->aToken[1])); |
| 266 | 282 | remote_has(rid); |
| 267 | 283 | blob_reset(&content); |
| 268 | 284 | } |
| 269 | 285 | |
| 270 | 286 | /* |
| | @@ -853,21 +869,19 @@ |
| 853 | 869 | } |
| 854 | 870 | |
| 855 | 871 | /* |
| 856 | 872 | ** Run the specified TH1 script, if any, and returns 1 on error. |
| 857 | 873 | */ |
| 858 | | -int xfer_run_script(const char *zScript, const char *zUuid){ |
| 859 | | - int rc; |
| 860 | | - if( !zScript ) return TH_OK; |
| 874 | +int xfer_run_script( |
| 875 | + const char *zScript, |
| 876 | + const char *zUuidOrList, |
| 877 | + int bIsList |
| 878 | +){ |
| 879 | + int rc = TH_OK; |
| 880 | + if( !zScript ) return rc; |
| 861 | 881 | Th_FossilInit(TH_INIT_DEFAULT); |
| 862 | | - if( zUuid ){ |
| 863 | | - rc = Th_SetVar(g.interp, "uuid", -1, zUuid, -1); |
| 864 | | - if( rc!=TH_OK ){ |
| 865 | | - fossil_error(1, "%s", Th_GetResult(g.interp, 0)); |
| 866 | | - return rc; |
| 867 | | - } |
| 868 | | - } |
| 882 | + Th_Store(bIsList ? "uuids" : "uuid", zUuidOrList ? zUuidOrList : ""); |
| 869 | 883 | rc = Th_Eval(g.interp, 0, zScript, -1); |
| 870 | 884 | if( rc!=TH_OK ){ |
| 871 | 885 | fossil_error(1, "%s", Th_GetResult(g.interp, 0)); |
| 872 | 886 | } |
| 873 | 887 | return rc; |
| | @@ -883,11 +897,11 @@ |
| 883 | 897 | ** # ... code here |
| 884 | 898 | ** set common_done 1 |
| 885 | 899 | ** } |
| 886 | 900 | */ |
| 887 | 901 | int xfer_run_common_script(void){ |
| 888 | | - return xfer_run_script(xfer_common_code(), 0); |
| 902 | + return xfer_run_script(xfer_common_code(), 0, 0); |
| 889 | 903 | } |
| 890 | 904 | |
| 891 | 905 | /* |
| 892 | 906 | ** If this variable is set, disable login checks. Used for debugging |
| 893 | 907 | ** only. |
| | @@ -917,10 +931,15 @@ |
| 917 | 931 | int nGimme = 0; |
| 918 | 932 | int size; |
| 919 | 933 | int recvConfig = 0; |
| 920 | 934 | char *zNow; |
| 921 | 935 | int rc; |
| 936 | + const char *zScript = 0; |
| 937 | + char *zUuidList = 0; |
| 938 | + int nUuidList = 0; |
| 939 | + char **pzUuidList = 0; |
| 940 | + int *pnUuidList = 0; |
| 922 | 941 | |
| 923 | 942 | if( fossil_strcmp(PD("REQUEST_METHOD","POST"),"POST") ){ |
| 924 | 943 | fossil_redirect_home(); |
| 925 | 944 | } |
| 926 | 945 | g.zLogin = "anonymous"; |
| | @@ -951,10 +970,15 @@ |
| 951 | 970 | rc = xfer_run_common_script(); |
| 952 | 971 | if( rc==TH_ERROR ){ |
| 953 | 972 | cgi_reset_content(); |
| 954 | 973 | @ error common\sscript\sfailed:\s%F(g.zErrMsg) |
| 955 | 974 | nErr++; |
| 975 | + } |
| 976 | + zScript = xfer_push_code(); |
| 977 | + if( zScript ){ /* NOTE: Are TH1 transfer hooks enabled? */ |
| 978 | + pzUuidList = &zUuidList; |
| 979 | + pnUuidList = &nUuidList; |
| 956 | 980 | } |
| 957 | 981 | while( blob_line(xfer.pIn, &xfer.line) ){ |
| 958 | 982 | if( blob_buffer(&xfer.line)[0]=='#' ) continue; |
| 959 | 983 | if( blob_size(&xfer.line)==0 ) continue; |
| 960 | 984 | xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken)); |
| | @@ -969,11 +993,11 @@ |
| 969 | 993 | cgi_reset_content(); |
| 970 | 994 | @ error not\sauthorized\sto\swrite |
| 971 | 995 | nErr++; |
| 972 | 996 | break; |
| 973 | 997 | } |
| 974 | | - xfer_accept_file(&xfer, 0); |
| 998 | + xfer_accept_file(&xfer, 0, pzUuidList, pnUuidList); |
| 975 | 999 | if( blob_size(&xfer.err) ){ |
| 976 | 1000 | cgi_reset_content(); |
| 977 | 1001 | @ error %T(blob_str(&xfer.err)) |
| 978 | 1002 | nErr++; |
| 979 | 1003 | break; |
| | @@ -990,11 +1014,11 @@ |
| 990 | 1014 | cgi_reset_content(); |
| 991 | 1015 | @ error not\sauthorized\sto\swrite |
| 992 | 1016 | nErr++; |
| 993 | 1017 | break; |
| 994 | 1018 | } |
| 995 | | - xfer_accept_compressed_file(&xfer); |
| 1019 | + xfer_accept_compressed_file(&xfer, pzUuidList, pnUuidList); |
| 996 | 1020 | if( blob_size(&xfer.err) ){ |
| 997 | 1021 | cgi_reset_content(); |
| 998 | 1022 | @ error %T(blob_str(&xfer.err)) |
| 999 | 1023 | nErr++; |
| 1000 | 1024 | break; |
| | @@ -1275,19 +1299,22 @@ |
| 1275 | 1299 | blobarray_reset(xfer.aToken, xfer.nToken); |
| 1276 | 1300 | blob_reset(&xfer.line); |
| 1277 | 1301 | } |
| 1278 | 1302 | if( isPush ){ |
| 1279 | 1303 | if( rc==TH_OK ){ |
| 1280 | | - rc = xfer_run_script(xfer_push_code(), 0); |
| 1304 | + rc = xfer_run_script(zScript, zUuidList, 1); |
| 1281 | 1305 | if( rc==TH_ERROR ){ |
| 1282 | 1306 | cgi_reset_content(); |
| 1283 | 1307 | @ error push\sscript\sfailed:\s%F(g.zErrMsg) |
| 1284 | 1308 | nErr++; |
| 1285 | 1309 | } |
| 1286 | 1310 | } |
| 1287 | 1311 | request_phantoms(&xfer, 500); |
| 1288 | 1312 | } |
| 1313 | + if( zUuidList ){ |
| 1314 | + Th_Free(g.interp, zUuidList); |
| 1315 | + } |
| 1289 | 1316 | if( isClone && nGimme==0 ){ |
| 1290 | 1317 | /* The initial "clone" message from client to server contains no |
| 1291 | 1318 | ** "gimme" cards. On that initial message, send the client an "igot" |
| 1292 | 1319 | ** card for every artifact currently in the repository. This will |
| 1293 | 1320 | ** cause the client to create phantoms for all artifacts, which will |
| | @@ -1637,21 +1664,21 @@ |
| 1637 | 1664 | ** file UUID DELTASRC SIZE \n CONTENT |
| 1638 | 1665 | ** |
| 1639 | 1666 | ** Receive a file transmitted from the server. |
| 1640 | 1667 | */ |
| 1641 | 1668 | if( blob_eq(&xfer.aToken[0],"file") ){ |
| 1642 | | - xfer_accept_file(&xfer, (syncFlags & SYNC_CLONE)!=0); |
| 1669 | + xfer_accept_file(&xfer, (syncFlags & SYNC_CLONE)!=0, 0, 0); |
| 1643 | 1670 | nArtifactRcvd++; |
| 1644 | 1671 | }else |
| 1645 | 1672 | |
| 1646 | 1673 | /* cfile UUID USIZE CSIZE \n CONTENT |
| 1647 | 1674 | ** cfile UUID DELTASRC USIZE CSIZE \n CONTENT |
| 1648 | 1675 | ** |
| 1649 | 1676 | ** Receive a compressed file transmitted from the server. |
| 1650 | 1677 | */ |
| 1651 | 1678 | if( blob_eq(&xfer.aToken[0],"cfile") ){ |
| 1652 | | - xfer_accept_compressed_file(&xfer); |
| 1679 | + xfer_accept_compressed_file(&xfer, 0, 0); |
| 1653 | 1680 | nArtifactRcvd++; |
| 1654 | 1681 | }else |
| 1655 | 1682 | |
| 1656 | 1683 | /* gimme UUID |
| 1657 | 1684 | ** |
| 1658 | 1685 | |