X-Git-Url: https://git.notmuchmail.org/git?p=notmuch;a=blobdiff_plain;f=notmuch-new.c;h=82e2d3582a0fe85d51e02a7f766121b3b42d9190;hp=0fa2a3cb72ebcda4a3de4131d3106a0fa4a96704;hb=e59cc0031fbf84f49e32dedb9927f427d2c49309;hpb=8bb6f7869c4c98190f010d60409938b1c50c5968 diff --git a/notmuch-new.c b/notmuch-new.c index 0fa2a3cb..82e2d358 100644 --- a/notmuch-new.c +++ b/notmuch-new.c @@ -24,6 +24,7 @@ typedef struct _filename_node { char *filename; + time_t mtime; struct _filename_node *next; } _filename_node_t; @@ -46,6 +47,7 @@ typedef struct { _filename_list_t *removed_files; _filename_list_t *removed_directories; + _filename_list_t *directory_mtimes; notmuch_bool_t synchronize_flags; _filename_list_t *message_ids_to_sync; @@ -86,7 +88,7 @@ _filename_list_create (const void *ctx) return list; } -static void +static _filename_node_t * _filename_list_add (_filename_list_t *list, const char *filename) { @@ -99,6 +101,8 @@ _filename_list_add (_filename_list_t *list, *(list->tail) = node; list->tail = &node->next; + + return node; } static void @@ -213,6 +217,7 @@ _entries_resemble_maildir (struct dirent **entries, int count) * information is lost from the database). * * o Tell the database to update its time of 'path' to 'fs_mtime' + * if fs_mtime isn't the current wall-clock time. */ static notmuch_status_t add_files_recursive (notmuch_database_t *notmuch, @@ -230,6 +235,7 @@ add_files_recursive (notmuch_database_t *notmuch, notmuch_directory_t *directory; notmuch_filenames_t *db_files = NULL; notmuch_filenames_t *db_subdirs = NULL; + time_t stat_time; struct stat st; notmuch_bool_t is_maildir, new_directory; const char **tag; @@ -239,6 +245,7 @@ add_files_recursive (notmuch_database_t *notmuch, path, strerror (errno)); return NOTMUCH_STATUS_FILE_ERROR; } + stat_time = time (NULL); /* This is not an error since we may have recursed based on a * symlink to a regular file, not a directory, and we don't know @@ -253,6 +260,25 @@ add_files_recursive (notmuch_database_t *notmuch, new_directory = db_mtime ? FALSE : TRUE; + /* XXX This is a temporary workaround. If we don't update the + * database mtime until after processing messages in this + * directory, then a 0 mtime is *not* sufficient to indicate that + * this directory has no messages or subdirs in the database (for + * example, if an earlier run skipped the mtime update because + * fs_mtime == stat_time, or was interrupted before updating the + * mtime at the end). To address this, we record a (bogus) + * non-zero value before processing any child messages so that a + * later run won't mistake this for a new directory (and, for + * example, fail to detect removed files and subdirs). + * + * A better solution would be for notmuch_database_get_directory + * to indicate if it really created a new directory or not, either + * by a new out-argument, or by recording this information and + * providing an accessor. + */ + if (new_directory) + notmuch_directory_set_mtime (directory, -1); + /* If the database knows about this directory, then we sort based * on strcmp to match the database sorting. Otherwise, we can do * inode-based sorting for faster filesystem operation. */ @@ -462,6 +488,7 @@ add_files_recursive (notmuch_database_t *notmuch, case NOTMUCH_STATUS_NULL_POINTER: case NOTMUCH_STATUS_TAG_TOO_LONG: case NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW: + case NOTMUCH_STATUS_UNBALANCED_ATOMIC: case NOTMUCH_STATUS_LAST_STATUS: INTERNAL_ERROR ("add_message returned unexpected value: %d", status); goto DONE; @@ -509,11 +536,13 @@ add_files_recursive (notmuch_database_t *notmuch, notmuch_filenames_move_to_next (db_subdirs); } - if (! interrupted) { - status = notmuch_directory_set_mtime (directory, fs_mtime); - if (status && ret == NOTMUCH_STATUS_SUCCESS) - ret = status; - } + /* If the directory's mtime is the same as the wall-clock time + * when we stat'ed the directory, we skip updating the mtime in + * the database because a message could be delivered later in this + * same second. This may lead to unnecessary re-scans, but it + * avoids overlooking messages. */ + if (fs_mtime != stat_time) + _filename_list_add (state->directory_mtimes, path)->mtime = fs_mtime; DONE: if (next) @@ -829,6 +858,7 @@ notmuch_new_command (void *ctx, int argc, char *argv[]) add_files_state.removed_files = _filename_list_create (ctx); add_files_state.removed_directories = _filename_list_create (ctx); + add_files_state.directory_mtimes = _filename_list_create (ctx); if (! debugger_is_active () && add_files_state.output_is_a_tty && ! add_files_state.verbose) { @@ -841,7 +871,7 @@ notmuch_new_command (void *ctx, int argc, char *argv[]) removed_files = 0; renamed_files = 0; gettimeofday (&tv_start, NULL); - for (f = add_files_state.removed_files->head; f; f = f->next) { + for (f = add_files_state.removed_files->head; f && !interrupted; f = f->next) { status = notmuch_database_remove_message (notmuch, f->filename); if (status == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) renamed_files++; @@ -856,7 +886,7 @@ notmuch_new_command (void *ctx, int argc, char *argv[]) } gettimeofday (&tv_start, NULL); - for (f = add_files_state.removed_directories->head, i = 0; f; f = f->next, i++) { + for (f = add_files_state.removed_directories->head, i = 0; f && !interrupted; f = f->next, i++) { _remove_directory (ctx, notmuch, f->filename, &renamed_files, &removed_files); if (do_print_progress) { @@ -867,8 +897,18 @@ notmuch_new_command (void *ctx, int argc, char *argv[]) } } + for (f = add_files_state.directory_mtimes->head; f && !interrupted; f = f->next) { + notmuch_directory_t *directory; + directory = notmuch_database_get_directory (notmuch, f->filename); + if (directory) { + notmuch_directory_set_mtime (directory, f->mtime); + notmuch_directory_destroy (directory); + } + } + talloc_free (add_files_state.removed_files); talloc_free (add_files_state.removed_directories); + talloc_free (add_files_state.directory_mtimes); /* Now that removals are done (hence the database is aware of all * renames), we can synchronize maildir_flags to tags for all