Fossil SCM

More work on unversioned file sync.

drh 2016-08-09 15:29 unversioned-files
Commit a3dcfe759541d1f266643241d2300aca7c358c1e
3 files changed +33 -16 +54 -2 +78 -45
+33 -16
--- src/sync.c
+++ src/sync.c
@@ -113,11 +113,15 @@
113113
** This routine processes the command-line argument for push, pull,
114114
** and sync. If a command-line argument is given, that is the URL
115115
** of a server to sync against. If no argument is given, use the
116116
** most recently synced URL. Remember the current URL for next time.
117117
*/
118
-static void process_sync_args(unsigned *pConfigFlags, unsigned *pSyncFlags){
118
+static void process_sync_args(
119
+ unsigned *pConfigFlags, /* Write configuration flags here */
120
+ unsigned *pSyncFlags, /* Write sync flags here */
121
+ int uvOnly /* Special handling flags for UV sync */
122
+){
119123
const char *zUrl = 0;
120124
const char *zHttpAuth = 0;
121125
unsigned configSync = 0;
122126
unsigned urlFlags = URL_REMEMBER | URL_PROMPT_PW;
123127
int urlOptional = 0;
@@ -125,28 +129,30 @@
125129
urlOptional = 1;
126130
urlFlags = 0;
127131
}
128132
zHttpAuth = find_option("httpauth","B",1);
129133
if( find_option("once",0,0)!=0 ) urlFlags &= ~URL_REMEMBER;
130
- if( find_option("private",0,0)!=0 ){
131
- *pSyncFlags |= SYNC_PRIVATE;
132
- }
133
- if( find_option("verbose","v",0)!=0 ){
134
- *pSyncFlags |= SYNC_VERBOSE;
135
- }
136
- /* The --verily option to sync, push, and pull forces extra igot cards
137
- ** to be exchanged. This can overcome malfunctions in the sync protocol.
138
- */
139
- if( find_option("verily",0,0)!=0 ){
140
- *pSyncFlags |= SYNC_RESYNC;
134
+ if( !uvOnly ){
135
+ if( find_option("private",0,0)!=0 ){
136
+ *pSyncFlags |= SYNC_PRIVATE;
137
+ }
138
+ /* The --verily option to sync, push, and pull forces extra igot cards
139
+ ** to be exchanged. This can overcome malfunctions in the sync protocol.
140
+ */
141
+ if( find_option("verily",0,0)!=0 ){
142
+ *pSyncFlags |= SYNC_RESYNC;
143
+ }
141144
}
142145
if( find_option("uv",0,0)!=0 ){
143146
*pSyncFlags |= SYNC_UNVERSIONED;
144147
}
148
+ if( find_option("verbose","v",0)!=0 ){
149
+ *pSyncFlags |= SYNC_VERBOSE;
150
+ }
145151
url_proxy_options();
146152
clone_ssh_find_options();
147
- db_find_and_open_repository(0, 0);
153
+ if( !uvOnly ) db_find_and_open_repository(0, 0);
148154
db_open_config(0, 0);
149155
if( g.argc==2 ){
150156
if( db_get_boolean("auto-shun",1) ) configSync = CONFIGSET_SHUN;
151157
}else if( g.argc==3 ){
152158
zUrl = g.argv[2];
@@ -207,11 +213,11 @@
207213
** See also: clone, config pull, push, remote-url, sync
208214
*/
209215
void pull_cmd(void){
210216
unsigned configFlags = 0;
211217
unsigned syncFlags = SYNC_PULL;
212
- process_sync_args(&configFlags, &syncFlags);
218
+ process_sync_args(&configFlags, &syncFlags, 0);
213219
214220
/* We should be done with options.. */
215221
verify_all_options();
216222
217223
client_sync(syncFlags, configFlags, 0);
@@ -249,11 +255,11 @@
249255
** See also: clone, config push, pull, remote-url, sync
250256
*/
251257
void push_cmd(void){
252258
unsigned configFlags = 0;
253259
unsigned syncFlags = SYNC_PUSH;
254
- process_sync_args(&configFlags, &syncFlags);
260
+ process_sync_args(&configFlags, &syncFlags, 0);
255261
256262
/* We should be done with options.. */
257263
verify_all_options();
258264
259265
if( db_get_boolean("dont-push",0) ){
@@ -294,11 +300,11 @@
294300
** See also: clone, pull, push, remote-url
295301
*/
296302
void sync_cmd(void){
297303
unsigned configFlags = 0;
298304
unsigned syncFlags = SYNC_PUSH|SYNC_PULL;
299
- process_sync_args(&configFlags, &syncFlags);
305
+ process_sync_args(&configFlags, &syncFlags, 0);
300306
301307
/* We should be done with options.. */
302308
verify_all_options();
303309
304310
if( db_get_boolean("dont-push",0) ) syncFlags &= ~SYNC_PUSH;
@@ -305,10 +311,21 @@
305311
client_sync(syncFlags, configFlags, 0);
306312
if( (syncFlags & SYNC_PUSH)==0 ){
307313
fossil_warning("pull only: the 'dont-push' option is set");
308314
}
309315
}
316
+
317
+/*
318
+** Handle the "fossil unversioned sync" command.
319
+*/
320
+void sync_unversioned(void){
321
+ unsigned configFlags = 0;
322
+ unsigned syncFlags = SYNC_UNVERSIONED;
323
+ process_sync_args(&configFlags, &syncFlags, 1);
324
+ verify_all_options();
325
+ client_sync(syncFlags, 0, 0);
326
+}
310327
311328
/*
312329
** COMMAND: remote-url
313330
**
314331
** Usage: %fossil remote-url ?URL|off?
315332
--- src/sync.c
+++ src/sync.c
@@ -113,11 +113,15 @@
113 ** This routine processes the command-line argument for push, pull,
114 ** and sync. If a command-line argument is given, that is the URL
115 ** of a server to sync against. If no argument is given, use the
116 ** most recently synced URL. Remember the current URL for next time.
117 */
118 static void process_sync_args(unsigned *pConfigFlags, unsigned *pSyncFlags){
 
 
 
 
119 const char *zUrl = 0;
120 const char *zHttpAuth = 0;
121 unsigned configSync = 0;
122 unsigned urlFlags = URL_REMEMBER | URL_PROMPT_PW;
123 int urlOptional = 0;
@@ -125,28 +129,30 @@
125 urlOptional = 1;
126 urlFlags = 0;
127 }
128 zHttpAuth = find_option("httpauth","B",1);
129 if( find_option("once",0,0)!=0 ) urlFlags &= ~URL_REMEMBER;
130 if( find_option("private",0,0)!=0 ){
131 *pSyncFlags |= SYNC_PRIVATE;
132 }
133 if( find_option("verbose","v",0)!=0 ){
134 *pSyncFlags |= SYNC_VERBOSE;
135 }
136 /* The --verily option to sync, push, and pull forces extra igot cards
137 ** to be exchanged. This can overcome malfunctions in the sync protocol.
138 */
139 if( find_option("verily",0,0)!=0 ){
140 *pSyncFlags |= SYNC_RESYNC;
141 }
142 if( find_option("uv",0,0)!=0 ){
143 *pSyncFlags |= SYNC_UNVERSIONED;
144 }
 
 
 
145 url_proxy_options();
146 clone_ssh_find_options();
147 db_find_and_open_repository(0, 0);
148 db_open_config(0, 0);
149 if( g.argc==2 ){
150 if( db_get_boolean("auto-shun",1) ) configSync = CONFIGSET_SHUN;
151 }else if( g.argc==3 ){
152 zUrl = g.argv[2];
@@ -207,11 +213,11 @@
207 ** See also: clone, config pull, push, remote-url, sync
208 */
209 void pull_cmd(void){
210 unsigned configFlags = 0;
211 unsigned syncFlags = SYNC_PULL;
212 process_sync_args(&configFlags, &syncFlags);
213
214 /* We should be done with options.. */
215 verify_all_options();
216
217 client_sync(syncFlags, configFlags, 0);
@@ -249,11 +255,11 @@
249 ** See also: clone, config push, pull, remote-url, sync
250 */
251 void push_cmd(void){
252 unsigned configFlags = 0;
253 unsigned syncFlags = SYNC_PUSH;
254 process_sync_args(&configFlags, &syncFlags);
255
256 /* We should be done with options.. */
257 verify_all_options();
258
259 if( db_get_boolean("dont-push",0) ){
@@ -294,11 +300,11 @@
294 ** See also: clone, pull, push, remote-url
295 */
296 void sync_cmd(void){
297 unsigned configFlags = 0;
298 unsigned syncFlags = SYNC_PUSH|SYNC_PULL;
299 process_sync_args(&configFlags, &syncFlags);
300
301 /* We should be done with options.. */
302 verify_all_options();
303
304 if( db_get_boolean("dont-push",0) ) syncFlags &= ~SYNC_PUSH;
@@ -305,10 +311,21 @@
305 client_sync(syncFlags, configFlags, 0);
306 if( (syncFlags & SYNC_PUSH)==0 ){
307 fossil_warning("pull only: the 'dont-push' option is set");
308 }
309 }
 
 
 
 
 
 
 
 
 
 
 
310
311 /*
312 ** COMMAND: remote-url
313 **
314 ** Usage: %fossil remote-url ?URL|off?
315
--- src/sync.c
+++ src/sync.c
@@ -113,11 +113,15 @@
113 ** This routine processes the command-line argument for push, pull,
114 ** and sync. If a command-line argument is given, that is the URL
115 ** of a server to sync against. If no argument is given, use the
116 ** most recently synced URL. Remember the current URL for next time.
117 */
118 static void process_sync_args(
119 unsigned *pConfigFlags, /* Write configuration flags here */
120 unsigned *pSyncFlags, /* Write sync flags here */
121 int uvOnly /* Special handling flags for UV sync */
122 ){
123 const char *zUrl = 0;
124 const char *zHttpAuth = 0;
125 unsigned configSync = 0;
126 unsigned urlFlags = URL_REMEMBER | URL_PROMPT_PW;
127 int urlOptional = 0;
@@ -125,28 +129,30 @@
129 urlOptional = 1;
130 urlFlags = 0;
131 }
132 zHttpAuth = find_option("httpauth","B",1);
133 if( find_option("once",0,0)!=0 ) urlFlags &= ~URL_REMEMBER;
134 if( !uvOnly ){
135 if( find_option("private",0,0)!=0 ){
136 *pSyncFlags |= SYNC_PRIVATE;
137 }
138 /* The --verily option to sync, push, and pull forces extra igot cards
139 ** to be exchanged. This can overcome malfunctions in the sync protocol.
140 */
141 if( find_option("verily",0,0)!=0 ){
142 *pSyncFlags |= SYNC_RESYNC;
143 }
 
144 }
145 if( find_option("uv",0,0)!=0 ){
146 *pSyncFlags |= SYNC_UNVERSIONED;
147 }
148 if( find_option("verbose","v",0)!=0 ){
149 *pSyncFlags |= SYNC_VERBOSE;
150 }
151 url_proxy_options();
152 clone_ssh_find_options();
153 if( !uvOnly ) db_find_and_open_repository(0, 0);
154 db_open_config(0, 0);
155 if( g.argc==2 ){
156 if( db_get_boolean("auto-shun",1) ) configSync = CONFIGSET_SHUN;
157 }else if( g.argc==3 ){
158 zUrl = g.argv[2];
@@ -207,11 +213,11 @@
213 ** See also: clone, config pull, push, remote-url, sync
214 */
215 void pull_cmd(void){
216 unsigned configFlags = 0;
217 unsigned syncFlags = SYNC_PULL;
218 process_sync_args(&configFlags, &syncFlags, 0);
219
220 /* We should be done with options.. */
221 verify_all_options();
222
223 client_sync(syncFlags, configFlags, 0);
@@ -249,11 +255,11 @@
255 ** See also: clone, config push, pull, remote-url, sync
256 */
257 void push_cmd(void){
258 unsigned configFlags = 0;
259 unsigned syncFlags = SYNC_PUSH;
260 process_sync_args(&configFlags, &syncFlags, 0);
261
262 /* We should be done with options.. */
263 verify_all_options();
264
265 if( db_get_boolean("dont-push",0) ){
@@ -294,11 +300,11 @@
300 ** See also: clone, pull, push, remote-url
301 */
302 void sync_cmd(void){
303 unsigned configFlags = 0;
304 unsigned syncFlags = SYNC_PUSH|SYNC_PULL;
305 process_sync_args(&configFlags, &syncFlags, 0);
306
307 /* We should be done with options.. */
308 verify_all_options();
309
310 if( db_get_boolean("dont-push",0) ) syncFlags &= ~SYNC_PUSH;
@@ -305,10 +311,21 @@
311 client_sync(syncFlags, configFlags, 0);
312 if( (syncFlags & SYNC_PUSH)==0 ){
313 fossil_warning("pull only: the 'dont-push' option is set");
314 }
315 }
316
317 /*
318 ** Handle the "fossil unversioned sync" command.
319 */
320 void sync_unversioned(void){
321 unsigned configFlags = 0;
322 unsigned syncFlags = SYNC_UNVERSIONED;
323 process_sync_args(&configFlags, &syncFlags, 1);
324 verify_all_options();
325 client_sync(syncFlags, 0, 0);
326 }
327
328 /*
329 ** COMMAND: remote-url
330 **
331 ** Usage: %fossil remote-url ?URL|off?
332
--- src/unversioned.c
+++ src/unversioned.c
@@ -101,10 +101,44 @@
101101
rc = 0;
102102
}
103103
db_finalize(&q);
104104
return rc;
105105
}
106
+
107
+/*
108
+** Check the status of unversioned file zName. Return an integer status
109
+** code as follows:
110
+**
111
+** 0: zName does not exist in the unversioned table.
112
+** 1: zName exists and should be replaced by mtime/zHash.
113
+** 2: zName exists and is the same as zHash but has a older mtime
114
+** 3: zName exists and is identical to mtime/zHash in all respects.
115
+** 4: zName exists and is the same as zHash but has a newer mtime.
116
+** 5: zName exists and should override mtime/zHash.
117
+*/
118
+int unversioned_status(const char *zName, sqlite3_int64 mtime, const char *zHash){
119
+ int iStatus = 0;
120
+ Stmt q;
121
+ db_prepare(&q, "SELECT mtime, hash FROM unversioned WHERE name=%Q", zName);
122
+ if( db_step(&q)==SQLITE_ROW ){
123
+ const char *zLocalHash = db_column_text(&q, 1);
124
+ int hashCmp;
125
+ sqlite3_int64 iLocalMtime = db_column_int64(&q, 0);
126
+ int mtimeCmp = iLocalMtime<mtime ? -1 : (iLocalMtime==mtime ? 0 : +1);
127
+ if( zLocalHash==0 ) zLocalHash = "-";
128
+ hashCmp = strcmp(zLocalHash, zHash);
129
+ if( hashCmp==0 ){
130
+ iStatus = 3 + mtimeCmp;
131
+ }else if( mtimeCmp<0 || (mtimeCmp==0 && hashCmp<0) ){
132
+ iStatus = 1;
133
+ }else{
134
+ iStatus = 5;
135
+ }
136
+ }
137
+ db_finalize(&q);
138
+ return iStatus;
139
+}
106140
107141
/*
108142
** COMMAND: unversioned
109143
**
110144
** Usage: %fossil unversioned SUBCOMMAND ARGS...
@@ -138,10 +172,12 @@
138172
**
139173
** sync ?URL? Synchronize the state of all unversioned files with
140174
** the remote repository URL. The most recent version of
141175
** each file is propagate to all repositories and all
142176
** prior versions are permanently forgotten.
177
+**
178
+** touch FILE ... Update the TIMESTAMP on all of the listed files
143179
**
144180
** Options:
145181
**
146182
** --mtime TIMESTAMP Use TIMESTAMP instead of "now" for "add" and "rm".
147183
*/
@@ -271,11 +307,11 @@
271307
zNoContent
272308
);
273309
}
274310
}
275311
db_finalize(&q);
276
- }else if( memcmp(zCmd, "revert", nCmd)==0 || memcmp(zCmd,"sync",nCmd)==0 ){
312
+ }else if( memcmp(zCmd, "revert", nCmd)==0 ){
277313
fossil_fatal("not yet implemented...");
278314
}else if( memcmp(zCmd, "rm", nCmd)==0 ){
279315
int i;
280316
verify_all_options();
281317
db_begin_transaction();
@@ -286,9 +322,25 @@
286322
mtime, g.argv[i]
287323
);
288324
}
289325
db_unset("uv-hash", 0);
290326
db_end_transaction(0);
327
+ }else if( memcmp(zCmd,"sync",nCmd)==0 ){
328
+ g.argv[1] = "sync";
329
+ g.argv[2] = "--uv";
330
+ sync_unversioned();
331
+ }else if( memcmp(zCmd, "touch", nCmd)==0 ){
332
+ int i;
333
+ verify_all_options();
334
+ db_begin_transaction();
335
+ for(i=3; i<g.argc; i++){
336
+ db_multi_exec(
337
+ "UPDATE unversioned SET mtime=%lld WHERE name=%Q",
338
+ mtime, g.argv[i]
339
+ );
340
+ }
341
+ db_unset("uv-hash", 0);
342
+ db_end_transaction(0);
291343
}else{
292
- usage("add|cat|export|ls|revert|rm|sync");
344
+ usage("add|cat|export|ls|revert|rm|sync|touch");
293345
}
294346
}
295347
--- src/unversioned.c
+++ src/unversioned.c
@@ -101,10 +101,44 @@
101 rc = 0;
102 }
103 db_finalize(&q);
104 return rc;
105 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
107 /*
108 ** COMMAND: unversioned
109 **
110 ** Usage: %fossil unversioned SUBCOMMAND ARGS...
@@ -138,10 +172,12 @@
138 **
139 ** sync ?URL? Synchronize the state of all unversioned files with
140 ** the remote repository URL. The most recent version of
141 ** each file is propagate to all repositories and all
142 ** prior versions are permanently forgotten.
 
 
143 **
144 ** Options:
145 **
146 ** --mtime TIMESTAMP Use TIMESTAMP instead of "now" for "add" and "rm".
147 */
@@ -271,11 +307,11 @@
271 zNoContent
272 );
273 }
274 }
275 db_finalize(&q);
276 }else if( memcmp(zCmd, "revert", nCmd)==0 || memcmp(zCmd,"sync",nCmd)==0 ){
277 fossil_fatal("not yet implemented...");
278 }else if( memcmp(zCmd, "rm", nCmd)==0 ){
279 int i;
280 verify_all_options();
281 db_begin_transaction();
@@ -286,9 +322,25 @@
286 mtime, g.argv[i]
287 );
288 }
289 db_unset("uv-hash", 0);
290 db_end_transaction(0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
291 }else{
292 usage("add|cat|export|ls|revert|rm|sync");
293 }
294 }
295
--- src/unversioned.c
+++ src/unversioned.c
@@ -101,10 +101,44 @@
101 rc = 0;
102 }
103 db_finalize(&q);
104 return rc;
105 }
106
107 /*
108 ** Check the status of unversioned file zName. Return an integer status
109 ** code as follows:
110 **
111 ** 0: zName does not exist in the unversioned table.
112 ** 1: zName exists and should be replaced by mtime/zHash.
113 ** 2: zName exists and is the same as zHash but has a older mtime
114 ** 3: zName exists and is identical to mtime/zHash in all respects.
115 ** 4: zName exists and is the same as zHash but has a newer mtime.
116 ** 5: zName exists and should override mtime/zHash.
117 */
118 int unversioned_status(const char *zName, sqlite3_int64 mtime, const char *zHash){
119 int iStatus = 0;
120 Stmt q;
121 db_prepare(&q, "SELECT mtime, hash FROM unversioned WHERE name=%Q", zName);
122 if( db_step(&q)==SQLITE_ROW ){
123 const char *zLocalHash = db_column_text(&q, 1);
124 int hashCmp;
125 sqlite3_int64 iLocalMtime = db_column_int64(&q, 0);
126 int mtimeCmp = iLocalMtime<mtime ? -1 : (iLocalMtime==mtime ? 0 : +1);
127 if( zLocalHash==0 ) zLocalHash = "-";
128 hashCmp = strcmp(zLocalHash, zHash);
129 if( hashCmp==0 ){
130 iStatus = 3 + mtimeCmp;
131 }else if( mtimeCmp<0 || (mtimeCmp==0 && hashCmp<0) ){
132 iStatus = 1;
133 }else{
134 iStatus = 5;
135 }
136 }
137 db_finalize(&q);
138 return iStatus;
139 }
140
141 /*
142 ** COMMAND: unversioned
143 **
144 ** Usage: %fossil unversioned SUBCOMMAND ARGS...
@@ -138,10 +172,12 @@
172 **
173 ** sync ?URL? Synchronize the state of all unversioned files with
174 ** the remote repository URL. The most recent version of
175 ** each file is propagate to all repositories and all
176 ** prior versions are permanently forgotten.
177 **
178 ** touch FILE ... Update the TIMESTAMP on all of the listed files
179 **
180 ** Options:
181 **
182 ** --mtime TIMESTAMP Use TIMESTAMP instead of "now" for "add" and "rm".
183 */
@@ -271,11 +307,11 @@
307 zNoContent
308 );
309 }
310 }
311 db_finalize(&q);
312 }else if( memcmp(zCmd, "revert", nCmd)==0 ){
313 fossil_fatal("not yet implemented...");
314 }else if( memcmp(zCmd, "rm", nCmd)==0 ){
315 int i;
316 verify_all_options();
317 db_begin_transaction();
@@ -286,9 +322,25 @@
322 mtime, g.argv[i]
323 );
324 }
325 db_unset("uv-hash", 0);
326 db_end_transaction(0);
327 }else if( memcmp(zCmd,"sync",nCmd)==0 ){
328 g.argv[1] = "sync";
329 g.argv[2] = "--uv";
330 sync_unversioned();
331 }else if( memcmp(zCmd, "touch", nCmd)==0 ){
332 int i;
333 verify_all_options();
334 db_begin_transaction();
335 for(i=3; i<g.argc; i++){
336 db_multi_exec(
337 "UPDATE unversioned SET mtime=%lld WHERE name=%Q",
338 mtime, g.argv[i]
339 );
340 }
341 db_unset("uv-hash", 0);
342 db_end_transaction(0);
343 }else{
344 usage("add|cat|export|ls|revert|rm|sync|touch");
345 }
346 }
347
+78 -45
--- src/xfer.c
+++ src/xfer.c
@@ -294,34 +294,37 @@
294294
**
295295
** uvfile NAME MTIME HASH SIZE FLAGS
296296
** uvfile NAME MTIME HASH SIZE FLAGS \n CONTENT
297297
**
298298
** If the 0x0001 bit of FLAGS is set, that means the file has been
299
-** deleted, SIZE is zero, the HASH is "0", and the "\n CONTENT" is omitted.
299
+** deleted, SIZE is zero, the HASH is "-", and the "\n CONTENT" is omitted.
300300
**
301301
** SIZE is the number of bytes of CONTENT. The CONTENT is uncompressed.
302302
** HASH is the SHA1 hash of CONTENT.
303303
**
304
-** If the 0x0004 bit of FLAGS is set, that means the CONTENT size
305
-** is too big to transmit and so the "\n CONTENT" is omitted.
304
+** If the 0x0004 bit of FLAGS is set, that means the CONTENT is omitted.
305
+** The sender might have omitted the content because it is too big to
306
+** transmit, or because it is unchanged and this record exists purely
307
+** to update the MTIME.
306308
*/
307309
static void xfer_accept_unversioned_file(Xfer *pXfer, int isWriter){
308310
sqlite3_int64 mtime; /* The MTIME */
309311
Blob *pHash; /* The HASH value */
310312
int sz; /* The SIZE */
311313
int flags; /* The FLAGS */
312314
Blob content; /* The CONTENT */
313315
Blob hash; /* Hash computed from CONTENT to compare with HASH */
314316
Stmt q; /* SQL statements for comparison and insert */
315
- int isDelete; /* HASH is "0" indicating this is a delete operation */
317
+ int isDelete; /* HASH is "-" indicating this is a delete operation */
316318
int nullContent; /* True of CONTENT is NULL */
319
+ int iStatus; /* Result from unversioned_status() */
317320
318321
pHash = &pXfer->aToken[3];
319322
if( pXfer->nToken==5
320323
|| !blob_is_filename(&pXfer->aToken[1])
321324
|| !blob_is_int64(&pXfer->aToken[2], &mtime)
322
- || (blob_eq(pHash,"0")!=0 && !blob_is_uuid(pHash))
325
+ || (blob_eq(pHash,"-")!=0 && !blob_is_uuid(pHash))
323326
|| !blob_is_int(&pXfer->aToken[4], &sz)
324327
|| !blob_is_int(&pXfer->aToken[5], &flags)
325328
){
326329
blob_appendf(&pXfer->err, "malformed uvfile line");
327330
return;
@@ -345,37 +348,23 @@
345348
346349
/* Check to see if current content really should be overwritten. Ideally,
347350
** a uvfile card should never have been sent unless the overwrite should
348351
** occur. But do not trust the sender. Double-check.
349352
*/
350
- db_prepare(&q,
351
- "SELECT mtime, hash FROM unversioned WHERE name=%Q",
352
- blob_str(&pXfer->aToken[1])
353
- );
354
- if( db_step(&q)==SQLITE_ROW ){
355
- sqlite3_int64 xtime = db_column_int64(&q, 0);
356
- const char *xhash = db_column_text(&q, 1);
357
- if( xtime>mtime ){
358
- db_finalize(&q);
359
- goto end_accept_unversioned_file;
360
- }
361
- if( xhash==0 ) xhash = "0";
362
- if( xtime==mtime && strcmp(xhash, blob_str(pHash))>0 ){
363
- db_finalize(&q);
364
- goto end_accept_unversioned_file;
365
- }
366
- }
367
- db_finalize(&q);
353
+ iStatus = unversioned_status(blob_str(&pXfer->aToken[1]), mtime, blob_str(pHash));
354
+ if( iStatus>=3 ) goto end_accept_unversioned_file;
368355
369356
/* Store the content */
370
- isDelete = blob_eq(pHash, "0");
357
+ isDelete = blob_eq(pHash, "-");
371358
if( isDelete ){
372359
db_prepare(&q,
373360
"UPDATE unversioned"
374361
" SET rcvid=:rcvid, mtime=:mtime, hash=NULL, sz=0, content=NULL"
375362
" WHERE name=:name"
376363
);
364
+ }else if( iStatus==4 ){
365
+ db_prepare(&q, "UPDATE unversioned SET mtime=:mtime WHERE name=:name");
377366
}else{
378367
db_prepare(&q,
379368
"REPLACE INTO unversioned(name, rcvid, mtime, hash, sz, content)"
380369
" VALUES(:name,:rcvid,:mtime,:hash,:sz,:content)"
381370
);
@@ -389,10 +378,11 @@
389378
blob_compress(&content, &content);
390379
db_bind_blob(&q, ":content", &content);
391380
}
392381
db_step(&q);
393382
db_finalize(&q);
383
+ db_unset("uv-hash", 0);
394384
395385
end_accept_unversioned_file:
396386
blob_reset(&content);
397387
blob_reset(&hash);
398388
}
@@ -642,28 +632,39 @@
642632
/*
643633
** Send the unversioned file identified by zName by generating the
644634
** appropriate "uvfile" card.
645635
**
646636
** uvfile NAME MTIME HASH SIZE FLAGS \n CONTENT
637
+**
638
+** If the noContent flag is set, omit the CONTENT and set the 0x0004 flag in FLAGS.
647639
*/
648
-static void send_unversioned_file(Xfer *pXfer, const char *zName){
640
+static void send_unversioned_file(Xfer *pXfer, const char *zName, int noContent){
649641
Stmt q1;
650642
651
- db_static_prepare(&q1,
652
- "SELECT mtime, hash, encoding, content FROM unversioned WHERE name=%Q",
653
- zName
654
- );
643
+ if( noContent ){
644
+ db_static_prepare(&q1,
645
+ "SELECT mtime, hash, encoding, sz FROM unversioned WHERE name=%Q",
646
+ zName
647
+ );
648
+ }else{
649
+ db_static_prepare(&q1,
650
+ "SELECT mtime, hash, encoding, sz, content FROM unversioned WHERE name=%Q",
651
+ zName
652
+ );
653
+ }
655654
if( db_step(&q1)==SQLITE_ROW ){
656655
sqlite3_int64 mtime = db_column_int64(&q1, 0);
657656
const char *zHash = db_column_text(&q1, 1);
658657
blob_appendf(pXfer->pOut, "uvfile %s %lld", zName, mtime);
659658
if( zHash==0 ){
660659
blob_append(pXfer->pOut, " 0 0 1\n", -1);
660
+ }else if( noContent ){
661
+ blob_appendf(pXfer->pOut, " %s %d 4\n", zHash, db_column_int(&q1,3));
661662
}else{
662663
Blob content;
663664
blob_init(&content, 0, 0);
664
- db_column_blob(&q1, 3, &content);
665
+ db_column_blob(&q1, 4, &content);
665666
if( db_column_int(&q1, 2) ){
666667
blob_uncompress(&content, &content);
667668
}
668669
blob_appendf(pXfer->pOut, " %s %d 0\n", zHash, blob_size(&content));
669670
blob_append(pXfer->pOut, blob_buffer(&content), blob_size(&content));
@@ -1004,11 +1005,11 @@
10041005
const char *zName = db_column_text(&uvq,0);
10051006
sqlite3_int64 mtime = db_column_int64(&uvq,1);
10061007
const char *zHash = db_column_text(&uvq,2);
10071008
int sz = db_column_int(&uvq,3);
10081009
nUvIgot++;
1009
- if( zHash==0 ){ sz = 0; zHash = "0"; }
1010
+ if( zHash==0 ){ sz = 0; zHash = "-"; }
10101011
blob_appendf(pXfer->pOut, "uvigot %s %lld %s %d\n",
10111012
zName, mtime, zHash, sz);
10121013
}
10131014
db_finalize(&uvq);
10141015
}
@@ -1245,11 +1246,11 @@
12451246
*/
12461247
if( blob_eq(&xfer.aToken[0], "uvgimme")
12471248
&& xfer.nToken==2
12481249
&& blob_is_filename(&xfer.aToken[1])
12491250
){
1250
- send_unversioned_file(&xfer, blob_str(&xfer.aToken[1]));
1251
+ send_unversioned_file(&xfer, blob_str(&xfer.aToken[1]), 0);
12511252
}else
12521253
12531254
/* igot UUID ?ISPRIVATE?
12541255
**
12551256
** Client announces that it has a particular file. If the ISPRIVATE
@@ -1427,11 +1428,10 @@
14271428
}
14281429
configure_receive(zName, &content, CONFIGSET_ALL);
14291430
blob_reset(&content);
14301431
blob_seek(xfer.pIn, 1, BLOB_SEEK_CUR);
14311432
}else
1432
-
14331433
14341434
14351435
/* cookie TEXT
14361436
**
14371437
** A cookie contains a arbitrary-length argument that is server-defined.
@@ -1705,11 +1705,18 @@
17051705
17061706
/* When syncing unversioned files, create a TEMP table in which to store
17071707
** the names of files that do not need to be sent from client to server.
17081708
*/
17091709
if( syncFlags & SYNC_UNVERSIONED ){
1710
- db_multi_exec("CREATE TEMP TABLE uv_dont_push(name TEXT PRIMARY KEY)WITHOUT ROWID;");
1710
+ db_multi_exec(
1711
+ "CREATE TEMP TABLE uv_toSend("
1712
+ " name TEXT PRIMARY KEY,"
1713
+ " mtimeOnly BOOLEAN"
1714
+ ") WITHOUT ROWID;"
1715
+ "INSERT INTO uv_toSend(name,mtimeOnly)"
1716
+ " SELECT name, 0 FROM unversioned WHERE hash IS NOT NULL;"
1717
+ );
17111718
}
17121719
17131720
/*
17141721
** Always begin with a clone, pull, or push message
17151722
*/
@@ -1830,18 +1837,14 @@
18301837
*/
18311838
if( uvDoPush ){
18321839
Stmt uvq;
18331840
assert( (syncFlags & SYNC_UNVERSIONED)!=0 );
18341841
assert( uvStatus==2 );
1835
- db_prepare(&uvq,
1836
- "SELECT name FROM unversioned"
1837
- " WHERE hash IS NOT NULL"
1838
- " EXCEPT "
1839
- "SELECT name FROM uv_dont_send"
1840
- );
1842
+ db_prepare(&uvq, "SELECT name, mtimeOnly FROM uv_tosend");
18411843
while( db_step(&uvq) ){
1842
- send_unversioned_file(&xfer, db_column_text(&uvq,0));
1844
+ send_unversioned_file(&xfer, db_column_text(&uvq,0), db_column_int(&uvq,1));
1845
+ nCardSent++;
18431846
}
18441847
db_finalize(&uvq);
18451848
uvDoPush = 0;
18461849
}
18471850
@@ -2005,27 +2008,56 @@
20052008
if( rid ) newPhantom = 1;
20062009
}
20072010
remote_has(rid);
20082011
}else
20092012
2010
- /* uvigot NAME TIMESTAMP HASH SIZE
2013
+ /* uvigot NAME MTIME HASH SIZE
20112014
**
20122015
** Server announces that it has a particular unversioned file. The
20132016
** server will only send this card if the client had previously sent
20142017
** a "pragma uv-hash" card with a hash that does not match.
20152018
**
2016
- ** If the identified file needs to be transferred, then do the
2017
- ** transfer.
2019
+ ** If the identified file needs to be transferred, then setup for the
2020
+ ** transfer. Generate a "uvgimme" card in the reply if the server version
2021
+ ** is newer than the client. Generate a "uvfile" card if the client version
2022
+ ** is newer than the server. If HASH is "-" (indicating that the file has
2023
+ ** been deleted) and MTIME is newer, then do the deletion.
20182024
*/
20192025
if( xfer.nToken==5
20202026
&& blob_eq(&xfer.aToken[0], "uvigot")
20212027
&& blob_is_filename(&xfer.aToken[1])
20222028
&& blob_is_int64(&xfer.aToken[2], &mtime)
20232029
&& blob_is_int(&xfer.aToken[4], &size)
2024
- && (size==0 || blob_is_uuid(&xfer.aToken[3]))
2030
+ && (blob_eq(&xfer.aToken[3],"-")==0 || blob_is_uuid(&xfer.aToken[3]))
20252031
){
2032
+ const char *zName = blob_str(&xfer.aToken[1]);
2033
+ const char *zHash = blob_str(&xfer.aToken[3]);
2034
+ int iStatus;
20262035
if( uvStatus==0 ) uvStatus = 2;
2036
+ iStatus = unversioned_status(zName, mtime, zHash);
2037
+ if( iStatus<=1 ){
2038
+ if( zHash[0]!='-' ){
2039
+ @ uvgimme %s(zName)
2040
+ }else if( iStatus==1 ){
2041
+ db_multi_exec(
2042
+ "UPDATE unversioned"
2043
+ " SET mtime=%lld, hash=NULL, sz=0, encoding=0, content=NULL"
2044
+ " WHERE name=%Q", mtime, zName
2045
+ );
2046
+ db_unset("uv-hash", 0);
2047
+ }
2048
+ }else if( iStatus==2 ){
2049
+ db_multi_exec(
2050
+ "UPDATE unversioned SET mtime=%lld WHERE name=%Q", mtime, zName
2051
+ );
2052
+ db_unset("uv-hash", 0);
2053
+ }
2054
+ if( iStatus<=3 ){
2055
+ db_multi_exec("DELETE FROM uv_tosend WHERE name=%Q", zName);
2056
+ }else if( iStatus==4 ){
2057
+ db_multi_exec("UPDATE uv_tosend SET mtimeOnly=1 WHERE name=%Q", zName);
2058
+ }
20272059
}else
20282060
20292061
/* push SERVERCODE PRODUCTCODE
20302062
**
20312063
** Should only happen in response to a clone. This message tells
@@ -2136,10 +2168,11 @@
21362168
*/
21372169
if( blob_eq(&xfer.aToken[1], "uv-pull-only") ){
21382170
uvStatus = 1;
21392171
}else if( blob_eq(&xfer.aToken[1], "uv-push-ok") ){
21402172
uvStatus = 2;
2173
+ uvDoPush = 1;
21412174
}
21422175
}else
21432176
21442177
/* error MESSAGE
21452178
**
21462179
--- src/xfer.c
+++ src/xfer.c
@@ -294,34 +294,37 @@
294 **
295 ** uvfile NAME MTIME HASH SIZE FLAGS
296 ** uvfile NAME MTIME HASH SIZE FLAGS \n CONTENT
297 **
298 ** If the 0x0001 bit of FLAGS is set, that means the file has been
299 ** deleted, SIZE is zero, the HASH is "0", and the "\n CONTENT" is omitted.
300 **
301 ** SIZE is the number of bytes of CONTENT. The CONTENT is uncompressed.
302 ** HASH is the SHA1 hash of CONTENT.
303 **
304 ** If the 0x0004 bit of FLAGS is set, that means the CONTENT size
305 ** is too big to transmit and so the "\n CONTENT" is omitted.
 
 
306 */
307 static void xfer_accept_unversioned_file(Xfer *pXfer, int isWriter){
308 sqlite3_int64 mtime; /* The MTIME */
309 Blob *pHash; /* The HASH value */
310 int sz; /* The SIZE */
311 int flags; /* The FLAGS */
312 Blob content; /* The CONTENT */
313 Blob hash; /* Hash computed from CONTENT to compare with HASH */
314 Stmt q; /* SQL statements for comparison and insert */
315 int isDelete; /* HASH is "0" indicating this is a delete operation */
316 int nullContent; /* True of CONTENT is NULL */
 
317
318 pHash = &pXfer->aToken[3];
319 if( pXfer->nToken==5
320 || !blob_is_filename(&pXfer->aToken[1])
321 || !blob_is_int64(&pXfer->aToken[2], &mtime)
322 || (blob_eq(pHash,"0")!=0 && !blob_is_uuid(pHash))
323 || !blob_is_int(&pXfer->aToken[4], &sz)
324 || !blob_is_int(&pXfer->aToken[5], &flags)
325 ){
326 blob_appendf(&pXfer->err, "malformed uvfile line");
327 return;
@@ -345,37 +348,23 @@
345
346 /* Check to see if current content really should be overwritten. Ideally,
347 ** a uvfile card should never have been sent unless the overwrite should
348 ** occur. But do not trust the sender. Double-check.
349 */
350 db_prepare(&q,
351 "SELECT mtime, hash FROM unversioned WHERE name=%Q",
352 blob_str(&pXfer->aToken[1])
353 );
354 if( db_step(&q)==SQLITE_ROW ){
355 sqlite3_int64 xtime = db_column_int64(&q, 0);
356 const char *xhash = db_column_text(&q, 1);
357 if( xtime>mtime ){
358 db_finalize(&q);
359 goto end_accept_unversioned_file;
360 }
361 if( xhash==0 ) xhash = "0";
362 if( xtime==mtime && strcmp(xhash, blob_str(pHash))>0 ){
363 db_finalize(&q);
364 goto end_accept_unversioned_file;
365 }
366 }
367 db_finalize(&q);
368
369 /* Store the content */
370 isDelete = blob_eq(pHash, "0");
371 if( isDelete ){
372 db_prepare(&q,
373 "UPDATE unversioned"
374 " SET rcvid=:rcvid, mtime=:mtime, hash=NULL, sz=0, content=NULL"
375 " WHERE name=:name"
376 );
 
 
377 }else{
378 db_prepare(&q,
379 "REPLACE INTO unversioned(name, rcvid, mtime, hash, sz, content)"
380 " VALUES(:name,:rcvid,:mtime,:hash,:sz,:content)"
381 );
@@ -389,10 +378,11 @@
389 blob_compress(&content, &content);
390 db_bind_blob(&q, ":content", &content);
391 }
392 db_step(&q);
393 db_finalize(&q);
 
394
395 end_accept_unversioned_file:
396 blob_reset(&content);
397 blob_reset(&hash);
398 }
@@ -642,28 +632,39 @@
642 /*
643 ** Send the unversioned file identified by zName by generating the
644 ** appropriate "uvfile" card.
645 **
646 ** uvfile NAME MTIME HASH SIZE FLAGS \n CONTENT
 
 
647 */
648 static void send_unversioned_file(Xfer *pXfer, const char *zName){
649 Stmt q1;
650
651 db_static_prepare(&q1,
652 "SELECT mtime, hash, encoding, content FROM unversioned WHERE name=%Q",
653 zName
654 );
 
 
 
 
 
 
 
655 if( db_step(&q1)==SQLITE_ROW ){
656 sqlite3_int64 mtime = db_column_int64(&q1, 0);
657 const char *zHash = db_column_text(&q1, 1);
658 blob_appendf(pXfer->pOut, "uvfile %s %lld", zName, mtime);
659 if( zHash==0 ){
660 blob_append(pXfer->pOut, " 0 0 1\n", -1);
 
 
661 }else{
662 Blob content;
663 blob_init(&content, 0, 0);
664 db_column_blob(&q1, 3, &content);
665 if( db_column_int(&q1, 2) ){
666 blob_uncompress(&content, &content);
667 }
668 blob_appendf(pXfer->pOut, " %s %d 0\n", zHash, blob_size(&content));
669 blob_append(pXfer->pOut, blob_buffer(&content), blob_size(&content));
@@ -1004,11 +1005,11 @@
1004 const char *zName = db_column_text(&uvq,0);
1005 sqlite3_int64 mtime = db_column_int64(&uvq,1);
1006 const char *zHash = db_column_text(&uvq,2);
1007 int sz = db_column_int(&uvq,3);
1008 nUvIgot++;
1009 if( zHash==0 ){ sz = 0; zHash = "0"; }
1010 blob_appendf(pXfer->pOut, "uvigot %s %lld %s %d\n",
1011 zName, mtime, zHash, sz);
1012 }
1013 db_finalize(&uvq);
1014 }
@@ -1245,11 +1246,11 @@
1245 */
1246 if( blob_eq(&xfer.aToken[0], "uvgimme")
1247 && xfer.nToken==2
1248 && blob_is_filename(&xfer.aToken[1])
1249 ){
1250 send_unversioned_file(&xfer, blob_str(&xfer.aToken[1]));
1251 }else
1252
1253 /* igot UUID ?ISPRIVATE?
1254 **
1255 ** Client announces that it has a particular file. If the ISPRIVATE
@@ -1427,11 +1428,10 @@
1427 }
1428 configure_receive(zName, &content, CONFIGSET_ALL);
1429 blob_reset(&content);
1430 blob_seek(xfer.pIn, 1, BLOB_SEEK_CUR);
1431 }else
1432
1433
1434
1435 /* cookie TEXT
1436 **
1437 ** A cookie contains a arbitrary-length argument that is server-defined.
@@ -1705,11 +1705,18 @@
1705
1706 /* When syncing unversioned files, create a TEMP table in which to store
1707 ** the names of files that do not need to be sent from client to server.
1708 */
1709 if( syncFlags & SYNC_UNVERSIONED ){
1710 db_multi_exec("CREATE TEMP TABLE uv_dont_push(name TEXT PRIMARY KEY)WITHOUT ROWID;");
 
 
 
 
 
 
 
1711 }
1712
1713 /*
1714 ** Always begin with a clone, pull, or push message
1715 */
@@ -1830,18 +1837,14 @@
1830 */
1831 if( uvDoPush ){
1832 Stmt uvq;
1833 assert( (syncFlags & SYNC_UNVERSIONED)!=0 );
1834 assert( uvStatus==2 );
1835 db_prepare(&uvq,
1836 "SELECT name FROM unversioned"
1837 " WHERE hash IS NOT NULL"
1838 " EXCEPT "
1839 "SELECT name FROM uv_dont_send"
1840 );
1841 while( db_step(&uvq) ){
1842 send_unversioned_file(&xfer, db_column_text(&uvq,0));
 
1843 }
1844 db_finalize(&uvq);
1845 uvDoPush = 0;
1846 }
1847
@@ -2005,27 +2008,56 @@
2005 if( rid ) newPhantom = 1;
2006 }
2007 remote_has(rid);
2008 }else
2009
2010 /* uvigot NAME TIMESTAMP HASH SIZE
2011 **
2012 ** Server announces that it has a particular unversioned file. The
2013 ** server will only send this card if the client had previously sent
2014 ** a "pragma uv-hash" card with a hash that does not match.
2015 **
2016 ** If the identified file needs to be transferred, then do the
2017 ** transfer.
 
 
 
2018 */
2019 if( xfer.nToken==5
2020 && blob_eq(&xfer.aToken[0], "uvigot")
2021 && blob_is_filename(&xfer.aToken[1])
2022 && blob_is_int64(&xfer.aToken[2], &mtime)
2023 && blob_is_int(&xfer.aToken[4], &size)
2024 && (size==0 || blob_is_uuid(&xfer.aToken[3]))
2025 ){
 
 
 
2026 if( uvStatus==0 ) uvStatus = 2;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2027 }else
2028
2029 /* push SERVERCODE PRODUCTCODE
2030 **
2031 ** Should only happen in response to a clone. This message tells
@@ -2136,10 +2168,11 @@
2136 */
2137 if( blob_eq(&xfer.aToken[1], "uv-pull-only") ){
2138 uvStatus = 1;
2139 }else if( blob_eq(&xfer.aToken[1], "uv-push-ok") ){
2140 uvStatus = 2;
 
2141 }
2142 }else
2143
2144 /* error MESSAGE
2145 **
2146
--- src/xfer.c
+++ src/xfer.c
@@ -294,34 +294,37 @@
294 **
295 ** uvfile NAME MTIME HASH SIZE FLAGS
296 ** uvfile NAME MTIME HASH SIZE FLAGS \n CONTENT
297 **
298 ** If the 0x0001 bit of FLAGS is set, that means the file has been
299 ** deleted, SIZE is zero, the HASH is "-", and the "\n CONTENT" is omitted.
300 **
301 ** SIZE is the number of bytes of CONTENT. The CONTENT is uncompressed.
302 ** HASH is the SHA1 hash of CONTENT.
303 **
304 ** If the 0x0004 bit of FLAGS is set, that means the CONTENT is omitted.
305 ** The sender might have omitted the content because it is too big to
306 ** transmit, or because it is unchanged and this record exists purely
307 ** to update the MTIME.
308 */
309 static void xfer_accept_unversioned_file(Xfer *pXfer, int isWriter){
310 sqlite3_int64 mtime; /* The MTIME */
311 Blob *pHash; /* The HASH value */
312 int sz; /* The SIZE */
313 int flags; /* The FLAGS */
314 Blob content; /* The CONTENT */
315 Blob hash; /* Hash computed from CONTENT to compare with HASH */
316 Stmt q; /* SQL statements for comparison and insert */
317 int isDelete; /* HASH is "-" indicating this is a delete operation */
318 int nullContent; /* True of CONTENT is NULL */
319 int iStatus; /* Result from unversioned_status() */
320
321 pHash = &pXfer->aToken[3];
322 if( pXfer->nToken==5
323 || !blob_is_filename(&pXfer->aToken[1])
324 || !blob_is_int64(&pXfer->aToken[2], &mtime)
325 || (blob_eq(pHash,"-")!=0 && !blob_is_uuid(pHash))
326 || !blob_is_int(&pXfer->aToken[4], &sz)
327 || !blob_is_int(&pXfer->aToken[5], &flags)
328 ){
329 blob_appendf(&pXfer->err, "malformed uvfile line");
330 return;
@@ -345,37 +348,23 @@
348
349 /* Check to see if current content really should be overwritten. Ideally,
350 ** a uvfile card should never have been sent unless the overwrite should
351 ** occur. But do not trust the sender. Double-check.
352 */
353 iStatus = unversioned_status(blob_str(&pXfer->aToken[1]), mtime, blob_str(pHash));
354 if( iStatus>=3 ) goto end_accept_unversioned_file;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
355
356 /* Store the content */
357 isDelete = blob_eq(pHash, "-");
358 if( isDelete ){
359 db_prepare(&q,
360 "UPDATE unversioned"
361 " SET rcvid=:rcvid, mtime=:mtime, hash=NULL, sz=0, content=NULL"
362 " WHERE name=:name"
363 );
364 }else if( iStatus==4 ){
365 db_prepare(&q, "UPDATE unversioned SET mtime=:mtime WHERE name=:name");
366 }else{
367 db_prepare(&q,
368 "REPLACE INTO unversioned(name, rcvid, mtime, hash, sz, content)"
369 " VALUES(:name,:rcvid,:mtime,:hash,:sz,:content)"
370 );
@@ -389,10 +378,11 @@
378 blob_compress(&content, &content);
379 db_bind_blob(&q, ":content", &content);
380 }
381 db_step(&q);
382 db_finalize(&q);
383 db_unset("uv-hash", 0);
384
385 end_accept_unversioned_file:
386 blob_reset(&content);
387 blob_reset(&hash);
388 }
@@ -642,28 +632,39 @@
632 /*
633 ** Send the unversioned file identified by zName by generating the
634 ** appropriate "uvfile" card.
635 **
636 ** uvfile NAME MTIME HASH SIZE FLAGS \n CONTENT
637 **
638 ** If the noContent flag is set, omit the CONTENT and set the 0x0004 flag in FLAGS.
639 */
640 static void send_unversioned_file(Xfer *pXfer, const char *zName, int noContent){
641 Stmt q1;
642
643 if( noContent ){
644 db_static_prepare(&q1,
645 "SELECT mtime, hash, encoding, sz FROM unversioned WHERE name=%Q",
646 zName
647 );
648 }else{
649 db_static_prepare(&q1,
650 "SELECT mtime, hash, encoding, sz, content FROM unversioned WHERE name=%Q",
651 zName
652 );
653 }
654 if( db_step(&q1)==SQLITE_ROW ){
655 sqlite3_int64 mtime = db_column_int64(&q1, 0);
656 const char *zHash = db_column_text(&q1, 1);
657 blob_appendf(pXfer->pOut, "uvfile %s %lld", zName, mtime);
658 if( zHash==0 ){
659 blob_append(pXfer->pOut, " 0 0 1\n", -1);
660 }else if( noContent ){
661 blob_appendf(pXfer->pOut, " %s %d 4\n", zHash, db_column_int(&q1,3));
662 }else{
663 Blob content;
664 blob_init(&content, 0, 0);
665 db_column_blob(&q1, 4, &content);
666 if( db_column_int(&q1, 2) ){
667 blob_uncompress(&content, &content);
668 }
669 blob_appendf(pXfer->pOut, " %s %d 0\n", zHash, blob_size(&content));
670 blob_append(pXfer->pOut, blob_buffer(&content), blob_size(&content));
@@ -1004,11 +1005,11 @@
1005 const char *zName = db_column_text(&uvq,0);
1006 sqlite3_int64 mtime = db_column_int64(&uvq,1);
1007 const char *zHash = db_column_text(&uvq,2);
1008 int sz = db_column_int(&uvq,3);
1009 nUvIgot++;
1010 if( zHash==0 ){ sz = 0; zHash = "-"; }
1011 blob_appendf(pXfer->pOut, "uvigot %s %lld %s %d\n",
1012 zName, mtime, zHash, sz);
1013 }
1014 db_finalize(&uvq);
1015 }
@@ -1245,11 +1246,11 @@
1246 */
1247 if( blob_eq(&xfer.aToken[0], "uvgimme")
1248 && xfer.nToken==2
1249 && blob_is_filename(&xfer.aToken[1])
1250 ){
1251 send_unversioned_file(&xfer, blob_str(&xfer.aToken[1]), 0);
1252 }else
1253
1254 /* igot UUID ?ISPRIVATE?
1255 **
1256 ** Client announces that it has a particular file. If the ISPRIVATE
@@ -1427,11 +1428,10 @@
1428 }
1429 configure_receive(zName, &content, CONFIGSET_ALL);
1430 blob_reset(&content);
1431 blob_seek(xfer.pIn, 1, BLOB_SEEK_CUR);
1432 }else
 
1433
1434
1435 /* cookie TEXT
1436 **
1437 ** A cookie contains a arbitrary-length argument that is server-defined.
@@ -1705,11 +1705,18 @@
1705
1706 /* When syncing unversioned files, create a TEMP table in which to store
1707 ** the names of files that do not need to be sent from client to server.
1708 */
1709 if( syncFlags & SYNC_UNVERSIONED ){
1710 db_multi_exec(
1711 "CREATE TEMP TABLE uv_toSend("
1712 " name TEXT PRIMARY KEY,"
1713 " mtimeOnly BOOLEAN"
1714 ") WITHOUT ROWID;"
1715 "INSERT INTO uv_toSend(name,mtimeOnly)"
1716 " SELECT name, 0 FROM unversioned WHERE hash IS NOT NULL;"
1717 );
1718 }
1719
1720 /*
1721 ** Always begin with a clone, pull, or push message
1722 */
@@ -1830,18 +1837,14 @@
1837 */
1838 if( uvDoPush ){
1839 Stmt uvq;
1840 assert( (syncFlags & SYNC_UNVERSIONED)!=0 );
1841 assert( uvStatus==2 );
1842 db_prepare(&uvq, "SELECT name, mtimeOnly FROM uv_tosend");
 
 
 
 
 
1843 while( db_step(&uvq) ){
1844 send_unversioned_file(&xfer, db_column_text(&uvq,0), db_column_int(&uvq,1));
1845 nCardSent++;
1846 }
1847 db_finalize(&uvq);
1848 uvDoPush = 0;
1849 }
1850
@@ -2005,27 +2008,56 @@
2008 if( rid ) newPhantom = 1;
2009 }
2010 remote_has(rid);
2011 }else
2012
2013 /* uvigot NAME MTIME HASH SIZE
2014 **
2015 ** Server announces that it has a particular unversioned file. The
2016 ** server will only send this card if the client had previously sent
2017 ** a "pragma uv-hash" card with a hash that does not match.
2018 **
2019 ** If the identified file needs to be transferred, then setup for the
2020 ** transfer. Generate a "uvgimme" card in the reply if the server version
2021 ** is newer than the client. Generate a "uvfile" card if the client version
2022 ** is newer than the server. If HASH is "-" (indicating that the file has
2023 ** been deleted) and MTIME is newer, then do the deletion.
2024 */
2025 if( xfer.nToken==5
2026 && blob_eq(&xfer.aToken[0], "uvigot")
2027 && blob_is_filename(&xfer.aToken[1])
2028 && blob_is_int64(&xfer.aToken[2], &mtime)
2029 && blob_is_int(&xfer.aToken[4], &size)
2030 && (blob_eq(&xfer.aToken[3],"-")==0 || blob_is_uuid(&xfer.aToken[3]))
2031 ){
2032 const char *zName = blob_str(&xfer.aToken[1]);
2033 const char *zHash = blob_str(&xfer.aToken[3]);
2034 int iStatus;
2035 if( uvStatus==0 ) uvStatus = 2;
2036 iStatus = unversioned_status(zName, mtime, zHash);
2037 if( iStatus<=1 ){
2038 if( zHash[0]!='-' ){
2039 @ uvgimme %s(zName)
2040 }else if( iStatus==1 ){
2041 db_multi_exec(
2042 "UPDATE unversioned"
2043 " SET mtime=%lld, hash=NULL, sz=0, encoding=0, content=NULL"
2044 " WHERE name=%Q", mtime, zName
2045 );
2046 db_unset("uv-hash", 0);
2047 }
2048 }else if( iStatus==2 ){
2049 db_multi_exec(
2050 "UPDATE unversioned SET mtime=%lld WHERE name=%Q", mtime, zName
2051 );
2052 db_unset("uv-hash", 0);
2053 }
2054 if( iStatus<=3 ){
2055 db_multi_exec("DELETE FROM uv_tosend WHERE name=%Q", zName);
2056 }else if( iStatus==4 ){
2057 db_multi_exec("UPDATE uv_tosend SET mtimeOnly=1 WHERE name=%Q", zName);
2058 }
2059 }else
2060
2061 /* push SERVERCODE PRODUCTCODE
2062 **
2063 ** Should only happen in response to a clone. This message tells
@@ -2136,10 +2168,11 @@
2168 */
2169 if( blob_eq(&xfer.aToken[1], "uv-pull-only") ){
2170 uvStatus = 1;
2171 }else if( blob_eq(&xfer.aToken[1], "uv-push-ok") ){
2172 uvStatus = 2;
2173 uvDoPush = 1;
2174 }
2175 }else
2176
2177 /* error MESSAGE
2178 **
2179

Keyboard Shortcuts

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