--- /dev/null
+Return-Path: <jani@nikula.org>\r
+X-Original-To: notmuch@notmuchmail.org\r
+Delivered-To: notmuch@notmuchmail.org\r
+Received: from localhost (localhost [127.0.0.1])\r
+ by arlo.cworth.org (Postfix) with ESMTP id 195076DE0360\r
+ for <notmuch@notmuchmail.org>; Fri, 15 Apr 2016 12:31:02 -0700 (PDT)\r
+X-Virus-Scanned: Debian amavisd-new at cworth.org\r
+X-Amavis-Alert: BAD HEADER SECTION, Duplicate header field: "References"\r
+X-Spam-Flag: NO\r
+X-Spam-Score: -0.557\r
+X-Spam-Level: \r
+X-Spam-Status: No, score=-0.557 tagged_above=-999 required=5 tests=[AWL=0.163,\r
+ DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_DNSWL_LOW=-0.7,\r
+ RCVD_IN_MSPIKE_H3=-0.01, RCVD_IN_MSPIKE_WL=-0.01] autolearn=disabled\r
+Received: from arlo.cworth.org ([127.0.0.1])\r
+ by localhost (arlo.cworth.org [127.0.0.1]) (amavisd-new, port 10024)\r
+ with ESMTP id KjVxt2cZ6-O5 for <notmuch@notmuchmail.org>;\r
+ Fri, 15 Apr 2016 12:30:54 -0700 (PDT)\r
+Received: from mail-wm0-f67.google.com (mail-wm0-f67.google.com\r
+ [74.125.82.67]) by arlo.cworth.org (Postfix) with ESMTPS id 8B0FA6DE02C6 for\r
+ <notmuch@notmuchmail.org>; Fri, 15 Apr 2016 12:30:42 -0700 (PDT)\r
+Received: by mail-wm0-f67.google.com with SMTP id n3so8629843wmn.1\r
+ for <notmuch@notmuchmail.org>; Fri, 15 Apr 2016 12:30:42 -0700 (PDT)\r
+DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;\r
+ d=nikula-org.20150623.gappssmtp.com; s=20150623;\r
+ h=from:to:cc:subject:date:message-id:in-reply-to:references\r
+ :in-reply-to:references:mime-version:content-transfer-encoding;\r
+ bh=Xp5rFuNK1ThMoMMAw6AJlxsBrC7L1Et3ctHWU3hNPDE=;\r
+ b=QFJ5fn9fxYCv4VvdbDI6s009HxS2Bfsre0L8s7aX+MhpSC7u4VCD7tU+0ScofCIiJn\r
+ senN73w3W+7UDlNlwIaUquxjqosBWx1m41tG9zFjkZacQE456xRKYpzaM4C6UE+bF6xa\r
+ t7CQtl5xZoZR1GmZkNaOsuZPmzVqPQrsKqRRmDJz7Io4vKclsa5W6o/FTE6srlWaR7r3\r
+ 3zFrt1KFOUoIAFFLbUB6+mrfFs4Z2kX6UbQSRO1IrAorF9Pah9HjmjwAyh4N1idEM7mZ\r
+ CI9cc/iH2bJVZ6qn4TF0E+sOhmIfjHZUPDYQ9PdjDHv+cOWAfVmEDaRjImUO3Uh1j6OP\r
+ 27/Q==\r
+X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;\r
+ d=1e100.net; s=20130820;\r
+ h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\r
+ :references:in-reply-to:references:mime-version\r
+ :content-transfer-encoding;\r
+ bh=Xp5rFuNK1ThMoMMAw6AJlxsBrC7L1Et3ctHWU3hNPDE=;\r
+ b=ai2j4a1fyp5znB5uQhUhlkEtR7TipHCFKMIWY0T8o1a3b+a3Iek87M7v15KPZnyNP0\r
+ 0mFu16vAbqMdlurwU9n+Ta8x736NBg0kpMToB8q+3YHepYhM7fhol5/5WSWv2idEaUPm\r
+ MOA4vKvtAtG+m1Br3RHRKvtXNAVMrbXuLmmfcqCAF0LiRi8wYN0YuzO4q1M0VtQLKfxd\r
+ 6ObMsjBKYnoiLrK1TA45l47Ao8g/n4tjGKMl6Zafl610vkbeNDMPhEChrxI8eqbgdEQu\r
+ FKHazxlQNJCmZunmDlndizEpEbqhRBSjYtl5u4ANtfMcrBwFOymuSF41gbWKliV3VBE7\r
+ D1Dg==\r
+X-Gm-Message-State:\r
+ AOPr4FVnZF7kdP15dOCMpRIQ2wuAk2jCXpl7CJhfX3miCDSvcPzah2IJArqzZsRtSfNOjQ==\r
+X-Received: by 10.195.13.135 with SMTP id ey7mr23435188wjd.161.1460748641236; \r
+ Fri, 15 Apr 2016 12:30:41 -0700 (PDT)\r
+Received: from localhost (mobile-access-bcee7f-102.dhcp.inet.fi.\r
+ [188.238.127.102])\r
+ by smtp.gmail.com with ESMTPSA id 202sm20676452wmw.5.2016.04.15.12.30.40\r
+ (version=TLSv1/SSLv3 cipher=OTHER);\r
+ Fri, 15 Apr 2016 12:30:40 -0700 (PDT)\r
+From: Jani Nikula <jani@nikula.org>\r
+To: notmuch@notmuchmail.org\r
+Subject: [RFC PATCH 4/5] cli: use homebrew scandir in notmuch new add_files\r
+Date: Fri, 15 Apr 2016 22:29:18 +0300\r
+Message-Id:\r
+ <6e67ca7c973419213f2b9d47711b24cf7cb35d7a.1460748142.git.jani@nikula.org>\r
+X-Mailer: git-send-email 2.1.4\r
+In-Reply-To: <cover.1460748142.git.jani@nikula.org>\r
+References: <cover.1460748142.git.jani@nikula.org>\r
+In-Reply-To: <cover.1460748142.git.jani@nikula.org>\r
+References: <cover.1460748142.git.jani@nikula.org>\r
+MIME-Version: 1.0\r
+Content-Type: text/plain; charset=UTF-8\r
+Content-Transfer-Encoding: 8bit\r
+X-BeenThere: notmuch@notmuchmail.org\r
+X-Mailman-Version: 2.1.20\r
+Precedence: list\r
+List-Id: "Use and development of the notmuch mail system."\r
+ <notmuch.notmuchmail.org>\r
+List-Unsubscribe: <https://notmuchmail.org/mailman/options/notmuch>,\r
+ <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
+List-Archive: <http://notmuchmail.org/pipermail/notmuch/>\r
+List-Post: <mailto:notmuch@notmuchmail.org>\r
+List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
+List-Subscribe: <https://notmuchmail.org/mailman/listinfo/notmuch>,\r
+ <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
+X-List-Received-Date: Fri, 15 Apr 2016 19:31:02 -0000\r
+\r
+Split the scanning to files and subdirectories. Filter out ignored\r
+files etc. in the scandir filter callback.\r
+\r
+The end result is perhaps slightly easier to follow than before and it\r
+should be easier to add clever ignore mechanisms like globbing in the\r
+scandir filter callback, but it's not at all certain if this is worth\r
+the trouble.\r
+\r
+Some tests will fail due to changes in where files are ignored and\r
+what debug logging is done; I didn't bother updating the logging or\r
+the tests much at this point.\r
+---\r
+ notmuch-new.c | 275 +++++++++++++++++++++++++++++++---------------------------\r
+ 1 file changed, 148 insertions(+), 127 deletions(-)\r
+\r
+diff --git a/notmuch-new.c b/notmuch-new.c\r
+index 930cbbc9b86f..262895d466ae 100644\r
+--- a/notmuch-new.c\r
++++ b/notmuch-new.c\r
+@@ -20,6 +20,7 @@\r
+ \r
+ #include "notmuch-client.h"\r
+ #include "tag-util.h"\r
++#include "scandir.h"\r
+ \r
+ #include <unistd.h>\r
+ \r
+@@ -151,9 +152,12 @@ generic_print_progress (const char *action, const char *object,\r
+ }\r
+ \r
+ static int\r
+-dirent_sort_strcmp_name (const struct dirent **a, const struct dirent **b)\r
++dirent_sort_strcmp_name (const void *_a, const void *_b)\r
+ {\r
+- return strcmp ((*a)->d_name, (*b)->d_name);\r
++ char * const *a = _a;\r
++ char * const *b = _b;\r
++\r
++ return strcmp (*a, *b);\r
+ }\r
+ \r
+ /* Return the type of a directory entry relative to path as a stat(2)\r
+@@ -206,18 +210,14 @@ dirent_type (const char *path, const struct dirent *entry)\r
+ * Return 1 if the directory looks like a Maildir and 0 otherwise.\r
+ */\r
+ static int\r
+-_entries_resemble_maildir (const char *path, struct dirent **entries, int count)\r
++_entries_resemble_maildir (char **subdirs, int count)\r
+ {\r
+ int i, found = 0;\r
+ \r
+ for (i = 0; i < count; i++) {\r
+- if (dirent_type (path, entries[i]) != S_IFDIR)\r
+- continue;\r
+-\r
+- if (strcmp(entries[i]->d_name, "new") == 0 ||\r
+- strcmp(entries[i]->d_name, "cur") == 0 ||\r
+- strcmp(entries[i]->d_name, "tmp") == 0)\r
+- {\r
++ if (strcmp(subdirs[i], "new") == 0 ||\r
++ strcmp(subdirs[i], "cur") == 0 ||\r
++ strcmp(subdirs[i], "tmp") == 0) {\r
+ found++;\r
+ if (found == 3)\r
+ return 1;\r
+@@ -241,6 +241,49 @@ _entry_in_ignore_list (const char *entry, add_files_state_t *state)\r
+ return FALSE;\r
+ }\r
+ \r
++struct filter {\r
++ const char *path;\r
++ add_files_state_t *state;\r
++ int entry_type;\r
++};\r
++\r
++static int filter_fn (const struct dirent *entry, void *context)\r
++{\r
++ struct filter *filter = context;\r
++ int entry_type;\r
++\r
++ /* Ignore any files/directories the user has configured to\r
++ * ignore. We do this before dirent_type both for performance\r
++ * and because we don't care if dirent_type fails on entries\r
++ * that are explicitly ignored.\r
++ */\r
++ if (_entry_in_ignore_list (entry->d_name, filter->state)) {\r
++ if (filter->state->debug)\r
++ printf ("(D) add_files, pass 1: explicitly ignoring %s/%s\n",\r
++ filter->path, entry->d_name);\r
++ return 0;\r
++ }\r
++\r
++ /* We only want to descend into directories (and symlinks to\r
++ * directories). */\r
++ entry_type = dirent_type (filter->path, entry);\r
++ if (entry_type == -1) {\r
++ /* Be pessimistic, e.g. so we don't lose lots of mail just\r
++ * because a user broke a symlink. */\r
++ fprintf (stderr, "Error reading file %s/%s: %s\n",\r
++ filter->path, entry->d_name, strerror (errno));\r
++ return -1;\r
++ }\r
++\r
++ if (entry_type != filter->entry_type)\r
++ return 0;\r
++\r
++ if (strcmp (entry->d_name, ".") == 0 || strcmp (entry->d_name, "..") == 0)\r
++ return 0;\r
++\r
++ return 1;\r
++}\r
++\r
+ /* Add a single file to the database. */\r
+ static notmuch_status_t\r
+ add_file (notmuch_database_t *notmuch, const char *filename,\r
+@@ -345,18 +388,22 @@ add_files (notmuch_database_t *notmuch,\r
+ const char *path,\r
+ add_files_state_t *state)\r
+ {\r
+- struct dirent *entry = NULL;\r
+ char *next = NULL;\r
+ time_t fs_mtime, db_mtime;\r
+ notmuch_status_t status, ret = NOTMUCH_STATUS_SUCCESS;\r
+- struct dirent **fs_entries = NULL;\r
+- int i, num_fs_entries = 0, entry_type;\r
++ char **fs_files = NULL, **fs_subdirs = NULL;\r
++ int num_fs_files = 0, num_fs_subdirs = 0;\r
++ int i;\r
+ notmuch_directory_t *directory;\r
+ notmuch_filenames_t *db_files = NULL;\r
+ notmuch_filenames_t *db_subdirs = NULL;\r
+ time_t stat_time;\r
+ struct stat st;\r
+ notmuch_bool_t is_maildir;\r
++ struct filter filter = {\r
++ .path = path,\r
++ .state = state,\r
++ };\r
+ \r
+ if (stat (path, &st)) {\r
+ fprintf (stderr, "Error reading directory %s: %s\n",\r
+@@ -410,11 +457,11 @@ add_files (notmuch_database_t *notmuch,\r
+ \r
+ /* If the database knows about this directory, then we sort based\r
+ * on strcmp to match the database sorting. */\r
+- num_fs_entries = scandir (path, &fs_entries, 0,\r
+- directory ?\r
+- dirent_sort_strcmp_name : NULL);\r
+-\r
+- if (num_fs_entries == -1) {\r
++ filter.entry_type = S_IFDIR;\r
++ num_fs_subdirs = scandirx (path, &fs_subdirs, filter_fn,\r
++ directory ? dirent_sort_strcmp_name : NULL,\r
++ &filter);\r
++ if (num_fs_subdirs == -1) {\r
+ fprintf (stderr, "Error opening directory %s: %s\n",\r
+ path, strerror (errno));\r
+ /* We consider this a fatal error because, if a user moved a\r
+@@ -426,50 +473,20 @@ add_files (notmuch_database_t *notmuch,\r
+ }\r
+ \r
+ /* Pass 1: Recurse into all sub-directories. */\r
+- is_maildir = _entries_resemble_maildir (path, fs_entries, num_fs_entries);\r
+-\r
+- for (i = 0; i < num_fs_entries; i++) {\r
+- if (interrupted)\r
+- break;\r
++ is_maildir = _entries_resemble_maildir (fs_subdirs, num_fs_subdirs);\r
+ \r
+- entry = fs_entries[i];\r
++ for (i = 0; i < num_fs_subdirs && !interrupted; i++) {\r
++ const char *name = fs_subdirs[i];\r
+ \r
+- /* Ignore any files/directories the user has configured to\r
+- * ignore. We do this before dirent_type both for performance\r
+- * and because we don't care if dirent_type fails on entries\r
+- * that are explicitly ignored.\r
++ /*\r
++ * Ignore the .notmuch directory and any "tmp" directory that\r
++ * appears within a maildir.\r
+ */\r
+- if (_entry_in_ignore_list (entry->d_name, state)) {\r
+- if (state->debug)\r
+- printf ("(D) add_files, pass 1: explicitly ignoring %s/%s\n",\r
+- path, entry->d_name);\r
++ if ((is_maildir && strcmp (name, "tmp") == 0) ||\r
++ strcmp (name, ".notmuch") == 0)\r
+ continue;\r
+- }\r
+ \r
+- /* We only want to descend into directories (and symlinks to\r
+- * directories). */\r
+- entry_type = dirent_type (path, entry);\r
+- if (entry_type == -1) {\r
+- /* Be pessimistic, e.g. so we don't lose lots of mail just\r
+- * because a user broke a symlink. */\r
+- fprintf (stderr, "Error reading file %s/%s: %s\n",\r
+- path, entry->d_name, strerror (errno));\r
+- return NOTMUCH_STATUS_FILE_ERROR;\r
+- } else if (entry_type != S_IFDIR) {\r
+- continue;\r
+- }\r
+-\r
+- /* Ignore special directories to avoid infinite recursion.\r
+- * Also ignore the .notmuch directory and any "tmp" directory\r
+- * that appears within a maildir.\r
+- */\r
+- if (strcmp (entry->d_name, ".") == 0 ||\r
+- strcmp (entry->d_name, "..") == 0 ||\r
+- (is_maildir && strcmp (entry->d_name, "tmp") == 0) ||\r
+- strcmp (entry->d_name, ".notmuch") == 0)\r
+- continue;\r
+-\r
+- next = talloc_asprintf (notmuch, "%s/%s", path, entry->d_name);\r
++ next = talloc_asprintf (notmuch, "%s/%s", path, name);\r
+ status = add_files (notmuch, next, state);\r
+ if (status) {\r
+ ret = status;\r
+@@ -498,27 +515,71 @@ add_files (notmuch_database_t *notmuch,\r
+ db_subdirs = notmuch_directory_get_child_directories (directory);\r
+ }\r
+ \r
+- /* Pass 2: Scan for new files, removed files, and removed directories. */\r
+- for (i = 0; i < num_fs_entries; i++)\r
+- {\r
+- if (interrupted)\r
+- break;\r
++ /* Pass 1½: Scan for removed directories. */\r
++ for (i = 0; i < num_fs_subdirs && !interrupted; i++) {\r
++ const char *name = fs_subdirs[i];\r
+ \r
+- entry = fs_entries[i];\r
++ /* Check if we've walked past any names in db_subdirs. If so,\r
++ * these have been deleted. */\r
++ while (notmuch_filenames_valid (db_subdirs) &&\r
++ strcmp (notmuch_filenames_get (db_subdirs), name) < 0) {\r
++ char *absolute = talloc_asprintf (state->removed_directories,\r
++ "%s/%s", path,\r
++ notmuch_filenames_get (db_subdirs));\r
+ \r
+- /* Ignore files & directories user has configured to be ignored */\r
+- if (_entry_in_ignore_list (entry->d_name, state)) {\r
+ if (state->debug)\r
+- printf ("(D) add_files, pass 2: explicitly ignoring %s/%s\n",\r
+- path, entry->d_name);\r
+- continue;\r
++ printf ("(D) add_files, pass 2: queuing passed directory %s for deletion from database\n",\r
++ absolute);\r
++\r
++ _filename_list_add (state->removed_directories, absolute);\r
++\r
++ notmuch_filenames_move_to_next (db_subdirs);\r
+ }\r
+ \r
+- /* Check if we've walked past any names in db_files or\r
+- * db_subdirs. If so, these have been deleted. */\r
++ if (notmuch_filenames_valid (db_subdirs) &&\r
++ strcmp (notmuch_filenames_get (db_subdirs), name) == 0)\r
++ notmuch_filenames_move_to_next (db_subdirs);\r
++ }\r
++\r
++ /* Now that we've walked the whole filesystem subdir list, subdirs\r
++ * left over in the database list have been deleted. */\r
++ while (notmuch_filenames_valid (db_subdirs)) {\r
++ char *absolute = talloc_asprintf (state->removed_directories,\r
++ "%s/%s", path,\r
++ notmuch_filenames_get (db_subdirs));\r
++\r
++ if (state->debug)\r
++ printf ("(D) add_files, pass 3: queuing leftover directory %s for deletion from database\n",\r
++ absolute);\r
++\r
++ _filename_list_add (state->removed_directories, absolute);\r
++\r
++ notmuch_filenames_move_to_next (db_subdirs);\r
++ }\r
++\r
++ /* Pass 2: Scan for new and removed files. */\r
++ filter.entry_type = S_IFREG;\r
++ num_fs_files = scandirx (path, &fs_files, filter_fn,\r
++ directory ? dirent_sort_strcmp_name : NULL,\r
++ &filter);\r
++ if (num_fs_files == -1) {\r
++ fprintf (stderr, "Error opening directory %s: %s\n",\r
++ path, strerror (errno));\r
++ /* We consider this a fatal error because, if a user moved a\r
++ * message from another directory that we were able to scan\r
++ * into this directory, skipping this directory will cause\r
++ * that message to be lost. */\r
++ ret = NOTMUCH_STATUS_FILE_ERROR;\r
++ goto DONE;\r
++ }\r
++\r
++ for (i = 0; i < num_fs_files && !interrupted; i++) {\r
++ const char *name = fs_files[i];\r
++\r
++ /* Check if we've walked past any names in db_files. If so,\r
++ * these have been deleted. */\r
+ while (notmuch_filenames_valid (db_files) &&\r
+- strcmp (notmuch_filenames_get (db_files), entry->d_name) < 0)\r
+- {\r
++ strcmp (notmuch_filenames_get (db_files), name) < 0) {\r
+ char *absolute = talloc_asprintf (state->removed_files,\r
+ "%s/%s", path,\r
+ notmuch_filenames_get (db_files));\r
+@@ -532,46 +593,16 @@ add_files (notmuch_database_t *notmuch,\r
+ notmuch_filenames_move_to_next (db_files);\r
+ }\r
+ \r
+- while (notmuch_filenames_valid (db_subdirs) &&\r
+- strcmp (notmuch_filenames_get (db_subdirs), entry->d_name) <= 0)\r
+- {\r
+- const char *filename = notmuch_filenames_get (db_subdirs);\r
+-\r
+- if (strcmp (filename, entry->d_name) < 0)\r
+- {\r
+- char *absolute = talloc_asprintf (state->removed_directories,\r
+- "%s/%s", path, filename);\r
+- if (state->debug)\r
+- printf ("(D) add_files, pass 2: queuing passed directory %s for deletion from database\n",\r
+- absolute);\r
+-\r
+- _filename_list_add (state->removed_directories, absolute);\r
+- }\r
+-\r
+- notmuch_filenames_move_to_next (db_subdirs);\r
+- }\r
+-\r
+- /* Only add regular files (and symlinks to regular files). */\r
+- entry_type = dirent_type (path, entry);\r
+- if (entry_type == -1) {\r
+- fprintf (stderr, "Error reading file %s/%s: %s\n",\r
+- path, entry->d_name, strerror (errno));\r
+- return NOTMUCH_STATUS_FILE_ERROR;\r
+- } else if (entry_type != S_IFREG) {\r
+- continue;\r
+- }\r
+-\r
+ /* Don't add a file that we've added before. */\r
+ if (notmuch_filenames_valid (db_files) &&\r
+- strcmp (notmuch_filenames_get (db_files), entry->d_name) == 0)\r
+- {\r
++ strcmp (notmuch_filenames_get (db_files), name) == 0) {\r
+ notmuch_filenames_move_to_next (db_files);\r
+ continue;\r
+ }\r
+ \r
+ /* We're now looking at a regular file that doesn't yet exist\r
+ * in the database, so add it. */\r
+- next = talloc_asprintf (notmuch, "%s/%s", path, entry->d_name);\r
++ next = talloc_asprintf (notmuch, "%s/%s", path, name);\r
+ \r
+ state->processed_files++;\r
+ \r
+@@ -605,10 +636,9 @@ add_files (notmuch_database_t *notmuch,\r
+ if (interrupted)\r
+ goto DONE;\r
+ \r
+- /* Now that we've walked the whole filesystem list, anything left\r
+- * over in the database lists has been deleted. */\r
+- while (notmuch_filenames_valid (db_files))\r
+- {\r
++ /* Now that we've walked the whole filesystem file list, files\r
++ * left over in the database list have been deleted. */\r
++ while (notmuch_filenames_valid (db_files)) {\r
+ char *absolute = talloc_asprintf (state->removed_files,\r
+ "%s/%s", path,\r
+ notmuch_filenames_get (db_files));\r
+@@ -621,21 +651,6 @@ add_files (notmuch_database_t *notmuch,\r
+ notmuch_filenames_move_to_next (db_files);\r
+ }\r
+ \r
+- while (notmuch_filenames_valid (db_subdirs))\r
+- {\r
+- char *absolute = talloc_asprintf (state->removed_directories,\r
+- "%s/%s", path,\r
+- notmuch_filenames_get (db_subdirs));\r
+-\r
+- if (state->debug)\r
+- printf ("(D) add_files, pass 3: queuing leftover directory %s for deletion from database\n",\r
+- absolute);\r
+-\r
+- _filename_list_add (state->removed_directories, absolute);\r
+-\r
+- notmuch_filenames_move_to_next (db_subdirs);\r
+- }\r
+-\r
+ /* If the directory's mtime is the same as the wall-clock time\r
+ * when we stat'ed the directory, we skip updating the mtime in\r
+ * the database because a message could be delivered later in this\r
+@@ -647,11 +662,17 @@ add_files (notmuch_database_t *notmuch,\r
+ DONE:\r
+ if (next)\r
+ talloc_free (next);\r
+- if (fs_entries) {\r
+- for (i = 0; i < num_fs_entries; i++)\r
+- free (fs_entries[i]);\r
++ if (fs_subdirs) {\r
++ for (i = 0; i < num_fs_subdirs; i++)\r
++ free (fs_subdirs[i]);\r
++\r
++ free (fs_subdirs);\r
++ }\r
++ if (fs_files) {\r
++ for (i = 0; i < num_fs_files; i++)\r
++ free (fs_files[i]);\r
+ \r
+- free (fs_entries);\r
++ free (fs_files);\r
+ }\r
+ if (db_subdirs)\r
+ notmuch_filenames_destroy (db_subdirs);\r
+-- \r
+2.1.4\r
+\r