add support for propagating folder deletions
This commit is contained in:
parent
a7eddc6ede
commit
d9a983add6
2
NEWS
2
NEWS
|
@ -12,6 +12,8 @@ Support for Windows file systems has been added.
|
||||||
|
|
||||||
Support for compressed data transfer has been added.
|
Support for compressed data transfer has been added.
|
||||||
|
|
||||||
|
Folder deletions can be propagated now.
|
||||||
|
|
||||||
[1.1.0]
|
[1.1.0]
|
||||||
|
|
||||||
Support for hierarchical mailboxes in Patterns.
|
Support for hierarchical mailboxes in Patterns.
|
||||||
|
|
2
TODO
2
TODO
|
@ -56,8 +56,6 @@ create dummies describing MIME structure of messages bigger than MaxSize.
|
||||||
flagging the dummy would fetch the real message. possibly remove --renew.
|
flagging the dummy would fetch the real message. possibly remove --renew.
|
||||||
note that all interaction needs to happen on the slave side probably.
|
note that all interaction needs to happen on the slave side probably.
|
||||||
|
|
||||||
propagate folder deletions. for safety, the target must be empty.
|
|
||||||
|
|
||||||
don't SELECT boxes unless really needed; in particular not for appending,
|
don't SELECT boxes unless really needed; in particular not for appending,
|
||||||
and in write-only mode not before changes are made.
|
and in write-only mode not before changes are made.
|
||||||
problem: UIDVALIDITY change detection is delayed, significantly complicating
|
problem: UIDVALIDITY change detection is delayed, significantly complicating
|
||||||
|
|
|
@ -149,6 +149,7 @@ static const struct {
|
||||||
} boxOps[] = {
|
} boxOps[] = {
|
||||||
{ OP_EXPUNGE, "Expunge" },
|
{ OP_EXPUNGE, "Expunge" },
|
||||||
{ OP_CREATE, "Create" },
|
{ OP_CREATE, "Create" },
|
||||||
|
{ OP_REMOVE, "Remove" },
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|
13
src/driver.h
13
src/driver.h
|
@ -174,6 +174,19 @@ struct driver {
|
||||||
void (*open_box)( store_t *ctx,
|
void (*open_box)( store_t *ctx,
|
||||||
void (*cb)( int sts, void *aux ), void *aux );
|
void (*cb)( int sts, void *aux ), void *aux );
|
||||||
|
|
||||||
|
/* Confirm that the open mailbox is empty. */
|
||||||
|
int (*confirm_box_empty)( store_t *ctx );
|
||||||
|
|
||||||
|
/* Delete the open mailbox. The mailbox is expected to be empty.
|
||||||
|
* Subfolders of the mailbox are *not* deleted.
|
||||||
|
* Some artifacts of the mailbox may remain, but they won't be
|
||||||
|
* recognized as a mailbox any more. */
|
||||||
|
void (*delete_box)( store_t *ctx,
|
||||||
|
void (*cb)( int sts, void *aux ), void *aux );
|
||||||
|
|
||||||
|
/* Remove the last artifacts of the open mailbox, as far as possible. */
|
||||||
|
int (*finish_delete_box)( store_t *ctx );
|
||||||
|
|
||||||
/* Invoked before load_box(), this informs the driver which operations (OP_*)
|
/* Invoked before load_box(), this informs the driver which operations (OP_*)
|
||||||
* will be performed on the mailbox. The driver may extend the set by implicitly
|
* will be performed on the mailbox. The driver may extend the set by implicitly
|
||||||
* needed or available operations. */
|
* needed or available operations. */
|
||||||
|
|
|
@ -2166,6 +2166,55 @@ imap_create_box( store_t *gctx,
|
||||||
free( buf );
|
free( buf );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************* imap_delete_box *******************/
|
||||||
|
|
||||||
|
static int
|
||||||
|
imap_confirm_box_empty( store_t *gctx )
|
||||||
|
{
|
||||||
|
return gctx->count ? DRV_BOX_BAD : DRV_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void imap_delete_box_p2( imap_store_t *, struct imap_cmd *, int );
|
||||||
|
|
||||||
|
static void
|
||||||
|
imap_delete_box( store_t *gctx,
|
||||||
|
void (*cb)( int sts, void *aux ), void *aux )
|
||||||
|
{
|
||||||
|
imap_store_t *ctx = (imap_store_t *)gctx;
|
||||||
|
struct imap_cmd_simple *cmd;
|
||||||
|
|
||||||
|
INIT_IMAP_CMD(imap_cmd_simple, cmd, cb, aux)
|
||||||
|
imap_exec( ctx, &cmd->gen, imap_delete_box_p2, "CLOSE" );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
imap_delete_box_p2( imap_store_t *ctx, struct imap_cmd *gcmd, int response )
|
||||||
|
{
|
||||||
|
struct imap_cmd_simple *cmdp = (struct imap_cmd_simple *)gcmd;
|
||||||
|
struct imap_cmd_simple *cmd;
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
if (response != RESP_OK) {
|
||||||
|
imap_done_simple_box( ctx, &cmdp->gen, response );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prepare_box( &buf, ctx ) < 0) {
|
||||||
|
imap_done_simple_box( ctx, &cmdp->gen, RESP_NO );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
INIT_IMAP_CMD(imap_cmd_simple, cmd, cmdp->callback, cmdp->callback_aux)
|
||||||
|
imap_exec( ctx, &cmd->gen, imap_done_simple_box,
|
||||||
|
"DELETE \"%\\s\"", buf );
|
||||||
|
free( buf );
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
imap_finish_delete_box( store_t *gctx ATTR_UNUSED )
|
||||||
|
{
|
||||||
|
return DRV_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/******************* imap_load_box *******************/
|
/******************* imap_load_box *******************/
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -2810,6 +2859,9 @@ struct driver imap_driver = {
|
||||||
imap_select_box,
|
imap_select_box,
|
||||||
imap_create_box,
|
imap_create_box,
|
||||||
imap_open_box,
|
imap_open_box,
|
||||||
|
imap_confirm_box_empty,
|
||||||
|
imap_delete_box,
|
||||||
|
imap_finish_delete_box,
|
||||||
imap_prepare_load_box,
|
imap_prepare_load_box,
|
||||||
imap_load_box,
|
imap_load_box,
|
||||||
imap_fetch_msg,
|
imap_fetch_msg,
|
||||||
|
|
|
@ -1076,6 +1076,73 @@ maildir_create_box( store_t *gctx,
|
||||||
cb( maildir_validate( gctx->path, 1, (maildir_store_t *)gctx ), aux );
|
cb( maildir_validate( gctx->path, 1, (maildir_store_t *)gctx ), aux );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
maildir_confirm_box_empty( store_t *gctx )
|
||||||
|
{
|
||||||
|
maildir_store_t *ctx = (maildir_store_t *)gctx;
|
||||||
|
msglist_t msglist;
|
||||||
|
|
||||||
|
ctx->nexcs = ctx->minuid = ctx->maxuid = ctx->newuid = 0;
|
||||||
|
|
||||||
|
if (maildir_scan( ctx, &msglist ) != DRV_OK)
|
||||||
|
return DRV_BOX_BAD;
|
||||||
|
maildir_free_scan( &msglist );
|
||||||
|
return gctx->count ? DRV_BOX_BAD : DRV_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
maildir_delete_box( store_t *gctx,
|
||||||
|
void (*cb)( int sts, void *aux ), void *aux )
|
||||||
|
{
|
||||||
|
int i, bl, ret = DRV_OK;
|
||||||
|
struct stat st;
|
||||||
|
char buf[_POSIX_PATH_MAX];
|
||||||
|
|
||||||
|
bl = nfsnprintf( buf, sizeof(buf) - 4, "%s/", gctx->path );
|
||||||
|
if (stat( buf, &st )) {
|
||||||
|
if (errno != ENOENT) {
|
||||||
|
sys_error( "Maildir error: cannot access mailbox '%s'", gctx->path );
|
||||||
|
ret = DRV_BOX_BAD;
|
||||||
|
}
|
||||||
|
} else if (!S_ISDIR(st.st_mode)) {
|
||||||
|
error( "Maildir error: '%s' is no valid mailbox\n", gctx->path );
|
||||||
|
ret = DRV_BOX_BAD;
|
||||||
|
} else if ((ret = maildir_clear_tmp( buf, sizeof(buf), bl )) == DRV_OK) {
|
||||||
|
nfsnprintf( buf + bl, sizeof(buf) - bl, ".uidvalidity" );
|
||||||
|
if (unlink( buf ) && errno != ENOENT)
|
||||||
|
goto badrm;
|
||||||
|
#ifdef USE_DB
|
||||||
|
nfsnprintf( buf + bl, sizeof(buf) - bl, ".isyncuidmap.db" );
|
||||||
|
if (unlink( buf ) && errno != ENOENT)
|
||||||
|
goto badrm;
|
||||||
|
#endif
|
||||||
|
/* We delete cur/ last, as it is the indicator for a present mailbox.
|
||||||
|
* That way an interrupted operation can be resumed. */
|
||||||
|
for (i = 3; --i >= 0; ) {
|
||||||
|
memcpy( buf + bl, subdirs[i], 4 );
|
||||||
|
if (rmdir( buf ) && errno != ENOENT) {
|
||||||
|
badrm:
|
||||||
|
sys_error( "Maildir error: cannot remove '%s'", buf );
|
||||||
|
ret = DRV_BOX_BAD;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cb( ret, aux );
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
maildir_finish_delete_box( store_t *gctx )
|
||||||
|
{
|
||||||
|
/* Subfolders are not deleted; the deleted folder is only "stripped of its mailboxness".
|
||||||
|
* Consequently, the rmdir may legitimately fail. This behavior follows the IMAP spec. */
|
||||||
|
if (rmdir( gctx->path ) && errno != ENOENT && errno != ENOTEMPTY) {
|
||||||
|
sys_error( "Maildir warning: cannot remove '%s'", gctx->path );
|
||||||
|
return DRV_BOX_BAD;
|
||||||
|
}
|
||||||
|
return DRV_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
maildir_prepare_load_box( store_t *gctx, int opts )
|
maildir_prepare_load_box( store_t *gctx, int opts )
|
||||||
{
|
{
|
||||||
|
@ -1565,6 +1632,9 @@ struct driver maildir_driver = {
|
||||||
maildir_select_box,
|
maildir_select_box,
|
||||||
maildir_create_box,
|
maildir_create_box,
|
||||||
maildir_open_box,
|
maildir_open_box,
|
||||||
|
maildir_confirm_box_empty,
|
||||||
|
maildir_delete_box,
|
||||||
|
maildir_finish_delete_box,
|
||||||
maildir_prepare_load_box,
|
maildir_prepare_load_box,
|
||||||
maildir_load_box,
|
maildir_load_box,
|
||||||
maildir_fetch_msg,
|
maildir_fetch_msg,
|
||||||
|
|
18
src/main.c
18
src/main.c
|
@ -299,7 +299,11 @@ main( int argc, char **argv )
|
||||||
mvars->ops[S] |= op;
|
mvars->ops[S] |= op;
|
||||||
else
|
else
|
||||||
goto badopt;
|
goto badopt;
|
||||||
mvars->ops[M] |= op & (XOP_HAVE_CREATE|XOP_HAVE_EXPUNGE);
|
mvars->ops[M] |= op & (XOP_HAVE_CREATE|XOP_HAVE_REMOVE|XOP_HAVE_EXPUNGE);
|
||||||
|
} else if (starts_with( opt, -1, "remove", 6 )) {
|
||||||
|
opt += 6;
|
||||||
|
op = OP_REMOVE|XOP_HAVE_REMOVE;
|
||||||
|
goto lcop;
|
||||||
} else if (starts_with( opt, -1, "expunge", 7 )) {
|
} else if (starts_with( opt, -1, "expunge", 7 )) {
|
||||||
opt += 7;
|
opt += 7;
|
||||||
op = OP_EXPUNGE|XOP_HAVE_EXPUNGE;
|
op = OP_EXPUNGE|XOP_HAVE_EXPUNGE;
|
||||||
|
@ -308,6 +312,8 @@ main( int argc, char **argv )
|
||||||
mvars->ops[M] |= XOP_HAVE_EXPUNGE;
|
mvars->ops[M] |= XOP_HAVE_EXPUNGE;
|
||||||
else if (!strcmp( opt, "no-create" ))
|
else if (!strcmp( opt, "no-create" ))
|
||||||
mvars->ops[M] |= XOP_HAVE_CREATE;
|
mvars->ops[M] |= XOP_HAVE_CREATE;
|
||||||
|
else if (!strcmp( opt, "no-remove" ))
|
||||||
|
mvars->ops[M] |= XOP_HAVE_REMOVE;
|
||||||
else if (!strcmp( opt, "full" ))
|
else if (!strcmp( opt, "full" ))
|
||||||
mvars->ops[M] |= XOP_HAVE_TYPE|XOP_PULL|XOP_PUSH;
|
mvars->ops[M] |= XOP_HAVE_TYPE|XOP_PULL|XOP_PUSH;
|
||||||
else if (!strcmp( opt, "noop" ))
|
else if (!strcmp( opt, "noop" ))
|
||||||
|
@ -386,8 +392,11 @@ main( int argc, char **argv )
|
||||||
ochar++;
|
ochar++;
|
||||||
else
|
else
|
||||||
cops |= op;
|
cops |= op;
|
||||||
mvars->ops[M] |= op & (XOP_HAVE_CREATE|XOP_HAVE_EXPUNGE);
|
mvars->ops[M] |= op & (XOP_HAVE_CREATE|XOP_HAVE_REMOVE|XOP_HAVE_EXPUNGE);
|
||||||
break;
|
break;
|
||||||
|
case 'R':
|
||||||
|
op = OP_REMOVE|XOP_HAVE_REMOVE;
|
||||||
|
goto cop;
|
||||||
case 'X':
|
case 'X':
|
||||||
op = OP_EXPUNGE|XOP_HAVE_EXPUNGE;
|
op = OP_EXPUNGE|XOP_HAVE_EXPUNGE;
|
||||||
goto cop;
|
goto cop;
|
||||||
|
@ -589,6 +598,7 @@ sync_chans( main_vars_t *mvars, int ent )
|
||||||
}
|
}
|
||||||
merge_actions( mvars->chan, mvars->ops, XOP_HAVE_TYPE, OP_MASK_TYPE, OP_MASK_TYPE );
|
merge_actions( mvars->chan, mvars->ops, XOP_HAVE_TYPE, OP_MASK_TYPE, OP_MASK_TYPE );
|
||||||
merge_actions( mvars->chan, mvars->ops, XOP_HAVE_CREATE, OP_CREATE, 0 );
|
merge_actions( mvars->chan, mvars->ops, XOP_HAVE_CREATE, OP_CREATE, 0 );
|
||||||
|
merge_actions( mvars->chan, mvars->ops, XOP_HAVE_REMOVE, OP_REMOVE, 0 );
|
||||||
merge_actions( mvars->chan, mvars->ops, XOP_HAVE_EXPUNGE, OP_EXPUNGE, 0 );
|
merge_actions( mvars->chan, mvars->ops, XOP_HAVE_EXPUNGE, OP_EXPUNGE, 0 );
|
||||||
|
|
||||||
mvars->state[M] = mvars->state[S] = ST_FRESH;
|
mvars->state[M] = mvars->state[S] = ST_FRESH;
|
||||||
|
@ -652,12 +662,8 @@ sync_chans( main_vars_t *mvars, int ent )
|
||||||
present[t] = BOX_PRESENT;
|
present[t] = BOX_PRESENT;
|
||||||
present[1-t] = BOX_ABSENT;
|
present[1-t] = BOX_ABSENT;
|
||||||
mvars->boxes[t] = mbox->next;
|
mvars->boxes[t] = mbox->next;
|
||||||
if ((mvars->chan->ops[1-t] & OP_MASK_TYPE) && (mvars->chan->ops[1-t] & OP_CREATE)) {
|
|
||||||
if (sync_listed_boxes( mvars, mbox, present ))
|
if (sync_listed_boxes( mvars, mbox, present ))
|
||||||
goto syncw;
|
goto syncw;
|
||||||
} else {
|
|
||||||
free( mbox );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!mvars->list) {
|
if (!mvars->list) {
|
||||||
|
|
20
src/mbsync.1
20
src/mbsync.1
|
@ -58,6 +58,9 @@ and exit.
|
||||||
\fB-C\fR[\fBm\fR][\fBs\fR], \fB--create\fR[\fB-master\fR|\fB-slave\fR]
|
\fB-C\fR[\fBm\fR][\fBs\fR], \fB--create\fR[\fB-master\fR|\fB-slave\fR]
|
||||||
Override any \fBCreate\fR options from the config file. See below.
|
Override any \fBCreate\fR options from the config file. See below.
|
||||||
.TP
|
.TP
|
||||||
|
\fB-R\fR[\fBm\fR][\fBs\fR], \fB--remove\fR[\fB-master\fR|\fB-slave\fR]
|
||||||
|
Override any \fBRemove\fR options from the config file. See below.
|
||||||
|
.TP
|
||||||
\fB-X\fR[\fBm\fR][\fBs\fR], \fB--expunge\fR[\fB-master\fR|\fB-slave\fR]
|
\fB-X\fR[\fBm\fR][\fBs\fR], \fB--expunge\fR[\fB-master\fR|\fB-slave\fR]
|
||||||
Override any \fBExpunge\fR options from the config file. See below.
|
Override any \fBExpunge\fR options from the config file. See below.
|
||||||
.TP
|
.TP
|
||||||
|
@ -483,7 +486,20 @@ Note that it is not allowed to assert a cell in two ways, e.g.
|
||||||
\fBCreate\fR {\fINone\fR|\fIMaster\fR|\fISlave\fR|\fIBoth\fR}
|
\fBCreate\fR {\fINone\fR|\fIMaster\fR|\fISlave\fR|\fIBoth\fR}
|
||||||
Automatically create missing mailboxes [on the Master/Slave].
|
Automatically create missing mailboxes [on the Master/Slave].
|
||||||
Otherwise print an error message and skip that mailbox pair if a mailbox
|
Otherwise print an error message and skip that mailbox pair if a mailbox
|
||||||
does not exist.
|
and the corresponding sync state does not exist.
|
||||||
|
(Global default: \fINone\fR)
|
||||||
|
..
|
||||||
|
.TP
|
||||||
|
\fBRemove\fR {\fINone\fR|\fIMaster\fR|\fISlave\fR|\fIBoth\fR}
|
||||||
|
Propagate mailbox deletions [to the Master/Slave].
|
||||||
|
Otherwise print an error message and skip that mailbox pair if a mailbox
|
||||||
|
does not exist but the corresponding sync state does.
|
||||||
|
.br
|
||||||
|
For MailDir mailboxes it is sufficient to delete the cur/ subdirectory to
|
||||||
|
mark them as deleted. This ensures compatibility with \fBSyncState *\fR.
|
||||||
|
.br
|
||||||
|
Note that for safety, non-empty mailboxes are never deleted.
|
||||||
|
.br
|
||||||
(Global default: \fINone\fR)
|
(Global default: \fINone\fR)
|
||||||
..
|
..
|
||||||
.TP
|
.TP
|
||||||
|
@ -503,7 +519,7 @@ date\fR) is actually the arrival time, but it is usually close enough.
|
||||||
(Default: \fIno\fR)
|
(Default: \fIno\fR)
|
||||||
..
|
..
|
||||||
.P
|
.P
|
||||||
\fBSync\fR, \fBCreate\fR, \fBExpunge\fR,
|
\fBSync\fR, \fBCreate\fR, \fBRemove\fR, \fBExpunge\fR,
|
||||||
\fBMaxMessages\fR, and \fBCopyArrivalDate\fR
|
\fBMaxMessages\fR, and \fBCopyArrivalDate\fR
|
||||||
can be used before any section for a global effect.
|
can be used before any section for a global effect.
|
||||||
The global settings are overridden by Channel-specific options,
|
The global settings are overridden by Channel-specific options,
|
||||||
|
|
85
src/sync.c
85
src/sync.c
|
@ -205,6 +205,8 @@ static int check_cancel( sync_vars_t *svars );
|
||||||
#define ST_SELECTED (1<<10)
|
#define ST_SELECTED (1<<10)
|
||||||
#define ST_DID_EXPUNGE (1<<11)
|
#define ST_DID_EXPUNGE (1<<11)
|
||||||
#define ST_CLOSING (1<<12)
|
#define ST_CLOSING (1<<12)
|
||||||
|
#define ST_CONFIRMED (1<<13)
|
||||||
|
#define ST_PRESENT (1<<14)
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -923,7 +925,20 @@ load_state( sync_vars_t *svars )
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
delete_state( sync_vars_t *svars )
|
||||||
|
{
|
||||||
|
unlink( svars->nname );
|
||||||
|
unlink( svars->jname );
|
||||||
|
if (unlink( svars->dname ) || unlink( svars->lname )) {
|
||||||
|
sys_error( "Error: channel %s: sync state cannot be deleted", svars->chan->name );
|
||||||
|
svars->ret = SYNC_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void box_confirmed( int sts, void *aux );
|
static void box_confirmed( int sts, void *aux );
|
||||||
|
static void box_confirmed2( sync_vars_t *svars, int t );
|
||||||
|
static void box_deleted( int sts, void *aux );
|
||||||
static void box_created( int sts, void *aux );
|
static void box_created( int sts, void *aux );
|
||||||
static void box_opened( int sts, void *aux );
|
static void box_opened( int sts, void *aux );
|
||||||
static void box_opened2( sync_vars_t *svars, int t );
|
static void box_opened2( sync_vars_t *svars, int t );
|
||||||
|
@ -988,7 +1003,7 @@ sync_boxes( store_t *ctx[], const char *names[], int present[], channel_conf_t *
|
||||||
for (t = 0; ; t++) {
|
for (t = 0; ; t++) {
|
||||||
info( "Opening %s box %s...\n", str_ms[t], svars->orig_name[t] );
|
info( "Opening %s box %s...\n", str_ms[t], svars->orig_name[t] );
|
||||||
if (present[t] == BOX_ABSENT)
|
if (present[t] == BOX_ABSENT)
|
||||||
box_confirmed( DRV_BOX_BAD, AUX );
|
box_confirmed2( svars, t );
|
||||||
else
|
else
|
||||||
svars->drv[t]->open_box( ctx[t], box_confirmed, AUX );
|
svars->drv[t]->open_box( ctx[t], box_confirmed, AUX );
|
||||||
if (t || check_cancel( svars ))
|
if (t || check_cancel( svars ))
|
||||||
|
@ -1008,16 +1023,80 @@ box_confirmed( int sts, void *aux )
|
||||||
if (check_cancel( svars ))
|
if (check_cancel( svars ))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (sts == DRV_BOX_BAD) {
|
if (sts == DRV_OK)
|
||||||
|
svars->state[t] |= ST_PRESENT;
|
||||||
|
box_confirmed2( svars, t );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
box_confirmed2( sync_vars_t *svars, int t )
|
||||||
|
{
|
||||||
|
svars->state[t] |= ST_CONFIRMED;
|
||||||
|
if (!(svars->state[1-t] & ST_CONFIRMED))
|
||||||
|
return;
|
||||||
|
|
||||||
|
sync_ref( svars );
|
||||||
|
for (t = 0; ; t++) {
|
||||||
|
if (!(svars->state[t] & ST_PRESENT)) {
|
||||||
|
if (!(svars->state[1-t] & ST_PRESENT)) {
|
||||||
|
if (!svars->existing) {
|
||||||
|
error( "Error: channel %s: both master %s and slave %s cannot be opened.\n",
|
||||||
|
svars->chan->name, svars->orig_name[M], svars->orig_name[S] );
|
||||||
|
bail:
|
||||||
|
svars->ret = SYNC_FAIL;
|
||||||
|
} else {
|
||||||
|
/* This can legitimately happen if a deletion propagation was interrupted.
|
||||||
|
* We have no place to record this transaction, so we just assume it.
|
||||||
|
* Of course this bears the danger of clearing the state if both mailboxes
|
||||||
|
* temorarily cannot be opened for some weird reason (while the stores can). */
|
||||||
|
delete_state( svars );
|
||||||
|
}
|
||||||
|
done:
|
||||||
|
sync_bail( svars );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (svars->existing) {
|
||||||
|
if (!(svars->chan->ops[1-t] & OP_REMOVE)) {
|
||||||
|
error( "Error: channel %s: %s %s cannot be opened.\n",
|
||||||
|
svars->chan->name, str_ms[t], svars->orig_name[t] );
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
if (svars->drv[1-t]->confirm_box_empty( svars->ctx[1-t] ) != DRV_OK) {
|
||||||
|
warn( "Warning: channel %s: %s %s cannot be opened and %s %s not empty.\n",
|
||||||
|
svars->chan->name, str_ms[t], svars->orig_name[t], str_ms[1-t], svars->orig_name[1-t] );
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
info( "Deleting %s %s...\n", str_ms[1-t], svars->orig_name[1-t] );
|
||||||
|
svars->drv[1-t]->delete_box( svars->ctx[1-t], box_deleted, INV_AUX );
|
||||||
|
} else {
|
||||||
if (!(svars->chan->ops[t] & OP_CREATE)) {
|
if (!(svars->chan->ops[t] & OP_CREATE)) {
|
||||||
box_opened( sts, aux );
|
box_opened( DRV_BOX_BAD, AUX );
|
||||||
} else {
|
} else {
|
||||||
info( "Creating %s %s...\n", str_ms[t], svars->orig_name[t] );
|
info( "Creating %s %s...\n", str_ms[t], svars->orig_name[t] );
|
||||||
svars->drv[t]->create_box( svars->ctx[t], box_created, AUX );
|
svars->drv[t]->create_box( svars->ctx[t], box_created, AUX );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
box_opened2( svars, t );
|
box_opened2( svars, t );
|
||||||
}
|
}
|
||||||
|
if (t || check_cancel( svars ))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sync_deref( svars );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
box_deleted( int sts, void *aux )
|
||||||
|
{
|
||||||
|
DECL_SVARS;
|
||||||
|
|
||||||
|
if (check_ret( sts, aux ))
|
||||||
|
return;
|
||||||
|
INIT_SVARS(aux);
|
||||||
|
|
||||||
|
delete_state( svars );
|
||||||
|
svars->drv[t]->finish_delete_box( svars->ctx[t] );
|
||||||
|
sync_bail( svars );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
12
src/sync.h
12
src/sync.h
|
@ -35,12 +35,14 @@
|
||||||
#define OP_MASK_TYPE (OP_NEW|OP_RENEW|OP_DELETE|OP_FLAGS) /* asserted in the target ops */
|
#define OP_MASK_TYPE (OP_NEW|OP_RENEW|OP_DELETE|OP_FLAGS) /* asserted in the target ops */
|
||||||
#define OP_EXPUNGE (1<<4)
|
#define OP_EXPUNGE (1<<4)
|
||||||
#define OP_CREATE (1<<5)
|
#define OP_CREATE (1<<5)
|
||||||
#define XOP_PUSH (1<<6)
|
#define OP_REMOVE (1<<6)
|
||||||
#define XOP_PULL (1<<7)
|
#define XOP_PUSH (1<<8)
|
||||||
|
#define XOP_PULL (1<<9)
|
||||||
#define XOP_MASK_DIR (XOP_PUSH|XOP_PULL)
|
#define XOP_MASK_DIR (XOP_PUSH|XOP_PULL)
|
||||||
#define XOP_HAVE_TYPE (1<<8)
|
#define XOP_HAVE_TYPE (1<<10)
|
||||||
#define XOP_HAVE_EXPUNGE (1<<9)
|
#define XOP_HAVE_EXPUNGE (1<<11)
|
||||||
#define XOP_HAVE_CREATE (1<<10)
|
#define XOP_HAVE_CREATE (1<<12)
|
||||||
|
#define XOP_HAVE_REMOVE (1<<13)
|
||||||
|
|
||||||
typedef struct channel_conf {
|
typedef struct channel_conf {
|
||||||
struct channel_conf *next;
|
struct channel_conf *next;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user