Fossil SCM

First attempt at transfering SYNCLOG data over the wire.

drh 2021-12-20 09:53 synclog
Commit d58eebb77f05255272856765fd57fee57098aed283c87807ccb4a68d12bea4ad
3 files changed +2 -2 +12 -31 +133 -5
+2 -2
--- src/export.c
+++ src/export.c
@@ -1700,11 +1700,11 @@
17001700
fossil_system(zRepack);
17011701
}
17021702
17031703
/* Record this export into the sync log */
17041704
zMirrorAbs = file_canonical_name_dup(zMirror);
1705
- sync_log_entry(SYNC_PUSH, zMirrorAbs, "git", 0);
1705
+ sync_log_entry("this", zMirrorAbs, 0, "git");
17061706
fossil_free(zMirrorAbs);
17071707
17081708
/* Optionally do a "git push" */
17091709
zPushUrl = db_text(0, "SELECT value FROM mconfig WHERE key='autopush'");
17101710
if( zPushUrl ){
@@ -1725,11 +1725,11 @@
17251725
}else if( db_is_writeable("repository") ){
17261726
db_unprotect(PROTECT_CONFIG);
17271727
db_multi_exec("REPLACE INTO config(name,value,mtime)"
17281728
"VALUES('gitpush:%q',1,now())", zPushUrl);
17291729
db_protect_pop();
1730
- sync_log_entry(SYNC_PUSH, zPushUrl, "git-push", 0);
1730
+ sync_log_entry("this", zPushUrl, 0, "git-push");
17311731
}
17321732
fossil_free(zPushCmd);
17331733
}
17341734
}
17351735
17361736
--- src/export.c
+++ src/export.c
@@ -1700,11 +1700,11 @@
1700 fossil_system(zRepack);
1701 }
1702
1703 /* Record this export into the sync log */
1704 zMirrorAbs = file_canonical_name_dup(zMirror);
1705 sync_log_entry(SYNC_PUSH, zMirrorAbs, "git", 0);
1706 fossil_free(zMirrorAbs);
1707
1708 /* Optionally do a "git push" */
1709 zPushUrl = db_text(0, "SELECT value FROM mconfig WHERE key='autopush'");
1710 if( zPushUrl ){
@@ -1725,11 +1725,11 @@
1725 }else if( db_is_writeable("repository") ){
1726 db_unprotect(PROTECT_CONFIG);
1727 db_multi_exec("REPLACE INTO config(name,value,mtime)"
1728 "VALUES('gitpush:%q',1,now())", zPushUrl);
1729 db_protect_pop();
1730 sync_log_entry(SYNC_PUSH, zPushUrl, "git-push", 0);
1731 }
1732 fossil_free(zPushCmd);
1733 }
1734 }
1735
1736
--- src/export.c
+++ src/export.c
@@ -1700,11 +1700,11 @@
1700 fossil_system(zRepack);
1701 }
1702
1703 /* Record this export into the sync log */
1704 zMirrorAbs = file_canonical_name_dup(zMirror);
1705 sync_log_entry("this", zMirrorAbs, 0, "git");
1706 fossil_free(zMirrorAbs);
1707
1708 /* Optionally do a "git push" */
1709 zPushUrl = db_text(0, "SELECT value FROM mconfig WHERE key='autopush'");
1710 if( zPushUrl ){
@@ -1725,11 +1725,11 @@
1725 }else if( db_is_writeable("repository") ){
1726 db_unprotect(PROTECT_CONFIG);
1727 db_multi_exec("REPLACE INTO config(name,value,mtime)"
1728 "VALUES('gitpush:%q',1,now())", zPushUrl);
1729 db_protect_pop();
1730 sync_log_entry("this", zPushUrl, 0, "git-push");
1731 }
1732 fossil_free(zPushCmd);
1733 }
1734 }
1735
1736
+12 -31
--- src/sync.c
+++ src/sync.c
@@ -93,58 +93,39 @@
9393
fossil_free(azOther);
9494
return nErr;
9595
}
9696
9797
/*
98
-** Make a new entry, or update an existing entry, in the SYNCLOG table
99
-** for a push or pull from this repository to another server named zRemote.
98
+** Make a new entry, or update an existing entry, in the SYNCLOG table.
10099
**
101100
** For an ordinary push/pull, zType is NULL. But it may also be a string
102101
** describing non-standard operations. For example zType might be "git"
103102
** when doing a "fossil git export", or zType might be "import" when doing
104103
** a "fossil pull --from-parent-project".
105
-**
106
-** For this routine, the sfrom value is always 'self'. The sto value is
107
-** the zRemote parameter. sto+sfrom form the primary key. If an entry
108
-** already exists with the same primary key, then the spull or spush times
109
-** are updated (or both).
110104
*/
111105
void sync_log_entry(
112
- int syncFlags, /* Indicates whether a PUSH or PULL or both */
113
- const char *zRemote, /* Server with which we push or pull */
114
- const char *zType, /* Type of sync. NULL for normal */
115
- i64 iTime /* Seconds since 1970, or 0 for "now" */
106
+ const char *zFrom, /* Content comes from this machine */
107
+ const char *zTo, /* Content goes to this machine */
108
+ i64 iTime, /* Transfer time, or 0 for "now" */
109
+ const char *zType /* Type of sync. NULL for normal */
116110
){
117
- Stmt s;
118111
schema_synclog();
119112
if( iTime<=0 ){
120
- db_prepare(&s,
113
+ db_multi_exec(
121114
"INSERT INTO repository.synclog(sfrom,sto,stime,stype)"
122
- " VALUES(:sfrom,:sto,unixepoch(),%Q)"
115
+ " VALUES(%Q,%Q,unixepoch(),%Q)"
123116
" ON CONFLICT DO UPDATE SET stime=unixepoch()",
124
- zType
117
+ zFrom, zTo, zType
125118
);
126119
}else{
127
- db_prepare(&s,
120
+ db_multi_exec(
128121
"INSERT INTO repository.synclog(sfrom,sto,stime,stype)"
129
- " VALUES(:sfrom,:sto,%lld,%Q)"
122
+ " VALUES(%Q,%Q,%lld,%Q)"
130123
" ON CONFLICT DO UPDATE SET stime=%lld WHERE stime<%lld",
131
- iTime, zType, iTime, iTime
124
+ zFrom, zTo, iTime, zType, iTime, iTime
132125
);
133126
}
134
- if( syncFlags & (SYNC_PULL|SYNC_CLONE) ){
135
- db_bind_text(&s, ":sfrom", zRemote);
136
- db_bind_text(&s, ":sto", "this");
137
- db_step(&s);
138
- db_reset(&s);
139
- }
140
- if( syncFlags & (SYNC_PUSH) ){
141
- db_bind_text(&s, ":sfrom", "this");
142
- db_bind_text(&s, ":sto", zRemote);
143
- db_step(&s);
144
- }
145
- db_finalize(&s);
146127
}
147128
148129
149130
/*
150131
** If the repository is configured for autosyncing, then do an
@@ -759,8 +740,8 @@
759740
}
760741
}
761742
db_unprotect(PROTECT_ALL);
762743
db_multi_exec("VACUUM repository INTO %Q", zDest);
763744
zFullName = file_canonical_name_dup(zDest);
764
- sync_log_entry(SYNC_PUSH, zFullName, "backup", 0);
745
+ sync_log_entry("this", zFullName, 0, "backup");
765746
fossil_free(zFullName);
766747
}
767748
--- src/sync.c
+++ src/sync.c
@@ -93,58 +93,39 @@
93 fossil_free(azOther);
94 return nErr;
95 }
96
97 /*
98 ** Make a new entry, or update an existing entry, in the SYNCLOG table
99 ** for a push or pull from this repository to another server named zRemote.
100 **
101 ** For an ordinary push/pull, zType is NULL. But it may also be a string
102 ** describing non-standard operations. For example zType might be "git"
103 ** when doing a "fossil git export", or zType might be "import" when doing
104 ** a "fossil pull --from-parent-project".
105 **
106 ** For this routine, the sfrom value is always 'self'. The sto value is
107 ** the zRemote parameter. sto+sfrom form the primary key. If an entry
108 ** already exists with the same primary key, then the spull or spush times
109 ** are updated (or both).
110 */
111 void sync_log_entry(
112 int syncFlags, /* Indicates whether a PUSH or PULL or both */
113 const char *zRemote, /* Server with which we push or pull */
114 const char *zType, /* Type of sync. NULL for normal */
115 i64 iTime /* Seconds since 1970, or 0 for "now" */
116 ){
117 Stmt s;
118 schema_synclog();
119 if( iTime<=0 ){
120 db_prepare(&s,
121 "INSERT INTO repository.synclog(sfrom,sto,stime,stype)"
122 " VALUES(:sfrom,:sto,unixepoch(),%Q)"
123 " ON CONFLICT DO UPDATE SET stime=unixepoch()",
124 zType
125 );
126 }else{
127 db_prepare(&s,
128 "INSERT INTO repository.synclog(sfrom,sto,stime,stype)"
129 " VALUES(:sfrom,:sto,%lld,%Q)"
130 " ON CONFLICT DO UPDATE SET stime=%lld WHERE stime<%lld",
131 iTime, zType, iTime, iTime
132 );
133 }
134 if( syncFlags & (SYNC_PULL|SYNC_CLONE) ){
135 db_bind_text(&s, ":sfrom", zRemote);
136 db_bind_text(&s, ":sto", "this");
137 db_step(&s);
138 db_reset(&s);
139 }
140 if( syncFlags & (SYNC_PUSH) ){
141 db_bind_text(&s, ":sfrom", "this");
142 db_bind_text(&s, ":sto", zRemote);
143 db_step(&s);
144 }
145 db_finalize(&s);
146 }
147
148
149 /*
150 ** If the repository is configured for autosyncing, then do an
@@ -759,8 +740,8 @@
759 }
760 }
761 db_unprotect(PROTECT_ALL);
762 db_multi_exec("VACUUM repository INTO %Q", zDest);
763 zFullName = file_canonical_name_dup(zDest);
764 sync_log_entry(SYNC_PUSH, zFullName, "backup", 0);
765 fossil_free(zFullName);
766 }
767
--- src/sync.c
+++ src/sync.c
@@ -93,58 +93,39 @@
93 fossil_free(azOther);
94 return nErr;
95 }
96
97 /*
98 ** Make a new entry, or update an existing entry, in the SYNCLOG table.
 
99 **
100 ** For an ordinary push/pull, zType is NULL. But it may also be a string
101 ** describing non-standard operations. For example zType might be "git"
102 ** when doing a "fossil git export", or zType might be "import" when doing
103 ** a "fossil pull --from-parent-project".
 
 
 
 
 
104 */
105 void sync_log_entry(
106 const char *zFrom, /* Content comes from this machine */
107 const char *zTo, /* Content goes to this machine */
108 i64 iTime, /* Transfer time, or 0 for "now" */
109 const char *zType /* Type of sync. NULL for normal */
110 ){
 
111 schema_synclog();
112 if( iTime<=0 ){
113 db_multi_exec(
114 "INSERT INTO repository.synclog(sfrom,sto,stime,stype)"
115 " VALUES(%Q,%Q,unixepoch(),%Q)"
116 " ON CONFLICT DO UPDATE SET stime=unixepoch()",
117 zFrom, zTo, zType
118 );
119 }else{
120 db_multi_exec(
121 "INSERT INTO repository.synclog(sfrom,sto,stime,stype)"
122 " VALUES(%Q,%Q,%lld,%Q)"
123 " ON CONFLICT DO UPDATE SET stime=%lld WHERE stime<%lld",
124 zFrom, zTo, iTime, zType, iTime, iTime
125 );
126 }
 
 
 
 
 
 
 
 
 
 
 
 
127 }
128
129
130 /*
131 ** If the repository is configured for autosyncing, then do an
@@ -759,8 +740,8 @@
740 }
741 }
742 db_unprotect(PROTECT_ALL);
743 db_multi_exec("VACUUM repository INTO %Q", zDest);
744 zFullName = file_canonical_name_dup(zDest);
745 sync_log_entry("this", zFullName, 0, "backup");
746 fossil_free(zFullName);
747 }
748
+133 -5
--- src/xfer.c
+++ src/xfer.c
@@ -1150,10 +1150,43 @@
11501150
** }
11511151
*/
11521152
int xfer_run_common_script(void){
11531153
return xfer_run_script(xfer_common_code(), 0, 0);
11541154
}
1155
+
1156
+/*
1157
+** The current line is a "pragma synclog". Accept this line into
1158
+** the SYNCLOG table, if appropriate.
1159
+**
1160
+** pragma synclog FROM TO MTIME ?TYPE?
1161
+**
1162
+** The name of the remote size is zRemote. The value of "this" for
1163
+** either the FROM or TO fields is converted into zRemote.
1164
+**
1165
+** If either FROM or TO is an alias for the current repository, then
1166
+** silently reject the entry.
1167
+*/
1168
+static void xfer_accept_synclog_pragma(
1169
+ Xfer *pXfer, /* Current line of xfer script */
1170
+ const char *zRemote /* The name of the remote repository */
1171
+){
1172
+ const char *zFrom = blob_str(&pXfer->aToken[2]);
1173
+ const char *zTo = blob_str(&pXfer->aToken[3]);
1174
+ i64 iTime = strtoll(blob_str(&pXfer->aToken[4]), 0, 0);
1175
+ const char *zType = pXfer->nToken>=5 ? blob_str(&pXfer->aToken[5]) : 0;
1176
+ if( strcmp(zFrom, "this")==0 ){
1177
+ zFrom = zRemote;
1178
+ }else if( db_exists("SELECT 1 FROM config WHERE name='baseurl:%q'",zFrom) ){
1179
+ iTime = 0;
1180
+ }
1181
+ if( strcmp(zTo, "this")==0 ){
1182
+ zTo = zRemote;
1183
+ }else if( db_exists("SELECT 1 FROM config WHERE name='baseurl:%q'",zTo) ){
1184
+ iTime = 0;
1185
+ }
1186
+ if( iTime>0 ) sync_log_entry(zFrom, zTo, iTime, zType);
1187
+}
11551188
11561189
/*
11571190
** If this variable is set, disable login checks. Used for debugging
11581191
** only.
11591192
*/
@@ -1187,10 +1220,11 @@
11871220
char *zUuidList = 0;
11881221
int nUuidList = 0;
11891222
char **pzUuidList = 0;
11901223
int *pnUuidList = 0;
11911224
int uvCatalogSent = 0;
1225
+ const char *zClientUrl = 0;
11921226
11931227
if( fossil_strcmp(PD("REQUEST_METHOD","POST"),"POST") ){
11941228
fossil_redirect_home();
11951229
}
11961230
g.zLogin = "anonymous";
@@ -1686,11 +1720,11 @@
16861720
db_protect_pop();
16871721
}
16881722
if( db_get_boolean("forbid-delta-manifests",0) ){
16891723
@ pragma avoid-delta-manifests
16901724
}
1691
- }
1725
+ }else
16921726
16931727
/* pragma ci-unlock CLIENT-ID
16941728
**
16951729
** Remove any locks previously held by CLIENT-ID. Clients send this
16961730
** pragma with their own ID whenever they know that they no longer
@@ -1706,10 +1740,61 @@
17061740
" WHERE name GLOB 'ci-lock-*'"
17071741
" AND json_extract(value,'$.clientid')=%Q",
17081742
blob_str(&xfer.aToken[2])
17091743
);
17101744
db_protect_pop();
1745
+ }else
1746
+
1747
+ /* pragma req-synclog ?CLIENT-URL?
1748
+ **
1749
+ ** Request synclog data. If the CLIENT-URL argument is provided,
1750
+ ** it will be the canonical URL for the client.
1751
+ */
1752
+ if( blob_eq(&xfer.aToken[1], "req-synclog") && g.perm.RdSLog ){
1753
+ Stmt qSynclog;
1754
+ if( xfer.nToken>=2 ){
1755
+ zClientUrl = blob_str(&xfer.aToken[2]);
1756
+ if( sqlite3_strlike("http%//localhost%", zClientUrl, 0)==0 ){
1757
+ zClientUrl = 0;
1758
+ }
1759
+ }
1760
+ db_prepare(&qSynclog,
1761
+ "SELECT sfrom, sto, unixepoch(stime), stype FROM synclog"
1762
+ );
1763
+ while( db_step(&qSynclog)==SQLITE_ROW ){
1764
+ const char *zFrom = db_column_text(&qSynclog,0);
1765
+ const char *zTo = db_column_text(&qSynclog,1);
1766
+ const char *zTime = db_column_text(&qSynclog,2);
1767
+ const char *zType = db_column_text(&qSynclog,3);
1768
+ if( zClientUrl ){
1769
+ if( strcmp(zFrom, zClientUrl)==0 ) continue;
1770
+ if( strcmp(zTo, zClientUrl)==0 ) continue;
1771
+ }
1772
+ if( zType!=0 && zType[0]!=0 ){
1773
+ @ pragma synclog %s(zFrom) %s(zTo) %s(zTime) %s(zType)
1774
+ }else{
1775
+ @ pragma synclog %s(zFrom) %s(zTo) %s(zTime)
1776
+ }
1777
+ }
1778
+ }else
1779
+
1780
+ /* pragma synclog FROM TO MTIME ?TYPE?
1781
+ **
1782
+ ** The client is uploading an entry from its SYNCLOG table. This
1783
+ ** will only be accepted if both:
1784
+ **
1785
+ ** (1) The client as WrSLog permission
1786
+ ** (2) A prior req-synclog pragma has identified the URL of the client
1787
+ **
1788
+ ** Insert the entry into the SYNC log if appropriate.
1789
+ */
1790
+ if( xfer.nToken>=4
1791
+ && blob_eq(&xfer.aToken[1], "synclog")
1792
+ && g.perm.WrSLog
1793
+ && zClientUrl!=0
1794
+ ){
1795
+ xfer_accept_synclog_pragma(&xfer, zClientUrl);
17111796
}
17121797
17131798
}else
17141799
17151800
/* Unknown message
@@ -2121,10 +2206,44 @@
21212206
blob_appendf(&send, "pragma ci-lock %s %s\n", zCkinLock, zClientId);
21222207
zCkinLock = 0;
21232208
}else if( zClientId ){
21242209
blob_appendf(&send, "pragma ci-unlock %s\n", zClientId);
21252210
}
2211
+
2212
+ /* Transfer SYNCLOG data on the first roundtrip, if appropriate */
2213
+ if( nCycle==0 ){
2214
+ const char *zSelfUrl = public_url();
2215
+ if( sqlite3_strlike("http%//localhost%", zSelfUrl, 0)==0 ){
2216
+ zSelfUrl = 0;
2217
+ }
2218
+ if( zSelfUrl==0 ){
2219
+ blob_appendf(&send,"pragma req-synclog\n");
2220
+ }else{
2221
+ blob_appendf(&send,"pragma req-synclog %s\n", zSelfUrl);
2222
+ if( syncFlags & SYNC_PUSH_SYNCLOG ){
2223
+ Stmt qSynclog;
2224
+ db_prepare(&qSynclog,
2225
+ "SELECT sfrom, sto, unixepoch(stime), stype FROM synclog"
2226
+ " WHERE sfrom!=%Q AND sto!=%Q",
2227
+ g.url.canonical, g.url.canonical
2228
+ );
2229
+ while( db_step(&qSynclog)==SQLITE_ROW ){
2230
+ const char *zFrom = db_column_text(&qSynclog,0);
2231
+ const char *zTo = db_column_text(&qSynclog,1);
2232
+ const char *zTime = db_column_text(&qSynclog,2);
2233
+ const char *zType = db_column_text(&qSynclog,3);
2234
+ if( zType!=0 && zType[0]!=0 ){
2235
+ blob_appendf(&send,"pragma synclog %s %s %s %s\n",
2236
+ zFrom, zTo, zTime, zType);
2237
+ }else{
2238
+ blob_appendf(&send,"pragma synclog %s %s %s\n",
2239
+ zFrom, zTo, zTime);
2240
+ }
2241
+ }
2242
+ }
2243
+ }
2244
+ }
21262245
21272246
/* Append randomness to the end of the uplink message. This makes all
21282247
** messages unique so that that the login-card nonce will always
21292248
** be unique.
21302249
*/
@@ -2524,19 +2643,19 @@
25242643
xfer.remoteDate = atoi(blob_str(&xfer.aToken[3]));
25252644
xfer.remoteTime = atoi(blob_str(&xfer.aToken[4]));
25262645
}
25272646
}
25282647
2529
- /* pragma synclog FROM TO MTIME TYPE
2648
+ /* pragma synclog FROM TO MTIME ?TYPE?
25302649
**
25312650
** The server is downloading an entry from its SYNCLOG table. Merge
25322651
** this into the local SYNCLOG table if appropriate.
25332652
** is running. The DATE and TIME are a pure numeric ISO8601 time
25342653
** for the specific check-in of the client.
25352654
*/
2536
- if( xfer.nToken==5 && blob_eq(&xfer.aToken[1], "synclog") ){
2537
- /* TBD */
2655
+ if( xfer.nToken>=4 && blob_eq(&xfer.aToken[1], "synclog") ){
2656
+ xfer_accept_synclog_pragma(&xfer, g.url.canonical);
25382657
}
25392658
25402659
/* pragma uv-pull-only
25412660
** pragma uv-push-ok
25422661
**
@@ -2705,11 +2824,20 @@
27052824
db_timespan_name(-rSkew));
27062825
g.clockSkewSeen = 1;
27072826
}
27082827
27092828
if( nErr==0 ){
2710
- sync_log_entry(syncFlags, g.url.canonical, zAltPCode!=0 ? "import" : 0, 0);
2829
+ if( zAltPCode!=0 ){
2830
+ sync_log_entry(g.url.canonical, "this", 0, "import");
2831
+ }else{
2832
+ if( syncFlags & SYNC_PUSH ){
2833
+ sync_log_entry("this", g.url.canonical, 0, 0);
2834
+ }
2835
+ if( syncFlags & SYNC_PULL ){
2836
+ sync_log_entry(g.url.canonical, "this", 0, 0);
2837
+ }
2838
+ }
27112839
}
27122840
27132841
fossil_force_newline();
27142842
fossil_print(
27152843
"%s done, wire bytes sent: %lld received: %lld ip: %s\n",
27162844
--- src/xfer.c
+++ src/xfer.c
@@ -1150,10 +1150,43 @@
1150 ** }
1151 */
1152 int xfer_run_common_script(void){
1153 return xfer_run_script(xfer_common_code(), 0, 0);
1154 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1155
1156 /*
1157 ** If this variable is set, disable login checks. Used for debugging
1158 ** only.
1159 */
@@ -1187,10 +1220,11 @@
1187 char *zUuidList = 0;
1188 int nUuidList = 0;
1189 char **pzUuidList = 0;
1190 int *pnUuidList = 0;
1191 int uvCatalogSent = 0;
 
1192
1193 if( fossil_strcmp(PD("REQUEST_METHOD","POST"),"POST") ){
1194 fossil_redirect_home();
1195 }
1196 g.zLogin = "anonymous";
@@ -1686,11 +1720,11 @@
1686 db_protect_pop();
1687 }
1688 if( db_get_boolean("forbid-delta-manifests",0) ){
1689 @ pragma avoid-delta-manifests
1690 }
1691 }
1692
1693 /* pragma ci-unlock CLIENT-ID
1694 **
1695 ** Remove any locks previously held by CLIENT-ID. Clients send this
1696 ** pragma with their own ID whenever they know that they no longer
@@ -1706,10 +1740,61 @@
1706 " WHERE name GLOB 'ci-lock-*'"
1707 " AND json_extract(value,'$.clientid')=%Q",
1708 blob_str(&xfer.aToken[2])
1709 );
1710 db_protect_pop();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1711 }
1712
1713 }else
1714
1715 /* Unknown message
@@ -2121,10 +2206,44 @@
2121 blob_appendf(&send, "pragma ci-lock %s %s\n", zCkinLock, zClientId);
2122 zCkinLock = 0;
2123 }else if( zClientId ){
2124 blob_appendf(&send, "pragma ci-unlock %s\n", zClientId);
2125 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2126
2127 /* Append randomness to the end of the uplink message. This makes all
2128 ** messages unique so that that the login-card nonce will always
2129 ** be unique.
2130 */
@@ -2524,19 +2643,19 @@
2524 xfer.remoteDate = atoi(blob_str(&xfer.aToken[3]));
2525 xfer.remoteTime = atoi(blob_str(&xfer.aToken[4]));
2526 }
2527 }
2528
2529 /* pragma synclog FROM TO MTIME TYPE
2530 **
2531 ** The server is downloading an entry from its SYNCLOG table. Merge
2532 ** this into the local SYNCLOG table if appropriate.
2533 ** is running. The DATE and TIME are a pure numeric ISO8601 time
2534 ** for the specific check-in of the client.
2535 */
2536 if( xfer.nToken==5 && blob_eq(&xfer.aToken[1], "synclog") ){
2537 /* TBD */
2538 }
2539
2540 /* pragma uv-pull-only
2541 ** pragma uv-push-ok
2542 **
@@ -2705,11 +2824,20 @@
2705 db_timespan_name(-rSkew));
2706 g.clockSkewSeen = 1;
2707 }
2708
2709 if( nErr==0 ){
2710 sync_log_entry(syncFlags, g.url.canonical, zAltPCode!=0 ? "import" : 0, 0);
 
 
 
 
 
 
 
 
 
2711 }
2712
2713 fossil_force_newline();
2714 fossil_print(
2715 "%s done, wire bytes sent: %lld received: %lld ip: %s\n",
2716
--- src/xfer.c
+++ src/xfer.c
@@ -1150,10 +1150,43 @@
1150 ** }
1151 */
1152 int xfer_run_common_script(void){
1153 return xfer_run_script(xfer_common_code(), 0, 0);
1154 }
1155
1156 /*
1157 ** The current line is a "pragma synclog". Accept this line into
1158 ** the SYNCLOG table, if appropriate.
1159 **
1160 ** pragma synclog FROM TO MTIME ?TYPE?
1161 **
1162 ** The name of the remote size is zRemote. The value of "this" for
1163 ** either the FROM or TO fields is converted into zRemote.
1164 **
1165 ** If either FROM or TO is an alias for the current repository, then
1166 ** silently reject the entry.
1167 */
1168 static void xfer_accept_synclog_pragma(
1169 Xfer *pXfer, /* Current line of xfer script */
1170 const char *zRemote /* The name of the remote repository */
1171 ){
1172 const char *zFrom = blob_str(&pXfer->aToken[2]);
1173 const char *zTo = blob_str(&pXfer->aToken[3]);
1174 i64 iTime = strtoll(blob_str(&pXfer->aToken[4]), 0, 0);
1175 const char *zType = pXfer->nToken>=5 ? blob_str(&pXfer->aToken[5]) : 0;
1176 if( strcmp(zFrom, "this")==0 ){
1177 zFrom = zRemote;
1178 }else if( db_exists("SELECT 1 FROM config WHERE name='baseurl:%q'",zFrom) ){
1179 iTime = 0;
1180 }
1181 if( strcmp(zTo, "this")==0 ){
1182 zTo = zRemote;
1183 }else if( db_exists("SELECT 1 FROM config WHERE name='baseurl:%q'",zTo) ){
1184 iTime = 0;
1185 }
1186 if( iTime>0 ) sync_log_entry(zFrom, zTo, iTime, zType);
1187 }
1188
1189 /*
1190 ** If this variable is set, disable login checks. Used for debugging
1191 ** only.
1192 */
@@ -1187,10 +1220,11 @@
1220 char *zUuidList = 0;
1221 int nUuidList = 0;
1222 char **pzUuidList = 0;
1223 int *pnUuidList = 0;
1224 int uvCatalogSent = 0;
1225 const char *zClientUrl = 0;
1226
1227 if( fossil_strcmp(PD("REQUEST_METHOD","POST"),"POST") ){
1228 fossil_redirect_home();
1229 }
1230 g.zLogin = "anonymous";
@@ -1686,11 +1720,11 @@
1720 db_protect_pop();
1721 }
1722 if( db_get_boolean("forbid-delta-manifests",0) ){
1723 @ pragma avoid-delta-manifests
1724 }
1725 }else
1726
1727 /* pragma ci-unlock CLIENT-ID
1728 **
1729 ** Remove any locks previously held by CLIENT-ID. Clients send this
1730 ** pragma with their own ID whenever they know that they no longer
@@ -1706,10 +1740,61 @@
1740 " WHERE name GLOB 'ci-lock-*'"
1741 " AND json_extract(value,'$.clientid')=%Q",
1742 blob_str(&xfer.aToken[2])
1743 );
1744 db_protect_pop();
1745 }else
1746
1747 /* pragma req-synclog ?CLIENT-URL?
1748 **
1749 ** Request synclog data. If the CLIENT-URL argument is provided,
1750 ** it will be the canonical URL for the client.
1751 */
1752 if( blob_eq(&xfer.aToken[1], "req-synclog") && g.perm.RdSLog ){
1753 Stmt qSynclog;
1754 if( xfer.nToken>=2 ){
1755 zClientUrl = blob_str(&xfer.aToken[2]);
1756 if( sqlite3_strlike("http%//localhost%", zClientUrl, 0)==0 ){
1757 zClientUrl = 0;
1758 }
1759 }
1760 db_prepare(&qSynclog,
1761 "SELECT sfrom, sto, unixepoch(stime), stype FROM synclog"
1762 );
1763 while( db_step(&qSynclog)==SQLITE_ROW ){
1764 const char *zFrom = db_column_text(&qSynclog,0);
1765 const char *zTo = db_column_text(&qSynclog,1);
1766 const char *zTime = db_column_text(&qSynclog,2);
1767 const char *zType = db_column_text(&qSynclog,3);
1768 if( zClientUrl ){
1769 if( strcmp(zFrom, zClientUrl)==0 ) continue;
1770 if( strcmp(zTo, zClientUrl)==0 ) continue;
1771 }
1772 if( zType!=0 && zType[0]!=0 ){
1773 @ pragma synclog %s(zFrom) %s(zTo) %s(zTime) %s(zType)
1774 }else{
1775 @ pragma synclog %s(zFrom) %s(zTo) %s(zTime)
1776 }
1777 }
1778 }else
1779
1780 /* pragma synclog FROM TO MTIME ?TYPE?
1781 **
1782 ** The client is uploading an entry from its SYNCLOG table. This
1783 ** will only be accepted if both:
1784 **
1785 ** (1) The client as WrSLog permission
1786 ** (2) A prior req-synclog pragma has identified the URL of the client
1787 **
1788 ** Insert the entry into the SYNC log if appropriate.
1789 */
1790 if( xfer.nToken>=4
1791 && blob_eq(&xfer.aToken[1], "synclog")
1792 && g.perm.WrSLog
1793 && zClientUrl!=0
1794 ){
1795 xfer_accept_synclog_pragma(&xfer, zClientUrl);
1796 }
1797
1798 }else
1799
1800 /* Unknown message
@@ -2121,10 +2206,44 @@
2206 blob_appendf(&send, "pragma ci-lock %s %s\n", zCkinLock, zClientId);
2207 zCkinLock = 0;
2208 }else if( zClientId ){
2209 blob_appendf(&send, "pragma ci-unlock %s\n", zClientId);
2210 }
2211
2212 /* Transfer SYNCLOG data on the first roundtrip, if appropriate */
2213 if( nCycle==0 ){
2214 const char *zSelfUrl = public_url();
2215 if( sqlite3_strlike("http%//localhost%", zSelfUrl, 0)==0 ){
2216 zSelfUrl = 0;
2217 }
2218 if( zSelfUrl==0 ){
2219 blob_appendf(&send,"pragma req-synclog\n");
2220 }else{
2221 blob_appendf(&send,"pragma req-synclog %s\n", zSelfUrl);
2222 if( syncFlags & SYNC_PUSH_SYNCLOG ){
2223 Stmt qSynclog;
2224 db_prepare(&qSynclog,
2225 "SELECT sfrom, sto, unixepoch(stime), stype FROM synclog"
2226 " WHERE sfrom!=%Q AND sto!=%Q",
2227 g.url.canonical, g.url.canonical
2228 );
2229 while( db_step(&qSynclog)==SQLITE_ROW ){
2230 const char *zFrom = db_column_text(&qSynclog,0);
2231 const char *zTo = db_column_text(&qSynclog,1);
2232 const char *zTime = db_column_text(&qSynclog,2);
2233 const char *zType = db_column_text(&qSynclog,3);
2234 if( zType!=0 && zType[0]!=0 ){
2235 blob_appendf(&send,"pragma synclog %s %s %s %s\n",
2236 zFrom, zTo, zTime, zType);
2237 }else{
2238 blob_appendf(&send,"pragma synclog %s %s %s\n",
2239 zFrom, zTo, zTime);
2240 }
2241 }
2242 }
2243 }
2244 }
2245
2246 /* Append randomness to the end of the uplink message. This makes all
2247 ** messages unique so that that the login-card nonce will always
2248 ** be unique.
2249 */
@@ -2524,19 +2643,19 @@
2643 xfer.remoteDate = atoi(blob_str(&xfer.aToken[3]));
2644 xfer.remoteTime = atoi(blob_str(&xfer.aToken[4]));
2645 }
2646 }
2647
2648 /* pragma synclog FROM TO MTIME ?TYPE?
2649 **
2650 ** The server is downloading an entry from its SYNCLOG table. Merge
2651 ** this into the local SYNCLOG table if appropriate.
2652 ** is running. The DATE and TIME are a pure numeric ISO8601 time
2653 ** for the specific check-in of the client.
2654 */
2655 if( xfer.nToken>=4 && blob_eq(&xfer.aToken[1], "synclog") ){
2656 xfer_accept_synclog_pragma(&xfer, g.url.canonical);
2657 }
2658
2659 /* pragma uv-pull-only
2660 ** pragma uv-push-ok
2661 **
@@ -2705,11 +2824,20 @@
2824 db_timespan_name(-rSkew));
2825 g.clockSkewSeen = 1;
2826 }
2827
2828 if( nErr==0 ){
2829 if( zAltPCode!=0 ){
2830 sync_log_entry(g.url.canonical, "this", 0, "import");
2831 }else{
2832 if( syncFlags & SYNC_PUSH ){
2833 sync_log_entry("this", g.url.canonical, 0, 0);
2834 }
2835 if( syncFlags & SYNC_PULL ){
2836 sync_log_entry(g.url.canonical, "this", 0, 0);
2837 }
2838 }
2839 }
2840
2841 fossil_force_newline();
2842 fossil_print(
2843 "%s done, wire bytes sent: %lld received: %lld ip: %s\n",
2844

Keyboard Shortcuts

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