add_files_recursive: Separate scanning for directories and files for legibility.

We now do two scans over the entries returned from scandir. The first
scan is looking for directories (and making the recursive call). The
second scan is looking for new files to add to the database.

This is easier to read than the previous code which had a single loop
and some if statements with ridiculously long bodies. It also has the
advantage that once the directory scan is complete we can do a single
comparison of the filesystem and database mtimes and entirely skip the
second scan if it's not needed.
This commit is contained in:
Carl Worth 2010-01-05 16:35:02 -08:00
parent 6f05dd8a8c
commit 28ce73848d

View file

@ -125,14 +125,14 @@ is_maildir (struct dirent **entries, int count)
* *
* o Ask the database for its timestamp of 'path' (db_mtime) * o Ask the database for its timestamp of 'path' (db_mtime)
* *
* o For each sub-directory of path, recursively call into this
* same function.
*
* o If 'fs_mtime' > 'db_mtime' * o If 'fs_mtime' > 'db_mtime'
* *
* o For each regular file directly within 'path', call * o For each regular file directly within 'path', call
* add_message to add the file to the database. * add_message to add the file to the database.
* *
* o For each sub-directory of path, recursively call into this
* same function.
*
* o Tell the database to update its time of 'path' to 'fs_mtime' * o Tell the database to update its time of 'path' to 'fs_mtime'
* *
* The 'struct stat *st' must point to a structure that has already * The 'struct stat *st' must point to a structure that has already
@ -150,7 +150,7 @@ add_files_recursive (notmuch_database_t *notmuch,
notmuch_status_t status, ret = NOTMUCH_STATUS_SUCCESS; notmuch_status_t status, ret = NOTMUCH_STATUS_SUCCESS;
notmuch_message_t *message = NULL; notmuch_message_t *message = NULL;
struct dirent **fs_entries = NULL; struct dirent **fs_entries = NULL;
int num_fs_entries; int i, num_fs_entries;
notmuch_directory_t *directory; notmuch_directory_t *directory;
struct stat st; struct stat st;
@ -179,18 +179,14 @@ add_files_recursive (notmuch_database_t *notmuch,
goto DONE; goto DONE;
} }
int i=0; /* First, recurse into all sub-directories. */
for (i = 0; i < num_fs_entries; i++) {
while (!interrupted) { if (interrupted)
if (i == num_fs_entries)
break; break;
entry = fs_entries[i++]; entry = fs_entries[i];
/* If this directory hasn't been modified since the last if (entry->d_type != DT_DIR)
* add_files, then we only need to look further for
* sub-directories. */
if (fs_mtime <= db_mtime && entry->d_type == DT_REG)
continue; continue;
/* Ignore special directories to avoid infinite recursion. /* Ignore special directories to avoid infinite recursion.
@ -209,69 +205,87 @@ add_files_recursive (notmuch_database_t *notmuch,
} }
next = talloc_asprintf (notmuch, "%s/%s", path, entry->d_name); next = talloc_asprintf (notmuch, "%s/%s", path, entry->d_name);
status = add_files_recursive (notmuch, next, state);
if (status && ret == NOTMUCH_STATUS_SUCCESS)
ret = status;
talloc_free (next);
next = NULL;
}
if (entry->d_type == DT_REG) { /* If this directory hasn't been modified since the last
state->processed_files++; * add_files, then we can skip the second pass where we look for
* new files in this directory. */
if (fs_mtime <= db_mtime)
goto DONE;
if (state->verbose) { /* Second, scan the regular files in this directory. */
if (state->output_is_a_tty) for (i = 0; i < num_fs_entries; i++) {
printf("\r\033[K"); if (interrupted)
break;
printf ("%i/%i: %s", entry = fs_entries[i];
state->processed_files,
state->total_files,
next);
putchar((state->output_is_a_tty) ? '\r' : '\n'); if (entry->d_type != DT_REG)
fflush (stdout); continue;
}
status = notmuch_database_add_message (notmuch, next, &message); next = talloc_asprintf (notmuch, "%s/%s", path, entry->d_name);
switch (status) {
/* success */
case NOTMUCH_STATUS_SUCCESS:
state->added_messages++;
tag_inbox_and_unread (message);
break;
/* Non-fatal issues (go on to next file) */
case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID:
/* Stay silent on this one. */
break;
case NOTMUCH_STATUS_FILE_NOT_EMAIL:
fprintf (stderr, "Note: Ignoring non-mail file: %s\n",
next);
break;
/* Fatal issues. Don't process anymore. */
case NOTMUCH_STATUS_READONLY_DATABASE:
case NOTMUCH_STATUS_XAPIAN_EXCEPTION:
case NOTMUCH_STATUS_OUT_OF_MEMORY:
fprintf (stderr, "Error: %s. Halting processing.\n",
notmuch_status_to_string (status));
ret = status;
goto DONE;
default:
case NOTMUCH_STATUS_FILE_ERROR:
case NOTMUCH_STATUS_NULL_POINTER:
case NOTMUCH_STATUS_TAG_TOO_LONG:
case NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW:
case NOTMUCH_STATUS_LAST_STATUS:
INTERNAL_ERROR ("add_message returned unexpected value: %d", status);
goto DONE;
}
if (message) { state->processed_files++;
notmuch_message_destroy (message);
message = NULL;
}
if (do_add_files_print_progress) { if (state->verbose) {
do_add_files_print_progress = 0; if (state->output_is_a_tty)
add_files_print_progress (state); printf("\r\033[K");
}
} else if (entry->d_type == DT_DIR) { printf ("%i/%i: %s",
status = add_files_recursive (notmuch, next, state); state->processed_files,
if (status && ret == NOTMUCH_STATUS_SUCCESS) state->total_files,
ret = status; next);
putchar((state->output_is_a_tty) ? '\r' : '\n');
fflush (stdout);
}
status = notmuch_database_add_message (notmuch, next, &message);
switch (status) {
/* success */
case NOTMUCH_STATUS_SUCCESS:
state->added_messages++;
tag_inbox_and_unread (message);
break;
/* Non-fatal issues (go on to next file) */
case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID:
/* Stay silent on this one. */
break;
case NOTMUCH_STATUS_FILE_NOT_EMAIL:
fprintf (stderr, "Note: Ignoring non-mail file: %s\n",
next);
break;
/* Fatal issues. Don't process anymore. */
case NOTMUCH_STATUS_READONLY_DATABASE:
case NOTMUCH_STATUS_XAPIAN_EXCEPTION:
case NOTMUCH_STATUS_OUT_OF_MEMORY:
fprintf (stderr, "Error: %s. Halting processing.\n",
notmuch_status_to_string (status));
ret = status;
goto DONE;
default:
case NOTMUCH_STATUS_FILE_ERROR:
case NOTMUCH_STATUS_NULL_POINTER:
case NOTMUCH_STATUS_TAG_TOO_LONG:
case NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW:
case NOTMUCH_STATUS_LAST_STATUS:
INTERNAL_ERROR ("add_message returned unexpected value: %d", status);
goto DONE;
}
if (message) {
notmuch_message_destroy (message);
message = NULL;
}
if (do_add_files_print_progress) {
do_add_files_print_progress = 0;
add_files_print_progress (state);
} }
talloc_free (next); talloc_free (next);