commit 97a42cd825be28f4b042a9b649845c8b954f9ea9
Author: Oswald Buddenhagen <[email protected]>
Date: Sat Dec 27 23:13:45 2014 +0100
factor out {prepare,lock,save,load}_state()
src/sync.c | 295 +++++++++++++++++++++++++++++-----------------------
1 files changed, 165 insertions(+), 130 deletions(-)
diff --git a/src/sync.c b/src/sync.c
index 96fabd4..c77a337 100644
--- a/src/sync.c
+++ b/src/sync.c
@@ -154,7 +154,7 @@ typedef struct {
store_t *ctx[2];
driver_t *drv[2];
const char *orig_name[2];
- int state[2], ref_count, nsrecs, ret, lfd;
+ int state[2], ref_count, nsrecs, ret, lfd, existing, replayed;
int new_total[2], new_done[2];
int flags_total[2], flags_done[2];
int trash_total[2], trash_done[2];
@@ -467,7 +467,6 @@ stats( sync_vars_t *svars )
static void sync_bail( sync_vars_t *svars );
-static void sync_bail1( sync_vars_t *svars );
static void sync_bail2( sync_vars_t *svars );
static void sync_bail3( sync_vars_t *svars );
static void cancel_done( void *aux );
@@ -580,91 +579,19 @@ clean_strdup( const char *s )
#define JOURNAL_VERSION "2"
-static void box_selected( int sts, void *aux );
-
-void
-sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan,
- void (*cb)( int sts, void *aux ), void *aux )
-{
- sync_vars_t *svars;
- int t;
-
- svars = nfcalloc( sizeof(*svars) );
- svars->t[1] = 1;
- svars->ref_count = 1;
- svars->cb = cb;
- svars->aux = aux;
- svars->ctx[0] = ctx[0];
- svars->ctx[1] = ctx[1];
- svars->chan = chan;
- svars->uidval[0] = svars->uidval[1] = -1;
- svars->srecadd = &svars->srecs;
-
- for (t = 0; t < 2; t++) {
- svars->orig_name[t] =
- (!names[t] || (ctx[t]->conf->map_inbox && !strcmp(
ctx[t]->conf->map_inbox, names[t] ))) ?
- "INBOX" : names[t];
- if (!ctx[t]->conf->flat_delim) {
- svars->box_name[t] = nfstrdup( svars->orig_name[t] );
- } else if (map_name( svars->orig_name[t], &svars->box_name[t],
0, "/", ctx[t]->conf->flat_delim ) < 0) {
- error( "Error: canonical mailbox name '%s' contains
flattened hierarchy delimiter\n", svars->orig_name[t] );
- svars->ret = SYNC_FAIL;
- sync_bail3( svars );
- return;
- }
- ctx[t]->uidvalidity = -1;
- set_bad_callback( ctx[t], store_bad, AUX );
- svars->drv[t] = ctx[t]->conf->driver;
- }
- /* Both boxes must be fully set up at this point, so that error exit
paths
- * don't run into uninitialized variables. */
- sync_ref( svars );
- for (t = 0; t < 2; t++) {
- info( "Selecting %s %s...\n", str_ms[t], svars->orig_name[t] );
- svars->drv[t]->select_box( ctx[t], svars->box_name[t],
(chan->ops[t] & OP_CREATE) != 0, box_selected, AUX );
- if (check_cancel( svars ))
- break;
- }
- sync_deref( svars );
-}
-
-static void load_box( sync_vars_t *svars, int t, int minwuid, int *mexcs, int
nmexcs );
-
-static void
-box_selected( int sts, void *aux )
+static int
+prepare_state( sync_vars_t *svars )
{
- DECL_SVARS;
- sync_rec_t *srec, *nsrec;
char *s, *cmname, *csname;
- store_t *ctx[2];
channel_conf_t *chan;
- FILE *jfp;
- int opts[2], line, t1, t2, t3;
- int *mexcs, nmexcs, rmexcs, minwuid;
- struct stat st;
- struct flock lck;
- char fbuf[16]; /* enlarge when support for keywords is added */
- char buf[128], buf1[64], buf2[64];
-
- if (check_ret( sts, aux ))
- return;
- INIT_SVARS(aux);
- ctx[0] = svars->ctx[0];
- ctx[1] = svars->ctx[1];
- svars->state[t] |= ST_SELECTED;
- if (!(svars->state[1-t] & ST_SELECTED))
- return;
chan = svars->chan;
if (!strcmp( chan->sync_state ? chan->sync_state :
global_conf.sync_state, "*" )) {
- if (!ctx[S]->path) {
+ if (!svars->ctx[S]->path) {
error( "Error: store '%s' does not support in-box sync
state\n", chan->stores[S]->name );
- sbail:
- svars->ret = SYNC_FAIL;
- sync_bail2( svars );
- return;
+ return 0;
}
- nfasprintf( &svars->dname, "%s/." EXE "state", ctx[S]->path );
+ nfasprintf( &svars->dname, "%s/." EXE "state",
svars->ctx[S]->path );
} else {
csname = clean_strdup( svars->box_name[S] );
if (chan->sync_state)
@@ -679,18 +606,26 @@ box_selected( int sts, void *aux )
free( csname );
if (!(s = strrchr( svars->dname, '/' ))) {
error( "Error: invalid SyncState location '%s'\n",
svars->dname );
- goto sbail;
+ return 0;
}
*s = 0;
if (mkdir( svars->dname, 0700 ) && errno != EEXIST) {
sys_error( "Error: cannot create SyncState directory
'%s'", svars->dname );
- goto sbail;
+ return 0;
}
*s = '/';
}
nfasprintf( &svars->jname, "%s.journal", svars->dname );
nfasprintf( &svars->nname, "%s.new", svars->dname );
nfasprintf( &svars->lname, "%s.lock", svars->dname );
+ return 1;
+}
+
+static int
+lock_state( sync_vars_t *svars )
+{
+ struct flock lck;
+
memset( &lck, 0, sizeof(lck) );
#if SEEK_SET != 0
lck.l_whence = SEEK_SET;
@@ -700,17 +635,59 @@ box_selected( int sts, void *aux )
#endif
if ((svars->lfd = open( svars->lname, O_WRONLY|O_CREAT, 0666 )) < 0) {
sys_error( "Error: cannot create lock file %s", svars->lname );
- svars->ret = SYNC_FAIL;
- sync_bail2( svars );
- return;
+ return 0;
}
if (fcntl( svars->lfd, F_SETLK, &lck )) {
error( "Error: channel :%s:%s-:%s:%s is locked\n",
- chan->stores[M]->name, svars->orig_name[M],
chan->stores[S]->name, svars->orig_name[S] );
- svars->ret = SYNC_FAIL;
- sync_bail1( svars );
- return;
+ svars->chan->stores[M]->name, svars->orig_name[M],
svars->chan->stores[S]->name, svars->orig_name[S] );
+ close( svars->lfd );
+ return 0;
}
+ return 1;
+}
+
+static void
+save_state( sync_vars_t *svars )
+{
+ sync_rec_t *srec;
+ char fbuf[16]; /* enlarge when support for keywords is added */
+
+ Fprintf( svars->nfp,
+ "MasterUidValidity %d\nSlaveUidValidity %d\nMaxPulledUid
%d\nMaxPushedUid %d\n",
+ svars->uidval[M], svars->uidval[S], svars->maxuid[M],
svars->maxuid[S] );
+ if (svars->smaxxuid)
+ Fprintf( svars->nfp, "MaxExpiredSlaveUid %d\n", svars->smaxxuid
);
+ Fprintf( svars->nfp, "\n" );
+ for (srec = svars->srecs; srec; srec = srec->next) {
+ if (srec->status & S_DEAD)
+ continue;
+ make_flags( srec->flags, fbuf );
+ Fprintf( svars->nfp, "%d %d %s%s\n", srec->uid[M], srec->uid[S],
+ srec->status & S_EXPIRED ? "X" : "", fbuf );
+ }
+
+ Fclose( svars->nfp, 1 );
+ Fclose( svars->jfp, 0 );
+ if (!(DFlags & KEEPJOURNAL)) {
+ /* order is important! */
+ if (rename( svars->nname, svars->dname ))
+ warn( "Warning: cannot commit sync state %s\n",
svars->dname );
+ else if (unlink( svars->jname ))
+ warn( "Warning: cannot delete journal %s\n",
svars->jname );
+ }
+}
+
+static int
+load_state( sync_vars_t *svars )
+{
+ sync_rec_t *srec, *nsrec;
+ char *s;
+ FILE *jfp;
+ int line, t, t1, t2, t3;
+ struct stat st;
+ char fbuf[16]; /* enlarge when support for keywords is added */
+ char buf[128], buf1[64], buf2[64];
+
if ((jfp = fopen( svars->dname, "r" ))) {
debug( "reading sync state %s ...\n", svars->dname );
line = 0;
@@ -720,10 +697,7 @@ box_selected( int sts, void *aux )
error( "Error: incomplete sync state header
entry at %s:%d\n", svars->dname, line );
jbail:
fclose( jfp );
- bail:
- svars->ret = SYNC_FAIL;
- sync_bail( svars );
- return;
+ return 0;
}
if (t == 1)
goto gothdr;
@@ -788,11 +762,13 @@ box_selected( int sts, void *aux )
svars->nsrecs++;
}
fclose( jfp );
+ svars->existing = 1;
} else {
if (errno != ENOENT) {
sys_error( "Error: cannot read sync state %s",
svars->dname );
- goto bail;
+ return 0;
}
+ svars->existing = 0;
}
svars->newmaxuid[M] = svars->maxuid[M];
svars->newmaxuid[S] = svars->maxuid[S];
@@ -936,19 +912,107 @@ box_selected( int sts, void *aux )
} else {
if (errno != ENOENT) {
sys_error( "Error: cannot read journal %s",
svars->jname );
- goto bail;
+ return 0;
}
}
+ svars->replayed = line;
+ return 1;
+}
+
+static void box_selected( int sts, void *aux );
+
+void
+sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan,
+ void (*cb)( int sts, void *aux ), void *aux )
+{
+ sync_vars_t *svars;
+ int t;
+
+ svars = nfcalloc( sizeof(*svars) );
+ svars->t[1] = 1;
+ svars->ref_count = 1;
+ svars->cb = cb;
+ svars->aux = aux;
+ svars->ctx[0] = ctx[0];
+ svars->ctx[1] = ctx[1];
+ svars->chan = chan;
+ svars->uidval[0] = svars->uidval[1] = -1;
+ svars->srecadd = &svars->srecs;
+
+ for (t = 0; t < 2; t++) {
+ svars->orig_name[t] =
+ (!names[t] || (ctx[t]->conf->map_inbox && !strcmp(
ctx[t]->conf->map_inbox, names[t] ))) ?
+ "INBOX" : names[t];
+ if (!ctx[t]->conf->flat_delim) {
+ svars->box_name[t] = nfstrdup( svars->orig_name[t] );
+ } else if (map_name( svars->orig_name[t], &svars->box_name[t],
0, "/", ctx[t]->conf->flat_delim ) < 0) {
+ error( "Error: canonical mailbox name '%s' contains
flattened hierarchy delimiter\n", svars->orig_name[t] );
+ svars->ret = SYNC_FAIL;
+ sync_bail3( svars );
+ return;
+ }
+ ctx[t]->uidvalidity = -1;
+ set_bad_callback( ctx[t], store_bad, AUX );
+ svars->drv[t] = ctx[t]->conf->driver;
+ }
+ /* Both boxes must be fully set up at this point, so that error exit
paths
+ * don't run into uninitialized variables. */
+ sync_ref( svars );
+ for (t = 0; t < 2; t++) {
+ info( "Selecting %s %s...\n", str_ms[t], svars->orig_name[t] );
+ svars->drv[t]->select_box( ctx[t], svars->box_name[t],
(chan->ops[t] & OP_CREATE) != 0, box_selected, AUX );
+ if (check_cancel( svars ))
+ break;
+ }
+ sync_deref( svars );
+}
+
+static void load_box( sync_vars_t *svars, int t, int minwuid, int *mexcs, int
nmexcs );
+
+static void
+box_selected( int sts, void *aux )
+{
+ DECL_SVARS;
+ sync_rec_t *srec;
+ store_t *ctx[2];
+ channel_conf_t *chan;
+ int opts[2], fails;
+ int *mexcs, nmexcs, rmexcs, minwuid;
+
+ if (check_ret( sts, aux ))
+ return;
+ INIT_SVARS(aux);
+ ctx[0] = svars->ctx[0];
+ ctx[1] = svars->ctx[1];
+ chan = svars->chan;
+ svars->state[t] |= ST_SELECTED;
+ if (!(svars->state[1-t] & ST_SELECTED))
+ return;
+
+ if (!prepare_state( svars ) || !lock_state( svars )) {
+ svars->ret = SYNC_FAIL;
+ sync_bail2( svars );
+ return;
+ }
+ if (!load_state( svars )) {
+ svars->ret = SYNC_FAIL;
+ sync_bail( svars );
+ return;
+ }
- t1 = 0;
+ fails = 0;
for (t = 0; t < 2; t++)
if (svars->uidval[t] >= 0 && svars->uidval[t] !=
ctx[t]->uidvalidity) {
error( "Error: UIDVALIDITY of %s changed (got %d,
expected %d)\n",
str_ms[t], ctx[t]->uidvalidity, svars->uidval[t]
);
- t1++;
+ fails++;
}
- if (t1)
- goto bail;
+ if (fails) {
+ bail:
+ svars->ret = SYNC_FAIL;
+ sync_bail( svars );
+ return;
+ }
if (!(svars->nfp = fopen( svars->nname, "w" ))) {
sys_error( "Error: cannot create new sync state %s",
svars->nname );
@@ -960,7 +1024,7 @@ box_selected( int sts, void *aux )
goto bail;
}
setlinebuf( svars->jfp );
- if (!line)
+ if (!svars->replayed)
Fprintf( svars->jfp, JOURNAL_VERSION "\n" );
opts[M] = opts[S] = 0;
@@ -994,7 +1058,7 @@ box_selected( int sts, void *aux )
}
if ((chan->ops[S] & (OP_NEW|OP_RENEW|OP_FLAGS)) && chan->max_messages)
opts[S] |= OPEN_OLD|OPEN_NEW|OPEN_FLAGS;
- if (line)
+ if (svars->replayed)
for (srec = svars->srecs; srec; srec = srec->next) {
if (srec->status & S_DEAD)
continue;
@@ -1816,7 +1880,6 @@ box_closed_p2( sync_vars_t *svars, int t )
{
sync_rec_t *srec;
int minwuid;
- char fbuf[16]; /* enlarge when support for keywords is added */
svars->state[t] |= ST_CLOSED;
if (!(svars->state[1-t] & ST_CLOSED))
@@ -1861,29 +1924,7 @@ box_closed_p2( sync_vars_t *svars, int t )
}
}
- Fprintf( svars->nfp,
- "MasterUidValidity %d\nSlaveUidValidity %d\nMaxPulledUid
%d\nMaxPushedUid %d\n",
- svars->uidval[M], svars->uidval[S], svars->maxuid[M],
svars->maxuid[S] );
- if (svars->smaxxuid)
- Fprintf( svars->nfp, "MaxExpiredSlaveUid %d\n", svars->smaxxuid
);
- Fprintf( svars->nfp, "\n" );
- for (srec = svars->srecs; srec; srec = srec->next) {
- if (srec->status & S_DEAD)
- continue;
- make_flags( srec->flags, fbuf );
- Fprintf( svars->nfp, "%d %d %s%s\n", srec->uid[M], srec->uid[S],
- srec->status & S_EXPIRED ? "X" : "", fbuf );
- }
-
- Fclose( svars->nfp, 1 );
- Fclose( svars->jfp, 0 );
- if (!(DFlags & KEEPJOURNAL)) {
- /* order is important! */
- if (rename( svars->nname, svars->dname ))
- warn( "Warning: cannot commit sync state %s\n",
svars->dname );
- else if (unlink( svars->jname ))
- warn( "Warning: cannot delete journal %s\n",
svars->jname );
- }
+ save_state( svars );
sync_bail( svars );
}
@@ -1898,12 +1939,6 @@ sync_bail( sync_vars_t *svars )
free( srec );
}
unlink( svars->lname );
- sync_bail1( svars );
-}
-
-static void
-sync_bail1( sync_vars_t *svars )
-{
close( svars->lfd );
sync_bail2( svars );
}
------------------------------------------------------------------------------
New Year. New Location. New Benefits. New Data Center in Ashburn, VA.
GigeNET is offering a free month of service with a new server in Ashburn.
Choose from 2 high performing configs, both with 100TB of bandwidth.
Higher redundancy.Lower latency.Increased capacity.Completely compliant.
http://p.sf.net/sfu/gigenet
_______________________________________________
isync-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/isync-devel