static int mailbox_reconstruct_compare_update(struct mailbox *mailbox,
                                              struct index_record *record,
                                              bit32 *valid_user_flags,
                                              int flags, int have_file,
                                              int has_snoozedannot,
                                              struct found_uids *discovered)
{
    const char *fname = mailbox_record_fname(mailbox, record);
    int r = 0;
    int i;
    struct index_record copy;
    struct stat sbuf;
    int make_changes = flags & RECONSTRUCT_MAKE_CHANGES;
    int re_parse = flags & RECONSTRUCT_ALWAYS_PARSE;
    int do_stat = flags & RECONSTRUCT_DO_STAT;
    int re_pack = 0;
    int did_stat = 0;

    int remove_temp_spool_file = 0 ;
#if defined ENABLE_OBJECTSTORE
    int object_storage_enabled = config_getswitch(IMAPOPT_OBJECT_STORAGE_ENABLED) ;

    if (object_storage_enabled && record->system_flags & FLAG_INTERNAL_ARCHIVED){  // put the file on spool temporarily
        remove_temp_spool_file = 1;
        r = objectstore_get(mailbox, record, fname);
    }
#endif

    /* does the file actually exist? */
    if (have_file && do_stat) {
        if (stat(fname, &sbuf) == -1 || (sbuf.st_size == 0)) {
            have_file = 0;
        }
        else if (record->size != (unsigned) sbuf.st_size) {
            re_parse = 1;
        }
        did_stat = 1;
    }

    if (!have_file) {
        /* well, that's OK if it's supposed to be missing! */
        if (record->internal_flags & FLAG_INTERNAL_UNLINKED) {
            r = 0 ;
            goto out;
        }

        printf("%s uid %u not found\n", mailbox_name(mailbox), record->uid);
        syslog(LOG_ERR, "%s uid %u not found", mailbox_name(mailbox), record->uid);

        if (!make_changes) {
            r = 0 ;
            goto out;
        }

        /* otherwise we have issues, mark it unlinked */
        unlink(fname);
        record->internal_flags |= FLAG_INTERNAL_EXPUNGED | FLAG_INTERNAL_UNLINKED;
        mailbox->i.options |= OPT_MAILBOX_NEEDS_REPACK;
        r = mailbox_rewrite_index_record(mailbox, record);
        goto out;
    }

    if (mailbox_cacherecord_internal(mailbox, record, MBCACHE_NOPARSE) || record->crec.len == 0) {
        re_parse = 1;
        re_pack = 1; /* cache record will have to be rewritten */
    }

    /* copy once the cache record is read in... */
    copy = *record;

    if (!record->internaldate) {
        re_parse = 1;
    }

    /* re-calculate all the "derived" fields by parsing the file on disk */
    if (re_parse) {
        /* set NULL in case parse finds a new value */
        record->internaldate = 0;

        r = message_parse(fname, record);
        if (r) goto out;

        /* unchanged, keep the old value */
        if (!record->internaldate)
            record->internaldate = copy.internaldate;

        /* it's not the same message! */
        if (!message_guid_equal(&record->guid, &copy.guid)) {
            int do_unlink = 0;

            printf("%s uid %u guid mismatch\n",
                   mailbox_name(mailbox), record->uid);
            syslog(LOG_ERR, "%s uid %u guid mismatch",
                   mailbox_name(mailbox), record->uid);

            if (!make_changes) {
                r = 0 ;
                goto out;
            }

            if (record->internal_flags & FLAG_INTERNAL_EXPUNGED) {
                /* already expunged, just unlink it */
                printf("%s uid %u already expunged, unlinking\n",
                       mailbox_name(mailbox), record->uid);
                syslog(LOG_ERR, "%s uid %u already expunged, unlinking",
                       mailbox_name(mailbox), record->uid);
                do_unlink = 1;
            }
            else if (flags & RECONSTRUCT_GUID_REWRITE) {
                /* treat this file as discovered */
                add_found(discovered, record->uid,
                          (record->internal_flags & FLAG_INTERNAL_ARCHIVED));
                printf("%s uid %u marking for uid upgrade\n",
                       mailbox_name(mailbox), record->uid);
                syslog(LOG_ERR, "%s uid %u marking for uid upgrade",
                       mailbox_name(mailbox), record->uid);
                do_unlink = 1;
            }
            else if (flags & RECONSTRUCT_GUID_UNLINK) {
                printf("%s uid %u unlinking as requested with -U\n",
                       mailbox_name(mailbox), record->uid);
                syslog(LOG_ERR, "%s uid %u unlinking as requested with -U",
                       mailbox_name(mailbox), record->uid);
                do_unlink = 1;
            }

            if (do_unlink) {
                /* rewrite with the original so we don't break the
                 * expectation that GUID never changes */
                copy.internal_flags |= FLAG_INTERNAL_EXPUNGED | FLAG_INTERNAL_UNLINKED;
                mailbox->i.options |= OPT_MAILBOX_NEEDS_UNLINK;
                r = mailbox_rewrite_index_record(mailbox, &copy);
                goto out;
            }

            /* otherwise we just report it and move on - hopefully the
             * correct file can be restored from backup or something */
            printf("run reconstruct with -R to fix or -U to remove\n");
            syslog(LOG_ERR, "run reconstruct with -R to fix or -U to remove");
            r = 0 ;
            goto out;
        }
    }

    if (!record->size) {
        /* dang, guess it failed to parse */

        printf("%s uid %u failed to parse\n", mailbox_name(mailbox), record->uid);
        syslog(LOG_ERR, "%s uid %u failed to parse", mailbox_name(mailbox), record->uid);

        if (!make_changes) {
            r = 0 ;
            goto out;
        }

        /* otherwise we have issues, mark it unlinked */
        unlink(fname);
        record->internal_flags |= FLAG_INTERNAL_EXPUNGED | FLAG_INTERNAL_UNLINKED;
        mailbox->i.options |= OPT_MAILBOX_NEEDS_REPACK;
        r = mailbox_rewrite_index_record(mailbox, record);
        goto out;
    }

    /* get internaldate from the file if not set */
    if (!record->internaldate) {
        if (did_stat || stat(fname, &sbuf) != -1)
            record->internaldate = sbuf.st_mtime;
        else
            record->internaldate = time(NULL);
    }
    if (!record->gmtime)
        record->gmtime = record->internaldate;
    if (!record->sentdate) {
        struct tm *tm = localtime(&record->internaldate);
        /* truncate to the day */
        tm->tm_sec = 0;
        tm->tm_min = 0;
        tm->tm_hour = 0;
        record->sentdate = mktime(tm);
    }

    /* XXX - conditions under which modseq or uid or internaldate could be bogus? */
    if (record->modseq > mailbox->i.highestmodseq) {
        printf("%s uid %u future modseq " MODSEQ_FMT " found\n",
                   mailbox_name(mailbox), record->uid, record->modseq);
        syslog(LOG_ERR, "%s uid %u future modseq " MODSEQ_FMT " found",
                   mailbox_name(mailbox), record->uid, record->modseq);
        mailbox_index_dirty(mailbox);
        mailbox->i.highestmodseq = mboxname_setmodseq(mailbox_name(mailbox),
                                                      record->modseq,
                                                      mailbox_mbtype(mailbox), /*flags*/0);
    }

    if (record->uid > mailbox->i.last_uid) {
        printf("%s future uid %u found\n",
               mailbox_name(mailbox), record->uid);
        syslog(LOG_ERR, "%s future uid %u found",
               mailbox_name(mailbox), record->uid);
        mailbox_index_dirty(mailbox);
        mailbox->i.last_uid = record->uid;
    }

    /* remove any user_flags that are missing from the header */
    for (i = 0; i < MAX_USER_FLAGS/32; i++) {
        record->user_flags[i] &= valid_user_flags[i];
    }

    /* check if the snoozed status matches (unless expunged, which shouldn't be snoozed) */
    if (!(record->internal_flags & FLAG_INTERNAL_EXPUNGED)
      && !!(record->internal_flags & FLAG_INTERNAL_SNOOZED) != !!has_snoozedannot) {
        printf("%s uid %u snoozed mismatch\n", mailbox_name(mailbox), record->uid);
        syslog(LOG_ERR, "%s uid %u snoozed mismatch", mailbox_name(mailbox), record->uid);
        if (has_snoozedannot) record->internal_flags |= FLAG_INTERNAL_SNOOZED;
        else record->internal_flags &= ~FLAG_INTERNAL_SNOOZED;
    }


    /* after all this - if it still matches in every respect, we don't need
     * to rewrite the record - just return */
    if (records_match(mailbox_name(mailbox), &copy, record)) {
        r = 0 ;
        goto out;
    }

    /* XXX - inform of changes */
    if (!make_changes) {
        r = 0 ;
        goto out;
    }

    /* rewrite the cache record */
    if (re_pack || !record->cache_offset || record->cache_crc != copy.cache_crc) {
        int32_t oldcrc = copy.cache_crc;
        int32_t newcrc = record->cache_crc;
        size_t oldoff = record->cache_offset;
        mailbox->i.options |= OPT_MAILBOX_NEEDS_REPACK;
        record->cache_offset = 0;
        r = mailbox_append_cache(mailbox, record);
        if (r) goto out ;
        printf("%s rewrote cache for %u (offset %llu to %llu, crc %u to %u/%u)\n",
               mailbox_name(mailbox), record->uid,
               (long long unsigned)oldoff, (long long unsigned)record->cache_offset,
               oldcrc, newcrc, record->cache_crc);
        syslog(LOG_NOTICE, "%s rewrote cache for %u (offset %llu to %llu, crc %u to %u/%u)",
               mailbox_name(mailbox), record->uid,
               (long long unsigned)oldoff, (long long unsigned)record->cache_offset,
               oldcrc, newcrc, record->cache_crc);
    }

    r = mailbox_rewrite_index_record(mailbox, record);

out:
    if (remove_temp_spool_file)
        remove(fname);
    return r;
}
static int mailbox_reconstruct_compare_update(struct mailbox *mailbox,
                                              struct index_record *record,
                                              bit32 *valid_user_flags,
                                              int flags, int have_file,
                                              int has_snoozedannot,
                                              struct found_uids *discovered)
{
    const char *fname = mailbox_record_fname(mailbox, record);
    int r = 0;
    int i;
    struct index_record copy;
    struct stat sbuf;
    int make_changes = flags & RECONSTRUCT_MAKE_CHANGES;
    int re_parse = flags & RECONSTRUCT_ALWAYS_PARSE;
    int do_stat = flags & RECONSTRUCT_DO_STAT;
    int re_pack = 0;
    int did_stat = 0;

    int remove_temp_spool_file = 0 ;
#if defined ENABLE_OBJECTSTORE
    int object_storage_enabled = config_getswitch(IMAPOPT_OBJECT_STORAGE_ENABLED) ;

    if (object_storage_enabled && record->system_flags & FLAG_INTERNAL_ARCHIVED){   
        remove_temp_spool_file = 1;
        r = objectstore_get(mailbox, record, fname);
    }
#endif

     
    if (have_file && do_stat) {
        if (stat(fname, &sbuf) == -1 || (sbuf.st_size == 0)) {
            have_file = 0;
        }
        else if (record->size != (unsigned) sbuf.st_size) {
            re_parse = 1;
        }
        did_stat = 1;
    }

    if (!have_file) {
         
        if (record->internal_flags & FLAG_INTERNAL_UNLINKED) {
            r = 0 ;
            goto out;
        }

        printf("%s uid %u not found\n", mailbox_name(mailbox), record->uid);
        syslog(LOG_ERR, "%s uid %u not found", mailbox_name(mailbox), record->uid);

        if (!make_changes) {
            r = 0 ;
            goto out;
        }

         
        unlink(fname);
        record->internal_flags |= FLAG_INTERNAL_EXPUNGED | FLAG_INTERNAL_UNLINKED;
        mailbox->i.options |= OPT_MAILBOX_NEEDS_REPACK;
        r = mailbox_rewrite_index_record(mailbox, record);
        goto out;
    }

    if (mailbox_cacherecord_internal(mailbox, record, MBCACHE_NOPARSE) || record->crec.len == 0) {
        re_parse = 1;
        re_pack = 1;  
    }

     
    copy = *record;

    if (!record->internaldate) {
        re_parse = 1;
    }

     
    if (re_parse) {
         
        record->internaldate = 0;

        r = message_parse(fname, record);
        if (r) goto out;

         
        if (!record->internaldate)
            record->internaldate = copy.internaldate;

         
        if (!message_guid_equal(&record->guid, &copy.guid)) {
            int do_unlink = 0;

            printf("%s uid %u guid mismatch\n",
                   mailbox_name(mailbox), record->uid);
            syslog(LOG_ERR, "%s uid %u guid mismatch",
                   mailbox_name(mailbox), record->uid);

            if (!make_changes) {
                r = 0 ;
                goto out;
            }

            if (record->internal_flags & FLAG_INTERNAL_EXPUNGED) {
                 
                printf("%s uid %u already expunged, unlinking\n",
                       mailbox_name(mailbox), record->uid);
                syslog(LOG_ERR, "%s uid %u already expunged, unlinking",
                       mailbox_name(mailbox), record->uid);
                do_unlink = 1;
            }
            else if (flags & RECONSTRUCT_GUID_REWRITE) {
                 
                add_found(discovered, record->uid,
                          (record->internal_flags & FLAG_INTERNAL_ARCHIVED));
                printf("%s uid %u marking for uid upgrade\n",
                       mailbox_name(mailbox), record->uid);
                syslog(LOG_ERR, "%s uid %u marking for uid upgrade",
                       mailbox_name(mailbox), record->uid);
                do_unlink = 1;
            }
            else if (flags & RECONSTRUCT_GUID_UNLINK) {
                printf("%s uid %u unlinking as requested with -U\n",
                       mailbox_name(mailbox), record->uid);
                syslog(LOG_ERR, "%s uid %u unlinking as requested with -U",
                       mailbox_name(mailbox), record->uid);
                do_unlink = 1;
            }

            if (do_unlink) {
                 
                copy.internal_flags |= FLAG_INTERNAL_EXPUNGED | FLAG_INTERNAL_UNLINKED;
                mailbox->i.options |= OPT_MAILBOX_NEEDS_UNLINK;
                r = mailbox_rewrite_index_record(mailbox, &copy);
                goto out;
            }

             
            printf("run reconstruct with -R to fix or -U to remove\n");
            syslog(LOG_ERR, "run reconstruct with -R to fix or -U to remove");
            r = 0 ;
            goto out;
        }
    }

    if (!record->size) {
         

        printf("%s uid %u failed to parse\n", mailbox_name(mailbox), record->uid);
        syslog(LOG_ERR, "%s uid %u failed to parse", mailbox_name(mailbox), record->uid);

        if (!make_changes) {
            r = 0 ;
            goto out;
        }

         
        unlink(fname);
        record->internal_flags |= FLAG_INTERNAL_EXPUNGED | FLAG_INTERNAL_UNLINKED;
        mailbox->i.options |= OPT_MAILBOX_NEEDS_REPACK;
        r = mailbox_rewrite_index_record(mailbox, record);
        goto out;
    }

     
    if (!record->internaldate) {
        if (did_stat || stat(fname, &sbuf) != -1)
            record->internaldate = sbuf.st_mtime;
        else
            record->internaldate = time(NULL);
    }
    if (!record->gmtime)
        record->gmtime = record->internaldate;
    if (!record->sentdate) {
        struct tm *tm = localtime(&record->internaldate);
         
        tm->tm_sec = 0;
        tm->tm_min = 0;
        tm->tm_hour = 0;
        record->sentdate = mktime(tm);
    }

     
    if (record->modseq > mailbox->i.highestmodseq) {
        printf("%s uid %u future modseq " MODSEQ_FMT " found\n",
                   mailbox_name(mailbox), record->uid, record->modseq);
        syslog(LOG_ERR, "%s uid %u future modseq " MODSEQ_FMT " found",
                   mailbox_name(mailbox), record->uid, record->modseq);
        mailbox_index_dirty(mailbox);
        mailbox->i.highestmodseq = mboxname_setmodseq(mailbox_name(mailbox),
                                                      record->modseq,
                                                      mailbox_mbtype(mailbox),  0);
    }

    if (record->uid > mailbox->i.last_uid) {
        printf("%s future uid %u found\n",
               mailbox_name(mailbox), record->uid);
        syslog(LOG_ERR, "%s future uid %u found",
               mailbox_name(mailbox), record->uid);
        mailbox_index_dirty(mailbox);
        mailbox->i.last_uid = record->uid;
    }

     
    for (i = 0; i < MAX_USER_FLAGS/32; i++) {
        record->user_flags[i] &= valid_user_flags[i];
    }

     
    if (!(record->internal_flags & FLAG_INTERNAL_EXPUNGED)
      && !!(record->internal_flags & FLAG_INTERNAL_SNOOZED) != !!has_snoozedannot) {
        printf("%s uid %u snoozed mismatch\n", mailbox_name(mailbox), record->uid);
        syslog(LOG_ERR, "%s uid %u snoozed mismatch", mailbox_name(mailbox), record->uid);
        if (has_snoozedannot) record->internal_flags |= FLAG_INTERNAL_SNOOZED;
        else record->internal_flags &= ~FLAG_INTERNAL_SNOOZED;
    }


     
    if (records_match(mailbox_name(mailbox), &copy, record)) {
        r = 0 ;
        goto out;
    }

     
    if (!make_changes) {
        r = 0 ;
        goto out;
    }

     
    if (re_pack || !record->cache_offset || record->cache_crc != copy.cache_crc) {
        int32_t oldcrc = copy.cache_crc;
        int32_t newcrc = record->cache_crc;
        size_t oldoff = record->cache_offset;
        mailbox->i.options |= OPT_MAILBOX_NEEDS_REPACK;
        record->cache_offset = 0;
        r = mailbox_append_cache(mailbox, record);
        if (r) goto out ;
        printf("%s rewrote cache for %u (offset %llu to %llu, crc %u to %u/%u)\n",
               mailbox_name(mailbox), record->uid,
               (long long unsigned)oldoff, (long long unsigned)record->cache_offset,
               oldcrc, newcrc, record->cache_crc);
        syslog(LOG_NOTICE, "%s rewrote cache for %u (offset %llu to %llu, crc %u to %u/%u)",
               mailbox_name(mailbox), record->uid,
               (long long unsigned)oldoff, (long long unsigned)record->cache_offset,
               oldcrc, newcrc, record->cache_crc);
    }

    r = mailbox_rewrite_index_record(mailbox, record);

out:
    if (remove_temp_spool_file)
        remove(fname);
    return r;
}