X-Git-Url: https://git.notmuchmail.org/git?p=notmuch;a=blobdiff_plain;f=notmuch-new.c;h=a2b30bdc3c62fb42d3c97c6eca721af7fc73fa5d;hp=7603d3d7b57f0a61236cef9f76afe5e8bd98740e;hb=fff24a2858686af8dfd579a9e09736bea9795e83;hpb=37bdd8987094220c84ec39f8f550753219f68bd4 diff --git a/notmuch-new.c b/notmuch-new.c index 7603d3d7..a2b30bdc 100644 --- a/notmuch-new.c +++ b/notmuch-new.c @@ -20,6 +20,8 @@ #include "notmuch-client.h" +#include + static volatile sig_atomic_t do_add_files_print_progress = 0; static void @@ -28,6 +30,16 @@ handle_sigalrm (unused (int signal)) do_add_files_print_progress = 1; } +static volatile sig_atomic_t interrupted; + +static void +handle_sigint (unused (int sig)) +{ + static char msg[] = "Stopping... \n"; + write(2, msg, sizeof(msg)-1); + interrupted = 1; +} + static void tag_inbox_and_unread (notmuch_message_t *message) { @@ -63,6 +75,11 @@ add_files_print_progress (add_files_state_t *state) fflush (stdout); } +static int ino_cmp(const struct dirent **a, const struct dirent **b) +{ + return ((*a)->d_ino < (*b)->d_ino) ? -1 : 1; +} + /* Examine 'path' recursively as follows: * * o Ask the filesystem for the mtime of 'path' (path_mtime) @@ -90,13 +107,13 @@ add_files_recursive (notmuch_database_t *notmuch, add_files_state_t *state) { DIR *dir = NULL; - struct dirent *e, *entry = NULL; - int entry_length; - int err; + struct dirent *entry = NULL; char *next = NULL; time_t path_mtime, path_dbtime; notmuch_status_t status, ret = NOTMUCH_STATUS_SUCCESS; notmuch_message_t *message = NULL; + struct dirent **namelist = NULL; + int num_entries; /* If we're told to, we bail out on encountering a read-only * directory, (with this being a clear clue from the user to @@ -112,31 +129,23 @@ add_files_recursive (notmuch_database_t *notmuch, path_mtime = st->st_mtime; path_dbtime = notmuch_database_get_timestamp (notmuch, path); + num_entries = scandir (path, &namelist, 0, ino_cmp); - dir = opendir (path); - if (dir == NULL) { + if (num_entries == -1) { fprintf (stderr, "Error opening directory %s: %s\n", path, strerror (errno)); ret = NOTMUCH_STATUS_FILE_ERROR; goto DONE; } - entry_length = offsetof (struct dirent, d_name) + - pathconf (path, _PC_NAME_MAX) + 1; - entry = malloc (entry_length); + int i=0; - while (1) { - err = readdir_r (dir, entry, &e); - if (err) { - fprintf (stderr, "Error reading directory: %s\n", - strerror (errno)); - ret = NOTMUCH_STATUS_FILE_ERROR; - goto DONE; - } - - if (e == NULL) + while (!interrupted) { + if (i == num_entries) break; + entry= namelist[i++]; + /* If this directory hasn't been modified since the last * add_files, then we only need to look further for * sub-directories. */ @@ -167,9 +176,17 @@ add_files_recursive (notmuch_database_t *notmuch, if (S_ISREG (st->st_mode)) { /* If the file hasn't been modified since the last * add_files, then we need not look at it. */ - if (st->st_mtime > path_dbtime) { + if (path_dbtime == 0 || st->st_mtime > path_dbtime) { state->processed_files++; + if (state->verbose) { + printf ("\r\033[K%i/%i: %s\r", + state->processed_files, + state->total_files, + next); + fflush (stdout); + } + status = notmuch_database_add_message (notmuch, next, &message); switch (status) { /* success */ @@ -186,6 +203,7 @@ add_files_recursive (notmuch_database_t *notmuch, 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", @@ -233,6 +251,8 @@ add_files_recursive (notmuch_database_t *notmuch, free (entry); if (dir) closedir (dir); + if (namelist) + free (namelist); return ret; } @@ -249,6 +269,7 @@ add_files (notmuch_database_t *notmuch, notmuch_status_t status; struct sigaction action; struct itimerval timerval; + notmuch_bool_t timer_is_active = FALSE; if (stat (path, &st)) { fprintf (stderr, "Error reading directory %s: %s\n", @@ -261,76 +282,72 @@ add_files (notmuch_database_t *notmuch, return NOTMUCH_STATUS_FILE_ERROR; } - /* Setup our handler for SIGALRM */ - memset (&action, 0, sizeof (struct sigaction)); - action.sa_handler = handle_sigalrm; - sigemptyset (&action.sa_mask); - action.sa_flags = SA_RESTART; - sigaction (SIGALRM, &action, NULL); - - /* Then start a timer to send SIGALRM once per second. */ - timerval.it_interval.tv_sec = 1; - timerval.it_interval.tv_usec = 0; - timerval.it_value.tv_sec = 1; - timerval.it_value.tv_usec = 0; - setitimer (ITIMER_REAL, &timerval, NULL); + if (isatty (fileno (stdout)) && ! debugger_is_active () + && ! state->verbose) + { + /* Setup our handler for SIGALRM */ + memset (&action, 0, sizeof (struct sigaction)); + action.sa_handler = handle_sigalrm; + sigemptyset (&action.sa_mask); + action.sa_flags = SA_RESTART; + sigaction (SIGALRM, &action, NULL); + + /* Then start a timer to send SIGALRM once per second. */ + timerval.it_interval.tv_sec = 1; + timerval.it_interval.tv_usec = 0; + timerval.it_value.tv_sec = 1; + timerval.it_value.tv_usec = 0; + setitimer (ITIMER_REAL, &timerval, NULL); + + timer_is_active = TRUE; + } status = add_files_recursive (notmuch, path, &st, state); - /* Now stop the timer. */ - timerval.it_interval.tv_sec = 0; - timerval.it_interval.tv_usec = 0; - timerval.it_value.tv_sec = 0; - timerval.it_value.tv_usec = 0; - setitimer (ITIMER_REAL, &timerval, NULL); - - /* And disable the signal handler. */ - action.sa_handler = SIG_IGN; - sigaction (SIGALRM, &action, NULL); + if (timer_is_active) { + /* Now stop the timer. */ + timerval.it_interval.tv_sec = 0; + timerval.it_interval.tv_usec = 0; + timerval.it_value.tv_sec = 0; + timerval.it_value.tv_usec = 0; + setitimer (ITIMER_REAL, &timerval, NULL); + + /* And disable the signal handler. */ + action.sa_handler = SIG_IGN; + sigaction (SIGALRM, &action, NULL); + } return status; } /* XXX: This should be merged with the add_files function since it * shares a lot of logic with it. */ -/* Recursively count all regular files in path and all sub-direcotries +/* Recursively count all regular files in path and all sub-directories * of path. The result is added to *count (which should be * initialized to zero by the top-level caller before calling * count_files). */ static void count_files (const char *path, int *count) { - DIR *dir; - struct dirent *e, *entry = NULL; - int entry_length; - int err; + struct dirent *entry = NULL; char *next; struct stat st; + struct dirent **namelist = NULL; + int n_entries = scandir (path, &namelist, 0, ino_cmp); + int i = 0; - dir = opendir (path); - - if (dir == NULL) { + if (n_entries == -1) { fprintf (stderr, "Warning: failed to open directory %s: %s\n", path, strerror (errno)); goto DONE; } - entry_length = offsetof (struct dirent, d_name) + - pathconf (path, _PC_NAME_MAX) + 1; - entry = malloc (entry_length); - - while (1) { - err = readdir_r (dir, entry, &e); - if (err) { - fprintf (stderr, "Error reading directory: %s\n", - strerror (errno)); - free (entry); - goto DONE; - } - - if (e == NULL) + while (!interrupted) { + if (i == n_entries) break; + entry= namelist[i++]; + /* Ignore special directories to avoid infinite recursion. * Also ignore the .notmuch directory. */ @@ -368,13 +385,12 @@ count_files (const char *path, int *count) DONE: if (entry) free (entry); - - closedir (dir); + if (namelist) + free (namelist); } int -notmuch_new_command (void *ctx, - unused (int argc), unused (char *argv[])) +notmuch_new_command (void *ctx, int argc, char *argv[]) { notmuch_config_t *config; notmuch_database_t *notmuch; @@ -385,7 +401,26 @@ notmuch_new_command (void *ctx, struct stat st; const char *db_path; char *dot_notmuch_path; - int new_database = 0; + struct sigaction action; + int i; + + add_files_state.verbose = 0; + + for (i = 0; i < argc && argv[i][0] == '-'; i++) { + if (STRNCMP_LITERAL (argv[i], "--verbose") == 0) { + add_files_state.verbose = 1; + } else { + fprintf (stderr, "Unrecognized option: %s\n", argv[i]); + return 1; + } + } + + /* Setup our handler for SIGINT */ + memset (&action, 0, sizeof (struct sigaction)); + action.sa_handler = handle_sigint; + sigemptyset (&action.sa_mask); + action.sa_flags = SA_RESTART; + sigaction (SIGINT, &action, NULL); config = notmuch_config_open (ctx, NULL, NULL); if (config == NULL) @@ -396,10 +431,22 @@ notmuch_new_command (void *ctx, dot_notmuch_path = talloc_asprintf (ctx, "%s/%s", db_path, ".notmuch"); if (stat (dot_notmuch_path, &st)) { - new_database = 1; + int count; + + count = 0; + count_files (db_path, &count); + if (interrupted) + return 1; + + printf ("Found %d total files. \n", count); notmuch = notmuch_database_create (db_path); + add_files_state.ignore_read_only_directories = FALSE; + add_files_state.total_files = count; } else { - notmuch = notmuch_database_open (db_path); + notmuch = notmuch_database_open (db_path, + NOTMUCH_DATABASE_MODE_READ_WRITE); + add_files_state.ignore_read_only_directories = TRUE; + add_files_state.total_files = 0; } if (notmuch == NULL) @@ -408,18 +455,7 @@ notmuch_new_command (void *ctx, talloc_free (dot_notmuch_path); dot_notmuch_path = NULL; - if (new_database) { - int count; - count_files (db_path, &count); - add_files_state.ignore_read_only_directories = FALSE; - add_files_state.total_files = count; - } else { - add_files_state.ignore_read_only_directories = TRUE; - add_files_state.total_files = 0; - } - add_files_state.saw_read_only_directory = FALSE; - add_files_state.total_files = 0; add_files_state.processed_files = 0; add_files_state.added_messages = 0; gettimeofday (&add_files_state.tv_start, NULL); @@ -452,7 +488,7 @@ notmuch_new_command (void *ctx, if (elapsed > 1 && ! add_files_state.saw_read_only_directory) { printf ("\nTip: If you have any sub-directories that are archives (that is,\n" - "they will never receive new mail), marking these directores as\n" + "they will never receive new mail), marking these directories as\n" "read-only (chmod u-w /path/to/dir) will make \"notmuch new\"\n" "much more efficient (it won't even look in those directories).\n"); } @@ -464,5 +500,5 @@ notmuch_new_command (void *ctx, notmuch_database_close (notmuch); - return ret; + return ret || interrupted; }