Browse Source

abstract growable arrays somewhat

... and sneak in a C99 requirement on the way. just because.
wip/uidval-recovery
Oswald Buddenhagen 8 years ago
parent
commit
7b567164ff
  1. 4
      configure.ac
  2. 31
      src/common.h
  3. 2
      src/driver.h
  4. 18
      src/drv_imap.c
  5. 83
      src/drv_maildir.c
  6. 27
      src/sync.c
  7. 4
      src/util.c

4
configure.ac

@ -4,9 +4,9 @@ AM_INIT_AUTOMAKE
AM_MAINTAINER_MODE AM_MAINTAINER_MODE
AC_PROG_CC AC_PROG_CC_C99
if test "$GCC" = yes; then if test "$GCC" = yes; then
CFLAGS="$CFLAGS -pipe -W -Wall -Wshadow -Wstrict-prototypes -ansi -pedantic -Wno-overlength-strings" CFLAGS="$CFLAGS -pipe -W -Wall -Wshadow -Wstrict-prototypes -std=c99 -pedantic -Wno-overlength-strings"
fi fi
CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE"

31
src/common.h

@ -43,10 +43,12 @@ typedef unsigned int uint;
# define ATTR_UNUSED __attribute__((unused)) # define ATTR_UNUSED __attribute__((unused))
# define ATTR_NORETURN __attribute__((noreturn)) # define ATTR_NORETURN __attribute__((noreturn))
# define ATTR_PRINTFLIKE(fmt,var) __attribute__((format(printf,fmt,var))) # define ATTR_PRINTFLIKE(fmt,var) __attribute__((format(printf,fmt,var)))
# define ATTR_PACKED(ref) __attribute__((packed,aligned(sizeof(ref))))
#else #else
# define ATTR_UNUSED # define ATTR_UNUSED
# define ATTR_NORETURN # define ATTR_NORETURN
# define ATTR_PRINTFLIKE(fmt,var) # define ATTR_PRINTFLIKE(fmt,var)
# define ATTR_PACKED(ref)
#endif #endif
#ifdef __GNUC__ #ifdef __GNUC__
@ -137,7 +139,34 @@ char *expand_strdup( const char *s );
int map_name( const char *arg, char **result, int reserve, const char *in, const char *out ); int map_name( const char *arg, char **result, int reserve, const char *in, const char *out );
void sort_ints( int *arr, int len ); #define DEFINE_ARRAY_TYPE(T) \
typedef struct T##_array { \
T *data; \
int size; \
} ATTR_PACKED(T *) T##_array_t; \
typedef struct T##_array_alloc { \
T##_array_t array; \
int alloc; \
} ATTR_PACKED(T *) T##_array_alloc_t; \
static INLINE T *T##_array_append( T##_array_alloc_t *arr ) \
{ \
if (arr->array.size == arr->alloc) { \
arr->alloc = arr->alloc * 2 + 100; \
arr->array.data = nfrealloc( arr->array.data, arr->alloc * sizeof(T) ); \
} \
return &arr->array.data[arr->array.size++]; \
}
#define ARRAY_INIT(arr) \
do { (arr)->array.data = 0; (arr)->array.size = (arr)->alloc = 0; } while (0)
#define ARRAY_SQUEEZE(arr) \
do { \
(arr)->data = nfrealloc( (arr)->data, (arr)->size * sizeof((arr)->data[0]) ); \
} while (0)
DEFINE_ARRAY_TYPE(int)
void sort_int_array( int_array_t array );
void arc4_init( void ); void arc4_init( void );
uchar arc4_getbyte( void ); uchar arc4_getbyte( void );

2
src/driver.h

@ -207,7 +207,7 @@ struct driver {
* and those named in the excs array (smaller than minuid). * and those named in the excs array (smaller than minuid).
* The driver takes ownership of the excs array. Messages below newuid do not need * The driver takes ownership of the excs array. Messages below newuid do not need
* to have the TUID populated even if OPEN_FIND is set. */ * to have the TUID populated even if OPEN_FIND is set. */
void (*load_box)( store_t *ctx, int minuid, int maxuid, int newuid, int *excs, int nexcs, void (*load_box)( store_t *ctx, int minuid, int maxuid, int newuid, int_array_t excs,
void (*cb)( int sts, void *aux ), void *aux ); void (*cb)( int sts, void *aux ), void *aux );
/* Fetch the contents and flags of the given message from the current mailbox. */ /* Fetch the contents and flags of the given message from the current mailbox. */

18
src/drv_imap.c

@ -2292,7 +2292,7 @@ imap_prepare_load_box( store_t *gctx, int opts )
static void imap_submit_load( imap_store_t *, const char *, int, struct imap_cmd_refcounted_state * ); static void imap_submit_load( imap_store_t *, const char *, int, struct imap_cmd_refcounted_state * );
static void static void
imap_load_box( store_t *gctx, int minuid, int maxuid, int newuid, int *excs, int nexcs, imap_load_box( store_t *gctx, int minuid, int maxuid, int newuid, int_array_t excs,
void (*cb)( int sts, void *aux ), void *aux ) void (*cb)( int sts, void *aux ), void *aux )
{ {
imap_store_t *ctx = (imap_store_t *)gctx; imap_store_t *ctx = (imap_store_t *)gctx;
@ -2300,21 +2300,21 @@ imap_load_box( store_t *gctx, int minuid, int maxuid, int newuid, int *excs, int
char buf[1000]; char buf[1000];
if (!ctx->gen.count) { if (!ctx->gen.count) {
free( excs ); free( excs.data );
cb( DRV_OK, aux ); cb( DRV_OK, aux );
} else { } else {
struct imap_cmd_refcounted_state *sts = imap_refcounted_new_state( cb, aux ); struct imap_cmd_refcounted_state *sts = imap_refcounted_new_state( cb, aux );
sort_ints( excs, nexcs ); sort_int_array( excs );
for (i = 0; i < nexcs; ) { for (i = 0; i < excs.size; ) {
for (bl = 0; i < nexcs && bl < 960; i++) { for (bl = 0; i < excs.size && bl < 960; i++) {
if (bl) if (bl)
buf[bl++] = ','; buf[bl++] = ',';
bl += sprintf( buf + bl, "%d", excs[i] ); bl += sprintf( buf + bl, "%d", excs.data[i] );
j = i; j = i;
for (; i + 1 < nexcs && excs[i + 1] == excs[i] + 1; i++) {} for (; i + 1 < excs.size && excs.data[i + 1] == excs.data[i] + 1; i++) {}
if (i != j) if (i != j)
bl += sprintf( buf + bl, ":%d", excs[i] ); bl += sprintf( buf + bl, ":%d", excs.data[i] );
} }
imap_submit_load( ctx, buf, 0, sts ); imap_submit_load( ctx, buf, 0, sts );
} }
@ -2333,7 +2333,7 @@ imap_load_box( store_t *gctx, int minuid, int maxuid, int newuid, int *excs, int
imap_submit_load( ctx, buf, (ctx->gen.opts & OPEN_FIND), sts ); imap_submit_load( ctx, buf, (ctx->gen.opts & OPEN_FIND), sts );
} }
done: done:
free( excs ); free( excs.data );
imap_refcounted_done( sts ); imap_refcounted_done( sts );
} }
} }

83
src/drv_maildir.c

@ -70,7 +70,8 @@ typedef struct maildir_message {
typedef struct maildir_store { typedef struct maildir_store {
store_t gen; store_t gen;
int uvfd, uvok, nuid, is_inbox, fresh[3]; int uvfd, uvok, nuid, is_inbox, fresh[3];
int minuid, maxuid, newuid, nexcs, *excs; int minuid, maxuid, newuid;
int_array_t excs;
char *trash; char *trash;
#ifdef USE_DB #ifdef USE_DB
DB *db; DB *db;
@ -262,7 +263,7 @@ maildir_cleanup( store_t *gctx )
free( ctx->usedb ); free( ctx->usedb );
#endif /* USE_DB */ #endif /* USE_DB */
free( gctx->path ); free( gctx->path );
free( ctx->excs ); free( ctx->excs.data );
if (ctx->uvfd >= 0) if (ctx->uvfd >= 0)
close( ctx->uvfd ); close( ctx->uvfd );
conf_wakeup( &ctx->lcktmr, -1 ); conf_wakeup( &ctx->lcktmr, -1 );
@ -446,20 +447,17 @@ typedef struct {
char tuid[TUIDL]; char tuid[TUIDL];
} msg_t; } msg_t;
typedef struct { DEFINE_ARRAY_TYPE(msg_t)
msg_t *ents;
int nents, nalloc;
} msglist_t;
static void static void
maildir_free_scan( msglist_t *msglist ) maildir_free_scan( msg_t_array_alloc_t *msglist )
{ {
int i; int i;
if (msglist->ents) { if (msglist->array.data) {
for (i = 0; i < msglist->nents; i++) for (i = 0; i < msglist->array.size; i++)
free( msglist->ents[i].base ); free( msglist->array.data[i].base );
free( msglist->ents ); free( msglist->array.data );
} }
} }
@ -821,7 +819,7 @@ maildir_compare( const void *l, const void *r )
} }
static int static int
maildir_scan( maildir_store_t *ctx, msglist_t *msglist ) maildir_scan( maildir_store_t *ctx, msg_t_array_alloc_t *msglist )
{ {
maildir_store_conf_t *conf = (maildir_store_conf_t *)ctx->gen.conf; maildir_store_conf_t *conf = (maildir_store_conf_t *)ctx->gen.conf;
DIR *d; DIR *d;
@ -839,8 +837,7 @@ maildir_scan( maildir_store_t *ctx, msglist_t *msglist )
char buf[_POSIX_PATH_MAX], nbuf[_POSIX_PATH_MAX]; char buf[_POSIX_PATH_MAX], nbuf[_POSIX_PATH_MAX];
again: again:
msglist->ents = 0; ARRAY_INIT( msglist );
msglist->nents = msglist->nalloc = 0;
ctx->gen.count = ctx->gen.recent = 0; ctx->gen.count = ctx->gen.recent = 0;
if (ctx->uvok || ctx->maxuid == INT_MAX) { if (ctx->uvok || ctx->maxuid == INT_MAX) {
#ifdef USE_DB #ifdef USE_DB
@ -926,17 +923,13 @@ maildir_scan( maildir_store_t *ctx, msglist_t *msglist )
} }
if (uid <= ctx->maxuid) { if (uid <= ctx->maxuid) {
if (uid < ctx->minuid) { if (uid < ctx->minuid) {
for (j = 0; j < ctx->nexcs; j++) for (j = 0; j < ctx->excs.size; j++)
if (ctx->excs[j] == uid) if (ctx->excs.data[j] == uid)
goto oke; goto oke;
continue; continue;
oke: ; oke: ;
} }
if (msglist->nalloc == msglist->nents) { entry = msg_t_array_append( msglist );
msglist->nalloc = msglist->nalloc * 2 + 100;
msglist->ents = nfrealloc( msglist->ents, msglist->nalloc * sizeof(msg_t) );
}
entry = &msglist->ents[msglist->nents++];
entry->base = nfstrdup( e->d_name ); entry->base = nfstrdup( e->d_name );
entry->uid = uid; entry->uid = uid;
entry->recent = i; entry->recent = i;
@ -992,9 +985,9 @@ maildir_scan( maildir_store_t *ctx, msglist_t *msglist )
tdb->close( tdb, 0 ); tdb->close( tdb, 0 );
} }
#endif /* USE_DB */ #endif /* USE_DB */
qsort( msglist->ents, msglist->nents, sizeof(msg_t), maildir_compare ); qsort( msglist->array.data, msglist->array.size, sizeof(msg_t), maildir_compare );
for (uid = i = 0; i < msglist->nents; i++) { for (uid = i = 0; i < msglist->array.size; i++) {
entry = &msglist->ents[i]; entry = &msglist->array.data[i];
if (entry->uid != INT_MAX) { if (entry->uid != INT_MAX) {
if (uid == entry->uid) { if (uid == entry->uid) {
#if 1 #if 1
@ -1134,7 +1127,7 @@ maildir_select_box( store_t *gctx, const char *name )
maildir_cleanup( gctx ); maildir_cleanup( gctx );
gctx->msgs = 0; gctx->msgs = 0;
ctx->excs = 0; ctx->excs.data = 0;
ctx->uvfd = -1; ctx->uvfd = -1;
#ifdef USE_DB #ifdef USE_DB
ctx->db = 0; ctx->db = 0;
@ -1215,9 +1208,9 @@ static int
maildir_confirm_box_empty( store_t *gctx ) maildir_confirm_box_empty( store_t *gctx )
{ {
maildir_store_t *ctx = (maildir_store_t *)gctx; maildir_store_t *ctx = (maildir_store_t *)gctx;
msglist_t msglist; msg_t_array_alloc_t msglist;
ctx->nexcs = ctx->minuid = ctx->maxuid = ctx->newuid = 0; ctx->excs.size = ctx->minuid = ctx->maxuid = ctx->newuid = 0;
if (maildir_scan( ctx, &msglist ) != DRV_OK) if (maildir_scan( ctx, &msglist ) != DRV_OK)
return DRV_BOX_BAD; return DRV_BOX_BAD;
@ -1289,27 +1282,27 @@ maildir_prepare_load_box( store_t *gctx, int opts )
} }
static void static void
maildir_load_box( store_t *gctx, int minuid, int maxuid, int newuid, int *excs, int nexcs, maildir_load_box( store_t *gctx, int minuid, int maxuid, int newuid, int_array_t excs,
void (*cb)( int sts, void *aux ), void *aux ) void (*cb)( int sts, void *aux ), void *aux )
{ {
maildir_store_t *ctx = (maildir_store_t *)gctx; maildir_store_t *ctx = (maildir_store_t *)gctx;
message_t **msgapp; message_t **msgapp;
msglist_t msglist; msg_t_array_alloc_t msglist;
int i; int i;
ctx->minuid = minuid; ctx->minuid = minuid;
ctx->maxuid = maxuid; ctx->maxuid = maxuid;
ctx->newuid = newuid; ctx->newuid = newuid;
ctx->excs = nfrealloc( excs, nexcs * sizeof(int) ); ARRAY_SQUEEZE( &excs );
ctx->nexcs = nexcs; ctx->excs = excs;
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;
} }
msgapp = &ctx->gen.msgs; msgapp = &ctx->gen.msgs;
for (i = 0; i < msglist.nents; i++) for (i = 0; i < msglist.array.size; i++)
maildir_app_msg( ctx, &msgapp, msglist.ents + i ); maildir_app_msg( ctx, &msgapp, msglist.array.data + i );
maildir_free_scan( &msglist ); maildir_free_scan( &msglist );
cb( DRV_OK, aux ); cb( DRV_OK, aux );
@ -1320,37 +1313,37 @@ maildir_rescan( maildir_store_t *ctx )
{ {
message_t **msgapp; message_t **msgapp;
maildir_message_t *msg; maildir_message_t *msg;
msglist_t msglist; msg_t_array_alloc_t msglist;
int i; int i;
ctx->fresh[0] = ctx->fresh[1] = 0; 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;
(msg = (maildir_message_t *)*msgapp) || i < msglist.nents; ) (msg = (maildir_message_t *)*msgapp) || i < msglist.array.size; )
{ {
if (!msg) { if (!msg) {
#if 0 #if 0
debug( "adding new message %d\n", msglist.ents[i].uid ); debug( "adding new message %d\n", msglist.array.data[i].uid );
maildir_app_msg( ctx, &msgapp, msglist.ents + i ); maildir_app_msg( ctx, &msgapp, msglist.array.data + i );
#else #else
debug( "ignoring new message %d\n", msglist.ents[i].uid ); debug( "ignoring new message %d\n", msglist.array.data[i].uid );
#endif #endif
i++; i++;
} else if (i >= msglist.nents) { } else if (i >= msglist.array.size) {
debug( "purging deleted message %d\n", msg->gen.uid ); debug( "purging deleted message %d\n", msg->gen.uid );
msg->gen.status = M_DEAD; msg->gen.status = M_DEAD;
msgapp = &msg->gen.next; msgapp = &msg->gen.next;
} else if (msglist.ents[i].uid < msg->gen.uid) { } else if (msglist.array.data[i].uid < msg->gen.uid) {
/* this should not happen, actually */ /* this should not happen, actually */
#if 0 #if 0
debug( "adding new message %d\n", msglist.ents[i].uid ); debug( "adding new message %d\n", msglist.array.data[i].uid );
maildir_app_msg( ctx, &msgapp, msglist.ents + i ); maildir_app_msg( ctx, &msgapp, msglist.array.data + i );
#else #else
debug( "ignoring new message %d\n", msglist.ents[i].uid ); debug( "ignoring new message %d\n", msglist.array.data[i].uid );
#endif #endif
i++; i++;
} else if (msglist.ents[i].uid > msg->gen.uid) { } else if (msglist.array.data[i].uid > msg->gen.uid) {
debug( "purging deleted message %d\n", msg->gen.uid ); debug( "purging deleted message %d\n", msg->gen.uid );
msg->gen.status = M_DEAD; msg->gen.status = M_DEAD;
msgapp = &msg->gen.next; msgapp = &msg->gen.next;
@ -1358,7 +1351,7 @@ maildir_rescan( maildir_store_t *ctx )
debug( "updating message %d\n", msg->gen.uid ); debug( "updating message %d\n", msg->gen.uid );
msg->gen.status &= ~(M_FLAGS|M_RECENT); msg->gen.status &= ~(M_FLAGS|M_RECENT);
free( msg->base ); free( msg->base );
maildir_init_msg( ctx, msg, msglist.ents + i ); maildir_init_msg( ctx, msg, msglist.array.data + i );
i++, msgapp = &msg->gen.next; i++, msgapp = &msg->gen.next;
} }
} }

27
src/sync.c

@ -938,7 +938,7 @@ 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 );
static void load_box( sync_vars_t *svars, int t, int minwuid, int *mexcs, int nmexcs ); static void load_box( sync_vars_t *svars, int t, int minwuid, int_array_t mexcs );
void void
sync_boxes( store_t *ctx[], const char *names[], int present[], channel_conf_t *chan, sync_boxes( store_t *ctx[], const char *names[], int present[], channel_conf_t *chan,
@ -1138,8 +1138,8 @@ box_opened2( sync_vars_t *svars, int t )
store_t *ctx[2]; store_t *ctx[2];
channel_conf_t *chan; channel_conf_t *chan;
sync_rec_t *srec; sync_rec_t *srec;
int opts[2], fails; int_array_alloc_t mexcs;
int *mexcs, nmexcs, rmexcs, minwuid; int opts[2], fails, minwuid;
svars->state[t] |= ST_SELECTED; svars->state[t] |= ST_SELECTED;
if (!(svars->state[1-t] & ST_SELECTED)) if (!(svars->state[1-t] & ST_SELECTED))
@ -1224,8 +1224,7 @@ box_opened2( sync_vars_t *svars, int t )
svars->drv[M]->prepare_load_box( ctx[M], opts[M] ); svars->drv[M]->prepare_load_box( ctx[M], opts[M] );
svars->drv[S]->prepare_load_box( ctx[S], opts[S] ); svars->drv[S]->prepare_load_box( ctx[S], opts[S] );
mexcs = 0; ARRAY_INIT( &mexcs );
nmexcs = rmexcs = 0;
if (svars->ctx[M]->opts & OPEN_OLD) { if (svars->ctx[M]->opts & OPEN_OLD) {
if (chan->max_messages) { if (chan->max_messages) {
/* When messages have been expired on the slave, the master fetch is split into /* When messages have been expired on the slave, the master fetch is split into
@ -1263,16 +1262,12 @@ box_opened2( sync_vars_t *svars, int t )
if (srec->uid[M] > 0 && srec->uid[S] > 0 && minwuid > srec->uid[M] && if (srec->uid[M] > 0 && srec->uid[S] > 0 && minwuid > srec->uid[M] &&
(!(svars->ctx[M]->opts & OPEN_NEW) || svars->maxuid[M] >= srec->uid[M])) { (!(svars->ctx[M]->opts & OPEN_NEW) || svars->maxuid[M] >= srec->uid[M])) {
/* The pair is alive, but outside the bulk range. */ /* The pair is alive, but outside the bulk range. */
if (nmexcs == rmexcs) { *int_array_append( &mexcs ) = srec->uid[M];
rmexcs = rmexcs * 2 + 100;
mexcs = nfrealloc( mexcs, rmexcs * sizeof(int) );
}
mexcs[nmexcs++] = srec->uid[M];
} }
} }
debugn( " exception list is:" ); debugn( " exception list is:" );
for (t = 0; t < nmexcs; t++) for (t = 0; t < mexcs.array.size; t++)
debugn( " %d", mexcs[t] ); debugn( " %d", mexcs.array.data[t] );
debug( "\n" ); debug( "\n" );
} else { } else {
minwuid = 1; minwuid = 1;
@ -1281,16 +1276,16 @@ box_opened2( sync_vars_t *svars, int t )
minwuid = INT_MAX; minwuid = INT_MAX;
} }
sync_ref( svars ); sync_ref( svars );
load_box( svars, M, minwuid, mexcs, nmexcs ); load_box( svars, M, minwuid, mexcs.array );
if (!check_cancel( svars )) if (!check_cancel( svars ))
load_box( svars, S, (ctx[S]->opts & OPEN_OLD) ? 1 : INT_MAX, 0, 0 ); load_box( svars, S, (ctx[S]->opts & OPEN_OLD) ? 1 : INT_MAX, (int_array_t){ 0, 0 } );
sync_deref( svars ); sync_deref( svars );
} }
static void box_loaded( int sts, void *aux ); static void box_loaded( int sts, void *aux );
static void static void
load_box( sync_vars_t *svars, int t, int minwuid, int *mexcs, int nmexcs ) load_box( sync_vars_t *svars, int t, int minwuid, int_array_t mexcs )
{ {
sync_rec_t *srec; sync_rec_t *srec;
int maxwuid; int maxwuid;
@ -1308,7 +1303,7 @@ load_box( sync_vars_t *svars, int t, int minwuid, int *mexcs, int nmexcs )
maxwuid = 0; maxwuid = 0;
info( "Loading %s...\n", str_ms[t] ); info( "Loading %s...\n", str_ms[t] );
debug( maxwuid == INT_MAX ? "loading %s [%d,inf]\n" : "loading %s [%d,%d]\n", str_ms[t], minwuid, maxwuid ); debug( maxwuid == INT_MAX ? "loading %s [%d,inf]\n" : "loading %s [%d,%d]\n", str_ms[t], minwuid, maxwuid );
svars->drv[t]->load_box( svars->ctx[t], minwuid, maxwuid, svars->newuid[t], mexcs, nmexcs, box_loaded, AUX ); svars->drv[t]->load_box( svars->ctx[t], minwuid, maxwuid, svars->newuid[t], mexcs, box_loaded, AUX );
} }
typedef struct { typedef struct {

4
src/util.c

@ -540,9 +540,9 @@ compare_ints( const void *l, const void *r )
} }
void void
sort_ints( int *arr, int len ) sort_int_array( int_array_t array )
{ {
qsort( arr, len, sizeof(int), compare_ints ); qsort( array.data, array.size, sizeof(int), compare_ints );
} }

Loading…
Cancel
Save