deal sensibly with incomplete maildir directories
a directory is no mailbox unless it contains a cur/ subdir. but if that one is present, create new/ and tmp/ if they are missing. this makes it possible to resume interrupted maildir creations.
This commit is contained in:
parent
5f4e3b285e
commit
7489ff8613
|
@ -68,7 +68,7 @@ typedef struct maildir_message {
|
||||||
|
|
||||||
typedef struct maildir_store {
|
typedef struct maildir_store {
|
||||||
store_t gen;
|
store_t gen;
|
||||||
int uvfd, uvok, nuid, fresh;
|
int uvfd, uvok, nuid, fresh[3];
|
||||||
int minuid, maxuid, newuid, nexcs, *excs;
|
int minuid, maxuid, newuid, nexcs, *excs;
|
||||||
char *trash;
|
char *trash;
|
||||||
#ifdef USE_DB
|
#ifdef USE_DB
|
||||||
|
@ -378,8 +378,12 @@ maildir_validate( const char *box, int create, maildir_store_t *ctx )
|
||||||
|
|
||||||
bl = nfsnprintf( buf, sizeof(buf) - 4, "%s/", box );
|
bl = nfsnprintf( buf, sizeof(buf) - 4, "%s/", box );
|
||||||
if (stat( buf, &st )) {
|
if (stat( buf, &st )) {
|
||||||
if (errno == ENOENT) {
|
if (errno != ENOENT) {
|
||||||
if (create) {
|
sys_error( "Maildir error: cannot access mailbox '%s'", box );
|
||||||
|
return DRV_BOX_BAD;
|
||||||
|
}
|
||||||
|
if (!create)
|
||||||
|
return DRV_BOX_BAD;
|
||||||
p = memrchr( buf, '/', bl - 1 );
|
p = memrchr( buf, '/', bl - 1 );
|
||||||
if (*(p + 1) == '.') {
|
if (*(p + 1) == '.') {
|
||||||
*p = 0;
|
*p = 0;
|
||||||
|
@ -388,37 +392,34 @@ maildir_validate( const char *box, int create, maildir_store_t *ctx )
|
||||||
*p = '/';
|
*p = '/';
|
||||||
}
|
}
|
||||||
if (mkdir( buf, 0700 )) {
|
if (mkdir( buf, 0700 )) {
|
||||||
sys_error( "Maildir error: cannot create mailbox '%s'", buf );
|
sys_error( "Maildir error: cannot create mailbox '%s'", box );
|
||||||
maildir_invoke_bad_callback( &ctx->gen );
|
maildir_invoke_bad_callback( &ctx->gen );
|
||||||
return DRV_CANCELED;
|
return DRV_CANCELED;
|
||||||
}
|
}
|
||||||
|
} else if (!S_ISDIR(st.st_mode)) {
|
||||||
|
notdir:
|
||||||
|
error( "Maildir error: '%s' is no valid mailbox\n", box );
|
||||||
|
return DRV_BOX_BAD;
|
||||||
|
}
|
||||||
for (i = 0; i < 3; i++) {
|
for (i = 0; i < 3; i++) {
|
||||||
memcpy( buf + bl, subdirs[i], 4 );
|
memcpy( buf + bl, subdirs[i], 4 );
|
||||||
|
if (stat( buf, &st )) {
|
||||||
|
/* We always create new/ and tmp/ if they are missing. cur/ is the presence indicator. */
|
||||||
|
if (!i && !create)
|
||||||
|
return DRV_BOX_BAD;
|
||||||
if (mkdir( buf, 0700 )) {
|
if (mkdir( buf, 0700 )) {
|
||||||
sys_error( "Maildir error: cannot create directory %s", buf );
|
sys_error( "Maildir error: cannot create directory %s", buf );
|
||||||
return DRV_BOX_BAD;
|
return DRV_BOX_BAD;
|
||||||
}
|
}
|
||||||
}
|
ctx->fresh[i] = 1;
|
||||||
|
} else if (!S_ISDIR(st.st_mode)) {
|
||||||
|
goto notdir;
|
||||||
} else {
|
} else {
|
||||||
error( "Maildir error: mailbox '%s' does not exist\n", buf );
|
if (i == 2) {
|
||||||
return DRV_BOX_BAD;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sys_error( "Maildir error: cannot access mailbox '%s'", buf );
|
|
||||||
return DRV_BOX_BAD;
|
|
||||||
}
|
|
||||||
ctx->fresh = 1;
|
|
||||||
} else {
|
|
||||||
for (i = 0; i < 3; i++) {
|
|
||||||
memcpy( buf + bl, subdirs[i], 4 );
|
|
||||||
if (stat( buf, &st ) || !S_ISDIR(st.st_mode)) {
|
|
||||||
error( "Maildir error: '%.*s' is no valid mailbox\n", bl, buf );
|
|
||||||
return DRV_BOX_BAD;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((ret = maildir_clear_tmp( buf, sizeof(buf), bl )) != DRV_OK)
|
if ((ret = maildir_clear_tmp( buf, sizeof(buf), bl )) != DRV_OK)
|
||||||
return ret;
|
return ret;
|
||||||
ctx->fresh = 0;
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return DRV_OK;
|
return DRV_OK;
|
||||||
}
|
}
|
||||||
|
@ -676,7 +677,7 @@ maildir_scan( maildir_store_t *ctx, msglist_t *msglist )
|
||||||
sys_error( "Maildir error: cannot stat %s", buf );
|
sys_error( "Maildir error: cannot stat %s", buf );
|
||||||
goto dfail;
|
goto dfail;
|
||||||
}
|
}
|
||||||
if (st.st_mtime == now && !(DFlags & ZERODELAY)) {
|
if (st.st_mtime == now && !(DFlags & ZERODELAY) && !ctx->fresh[i]) {
|
||||||
/* If the modification happened during this second, we wouldn't be able to
|
/* If the modification happened during this second, we wouldn't be able to
|
||||||
* tell if there were further modifications during this second. So wait.
|
* tell if there were further modifications during this second. So wait.
|
||||||
* This has the nice side effect that we wait for "batches" of changes to
|
* This has the nice side effect that we wait for "batches" of changes to
|
||||||
|
@ -948,6 +949,7 @@ maildir_select_box( store_t *gctx, const char *name )
|
||||||
#ifdef USE_DB
|
#ifdef USE_DB
|
||||||
ctx->db = 0;
|
ctx->db = 0;
|
||||||
#endif /* USE_DB */
|
#endif /* USE_DB */
|
||||||
|
ctx->fresh[0] = ctx->fresh[1] = 0;
|
||||||
if (starts_with( name, -1, "INBOX", 5 ) && (!name[5] || name[5] == '/')) {
|
if (starts_with( name, -1, "INBOX", 5 ) && (!name[5] || name[5] == '/')) {
|
||||||
gctx->path = maildir_join_path( ((maildir_store_conf_t *)gctx->conf)->inbox, name + 5 );
|
gctx->path = maildir_join_path( ((maildir_store_conf_t *)gctx->conf)->inbox, name + 5 );
|
||||||
} else {
|
} else {
|
||||||
|
@ -1088,11 +1090,6 @@ maildir_load_box( store_t *gctx, int minuid, int maxuid, int newuid, int *excs,
|
||||||
ctx->excs = nfrealloc( excs, nexcs * sizeof(int) );
|
ctx->excs = nfrealloc( excs, nexcs * sizeof(int) );
|
||||||
ctx->nexcs = nexcs;
|
ctx->nexcs = nexcs;
|
||||||
|
|
||||||
if (ctx->fresh) {
|
|
||||||
ctx->gen.count = ctx->gen.recent = 0;
|
|
||||||
goto dontscan;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (maildir_scan( ctx, &msglist ) != DRV_OK) {
|
if (maildir_scan( ctx, &msglist ) != DRV_OK) {
|
||||||
cb( DRV_BOX_BAD, aux );
|
cb( DRV_BOX_BAD, aux );
|
||||||
return;
|
return;
|
||||||
|
@ -1102,7 +1099,6 @@ maildir_load_box( store_t *gctx, int minuid, int maxuid, int newuid, int *excs,
|
||||||
maildir_app_msg( ctx, &msgapp, msglist.ents + i );
|
maildir_app_msg( ctx, &msgapp, msglist.ents + i );
|
||||||
maildir_free_scan( &msglist );
|
maildir_free_scan( &msglist );
|
||||||
|
|
||||||
dontscan:
|
|
||||||
cb( DRV_OK, aux );
|
cb( DRV_OK, aux );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1114,6 +1110,7 @@ maildir_rescan( maildir_store_t *ctx )
|
||||||
msglist_t msglist;
|
msglist_t msglist;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
ctx->fresh[0] = ctx->fresh[1] = 0;
|
||||||
if (maildir_scan( ctx, &msglist ) != DRV_OK)
|
if (maildir_scan( ctx, &msglist ) != DRV_OK)
|
||||||
return DRV_BOX_BAD;
|
return DRV_BOX_BAD;
|
||||||
for (msgapp = &ctx->gen.msgs, i = 0;
|
for (msgapp = &ctx->gen.msgs, i = 0;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user