From b3f3fbd0bbfd2625ab6eb890dee20237c28ecf5e Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 8 May 2012 00:08:35 +0300 Subject: [PATCH] Re: [PATCH 2/2] new: Centralize file type stat-ing logic --- cd/f143d3e1a7f857a693d1c664ad1e917efa5fbc | 546 ++++++++++++++++++++++ 1 file changed, 546 insertions(+) create mode 100644 cd/f143d3e1a7f857a693d1c664ad1e917efa5fbc diff --git a/cd/f143d3e1a7f857a693d1c664ad1e917efa5fbc b/cd/f143d3e1a7f857a693d1c664ad1e917efa5fbc new file mode 100644 index 000000000..e26b9ad9a --- /dev/null +++ b/cd/f143d3e1a7f857a693d1c664ad1e917efa5fbc @@ -0,0 +1,546 @@ +Return-Path: +X-Original-To: notmuch@notmuchmail.org +Delivered-To: notmuch@notmuchmail.org +Received: from localhost (localhost [127.0.0.1]) + by olra.theworths.org (Postfix) with ESMTP id 460FC431FB6 + for ; Mon, 7 May 2012 14:08:39 -0700 (PDT) +X-Virus-Scanned: Debian amavisd-new at olra.theworths.org +X-Spam-Flag: NO +X-Spam-Score: -0.699 +X-Spam-Level: +X-Spam-Status: No, score=-0.699 tagged_above=-999 required=5 + tests=[HTML_MESSAGE=0.001, RCVD_IN_DNSWL_LOW=-0.7] autolearn=disabled +Received: from olra.theworths.org ([127.0.0.1]) + by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024) + with ESMTP id v9+Gi4YCfqE6 for ; + Mon, 7 May 2012 14:08:37 -0700 (PDT) +Received: from mail-pb0-f53.google.com (mail-pb0-f53.google.com + [209.85.160.53]) (using TLSv1 with cipher RC4-SHA (128/128 bits)) + (No client certificate requested) + by olra.theworths.org (Postfix) with ESMTPS id AF375431FAE + for ; Mon, 7 May 2012 14:08:37 -0700 (PDT) +Received: by pbbrr13 with SMTP id rr13so8240660pbb.26 + for ; Mon, 07 May 2012 14:08:35 -0700 (PDT) +X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=google.com; s=20120113; + h=mime-version:in-reply-to:references:date:message-id:subject:from:to + :cc:content-type:x-gm-message-state; + bh=vmHcNGrU4I/7z3kpCwJhVirRk0Hap1yMXRTbQFRFyhE=; + b=DPr1y4CbTOPTtEvpeHD99HPfPhoTveicyQjj6Bg4OkOBvUowBKdOQMBa02qjd4z07R + R4mU/CesDgYezoLZgg9E5u0IEnC1GIqMX6b7L6mRzGLZrLtfyRixYs3F17RzlQtwoBNc + 1V1eH7WMdOGHDjJq6GJoIjoGSpJETl6eoac5umml1eiWdswcWZvNkpDdmSVlZUChb5Zo + /3pcTk00NO0NoqJLfeIOVU7agItvYeJ87AgAbWJShTP+q/Brz643VLNre3gPcYFn23CS + rQqdzTH8fh7L/w+pgMRfZHmSgPGfLc/2C+rRv3DvUCT4mSZirmGaq0zD2MbXaZMJOphx + eakQ== +MIME-Version: 1.0 +Received: by 10.68.236.5 with SMTP id uq5mr410171pbc.165.1336424915761; Mon, + 07 May 2012 14:08:35 -0700 (PDT) +Received: by 10.68.52.33 with HTTP; Mon, 7 May 2012 14:08:35 -0700 (PDT) +Received: by 10.68.52.33 with HTTP; Mon, 7 May 2012 14:08:35 -0700 (PDT) +In-Reply-To: <1336414186-15293-3-git-send-email-amdragon@mit.edu> +References: <1336414186-15293-1-git-send-email-amdragon@mit.edu> + <1336414186-15293-3-git-send-email-amdragon@mit.edu> +Date: Tue, 8 May 2012 00:08:35 +0300 +Message-ID: + +Subject: Re: [PATCH 2/2] new: Centralize file type stat-ing logic +From: Jani Nikula +To: Austin Clements +Content-Type: multipart/alternative; boundary=047d7b33c9c65f7b8204bf78ac10 +X-Gm-Message-State: + ALoCoQmhKRKJHFxNKNd4Q3OgSi6Wk0CGmXs1VXfUKMYwCjTunscnVZ4zVse3K3U19uflXQ4VgCwf +Cc: Notmuch Mail , Vladimir Marek +X-BeenThere: notmuch@notmuchmail.org +X-Mailman-Version: 2.1.13 +Precedence: list +List-Id: "Use and development of the notmuch mail system." + +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +X-List-Received-Date: Mon, 07 May 2012 21:08:39 -0000 + +--047d7b33c9c65f7b8204bf78ac10 +Content-Type: text/plain; charset=UTF-8 + +On May 7, 2012 9:10 PM, "Austin Clements" wrote: +> +> This moves our logic to get a file's type into one function. This has +> several benefits: we can support OSes and file systems that do not +> provide dirent.d_type or always return DT_UNKNOWN, complex +> symlink-handling logic has been replaced by a simple stat fall-through +> in one place, and the error message for un-stat-able file is more +> accurate (previously, the error always mentioned directories, even +> though a broken symlink is not a directory). + +Please find some quick drive-by-review below. + +J. + +> --- +> notmuch-new.c | 99 +++++++++++++++++++++++++++++++++++----------------------- +> test/new | 2 +- +> 2 files changed, 60 insertions(+), 41 deletions(-) +> +> diff --git a/notmuch-new.c b/notmuch-new.c +> index cb720cc..cf2580e 100644 +> --- a/notmuch-new.c +> +++ b/notmuch-new.c +> @@ -154,6 +154,44 @@ dirent_sort_strcmp_name (const struct dirent **a, +const struct dirent **b) +> return strcmp ((*a)->d_name, (*b)->d_name); +> } +> +> +/* Return the type of a directory entry relative to path as a stat(2) +> + * mode. Like stat, this follows symlinks. Returns -1 and sets errno +> + * if the file's type cannot be determined (which includes dangling +> + * symlinks). +> + */ +> +static int +> +dirent_type (const char *path, const struct dirent *entry) +> +{ +> + struct stat statbuf; +> + char *abspath; +> + int err; +> + +> +#ifdef _DIRENT_HAVE_D_TYPE +> + /* Mapping from d_type to stat mode_t. We omit DT_LNK so that +> + * we'll fall through to stat and get the real file type. */ +> + static const mode_t modes[] = { +> + [DT_BLK] = S_IFBLK, +> + [DT_CHR] = S_IFCHR, +> + [DT_DIR] = S_IFDIR, +> + [DT_FIFO] = S_IFIFO, +> + [DT_REG] = S_IFREG, +> + [DT_SOCK] = S_IFSOCK +> + }; +> + if (entry->d_type < sizeof(modes)/sizeof(modes[0]) && + +ARRAY_SIZE() + +> + modes[entry->d_type]) +> + return modes[entry->d_type]; +> +#endif +> + +> + abspath = talloc_asprintf (NULL, "%s/%s", path, entry->d_name); +> + if (!abspath) +> + return -1; + +Does talloc set errno in this case? I suspect not. + +> + err = stat(abspath, &statbuf); +> + talloc_free (abspath); + +This likely breaks your promise about errno. You can't trust talloc_free() +not calling some function that sets errno. + +> + if (err < 0) +> + return -1; +> + return statbuf.st_mode & S_IFMT; +> +} +> + +> /* Test if the directory looks like a Maildir directory. +> * +> * Search through the array of directory entries to see if we can find all +> @@ -162,12 +200,12 @@ dirent_sort_strcmp_name (const struct dirent **a, +const struct dirent **b) +> * Return 1 if the directory looks like a Maildir and 0 otherwise. +> */ +> static int +> -_entries_resemble_maildir (struct dirent **entries, int count) +> +_entries_resemble_maildir (const char *path, struct dirent **entries, +int count) +> { +> int i, found = 0; +> +> for (i = 0; i < count; i++) { +> - if (entries[i]->d_type != DT_DIR && entries[i]->d_type != +DT_UNKNOWN) +> + if (dirent_type (path, entries[i]) != S_IFDIR) +> continue; +> +> if (strcmp(entries[i]->d_name, "new") == 0 || +> @@ -250,7 +288,7 @@ add_files_recursive (notmuch_database_t *notmuch, +> notmuch_status_t status, ret = NOTMUCH_STATUS_SUCCESS; +> notmuch_message_t *message = NULL; +> struct dirent **fs_entries = NULL; +> - int i, num_fs_entries; +> + int i, num_fs_entries, entry_type; +> notmuch_directory_t *directory; +> notmuch_filenames_t *db_files = NULL; +> notmuch_filenames_t *db_subdirs = NULL; +> @@ -317,7 +355,7 @@ add_files_recursive (notmuch_database_t *notmuch, +> } +> +> /* Pass 1: Recurse into all sub-directories. */ +> - is_maildir = _entries_resemble_maildir (fs_entries, num_fs_entries); +> + is_maildir = _entries_resemble_maildir (path, fs_entries, +num_fs_entries); +> +> for (i = 0; i < num_fs_entries; i++) { +> if (interrupted) +> @@ -325,17 +363,16 @@ add_files_recursive (notmuch_database_t *notmuch, +> +> entry = fs_entries[i]; +> +> - /* We only want to descend into directories. +> - * But symlinks can be to directories too, of course. +> - * +> - * And if the filesystem doesn't tell us the file type in the +> - * scandir results, then it might be a directory (and if not, +> - * then we'll stat and return immediately in the next level of +> - * recursion). */ +> - if (entry->d_type != DT_DIR && +> - entry->d_type != DT_LNK && +> - entry->d_type != DT_UNKNOWN) +> - { +> + /* We only want to descend into directories (and symlinks to +> + * directories). */ +> + entry_type = dirent_type (path, entry); +> + if (entry_type == -1) { +> + /* Be pessimistic, e.g. so we don't loose lots of mail + +s/loose/lose/ ? + +> + * just because a user broke a symlink. */ +> + fprintf (stderr, "Error reading file %s/%s: %s\n", +> + path, entry->d_name, strerror (errno)); + +You can't trust errno here, as explained above. + +> + return NOTMUCH_STATUS_FILE_ERROR; +> + } else if (entry_type != S_IFDIR) { +> continue; +> } +> +> @@ -425,31 +462,13 @@ add_files_recursive (notmuch_database_t *notmuch, +> notmuch_filenames_move_to_next (db_subdirs); +> } +> +> - /* If we're looking at a symlink, we only want to add it if it +> - * links to a regular file, (and not to a directory, say). +> - * +> - * Similarly, if the file is of unknown type (due to filesystem +> - * limitations), then we also need to look closer. +> - * +> - * In either case, a stat does the trick. +> - */ +> - if (entry->d_type == DT_LNK || entry->d_type == DT_UNKNOWN) { +> - int err; +> - +> - next = talloc_asprintf (notmuch, "%s/%s", path, +entry->d_name); +> - err = stat (next, &st); +> - talloc_free (next); +> - next = NULL; +> - +> - /* Don't emit an error for a link pointing nowhere, since +> - * the directory-traversal pass will have already done +> - * that. */ +> - if (err) +> - continue; +> - +> - if (! S_ISREG (st.st_mode)) +> - continue; +> - } else if (entry->d_type != DT_REG) { +> + /* Only add regular files (and symlinks to regular files). */ +> + entry_type = dirent_type (path, entry); +> + if (entry_type == -1) { +> + fprintf (stderr, "Error reading file %s/%s: %s\n", +> + path, entry->d_name, strerror (errno)); + +Ditto. + +> + return NOTMUCH_STATUS_FILE_ERROR; +> + } else if (entry_type != S_IFREG) { +> continue; +> } +> +> diff --git a/test/new b/test/new +> index 26253db..e3900f5 100755 +> --- a/test/new +> +++ b/test/new +> @@ -140,7 +140,7 @@ test_begin_subtest "Broken symlink aborts" +> ln -s does-not-exist "${MAIL_DIR}/broken" +> output=$(NOTMUCH_NEW 2>&1) +> test_expect_equal "$output" \ +> -"Error reading directory /run/shm/nm/tmp.new/mail/broken: No such file +or directory +> +"Error reading file /run/shm/nm/tmp.new/mail/broken: No such file or +directory +> Note: A fatal error was encountered: Something went wrong trying to read +or write a file +> No new mail." +> rm "${MAIL_DIR}/broken" +> -- +> 1.7.10 +> +> _______________________________________________ +> notmuch mailing list +> notmuch@notmuchmail.org +> http://notmuchmail.org/mailman/listinfo/notmuch + +--047d7b33c9c65f7b8204bf78ac10 +Content-Type: text/html; charset=UTF-8 +Content-Transfer-Encoding: quoted-printable + +


+On May 7, 2012 9:10 PM, "Austin Clements" <amdragon@mit.edu> wrote:
+>
+> This moves our logic to get a file's type into one function. =C2= +=A0This has
+> several benefits: we can support OSes and file systems that do not
+> provide dirent.d_type or always return DT_UNKNOWN, complex
+> symlink-handling logic has been replaced by a simple stat fall-through= +
+> in one place, and the error message for un-stat-able file is more
+> accurate (previously, the error always mentioned directories, even
+> though a broken symlink is not a directory).

+

Please find some quick drive-by-review below.

+

J.

+

> ---
+> =C2=A0notmuch-new.c | =C2=A0 99 ++++++++++++++++++++++++++++++++++----= +-------------------
+> =C2=A0test/new =C2=A0 =C2=A0 =C2=A0| =C2=A0 =C2=A02 +-
+> =C2=A02 files changed, 60 insertions(+), 41 deletions(-)
+>
+> diff --git a/notmuch-new.c b/notmuch-new.c
+> index cb720cc..cf2580e 100644
+> --- a/notmuch-new.c
+> +++ b/notmuch-new.c
+> @@ -154,6 +154,44 @@ dirent_sort_strcmp_name (const struct dirent **a,= + const struct dirent **b)
+> =C2=A0 =C2=A0 return strcmp ((*a)->d_name, (*b)->d_name);
+> =C2=A0}
+>
+> +/* Return the type of a directory entry relative to path as a stat(2)= +
+> + * mode. =C2=A0Like stat, this follows symlinks. =C2=A0Returns -1 and= + sets errno
+> + * if the file's type cannot be determined (which includes dangli= +ng
+> + * symlinks).
+> + */
+> +static int
+> +dirent_type (const char *path, const struct dirent *entry)
+> +{
+> + =C2=A0 =C2=A0struct stat statbuf;
+> + =C2=A0 =C2=A0char *abspath;
+> + =C2=A0 =C2=A0int err;
+> +
+> +#ifdef _DIRENT_HAVE_D_TYPE
+> + =C2=A0 =C2=A0/* Mapping from d_type to stat mode_t. =C2=A0We omit DT= +_LNK so that
+> + =C2=A0 =C2=A0 * we'll fall through to stat and get the real file= + type. */
+> + =C2=A0 =C2=A0static const mode_t modes[] =3D {
+> + =C2=A0 =C2=A0 =C2=A0 [DT_BLK] =C2=A0=3D S_IFBLK,
+> + =C2=A0 =C2=A0 =C2=A0 [DT_CHR] =C2=A0=3D S_IFCHR,
+> + =C2=A0 =C2=A0 =C2=A0 [DT_DIR] =C2=A0=3D S_IFDIR,
+> + =C2=A0 =C2=A0 =C2=A0 [DT_FIFO] =3D S_IFIFO,
+> + =C2=A0 =C2=A0 =C2=A0 [DT_REG] =C2=A0=3D S_IFREG,
+> + =C2=A0 =C2=A0 =C2=A0 [DT_SOCK] =3D S_IFSOCK
+> + =C2=A0 =C2=A0};
+> + =C2=A0 =C2=A0if (entry->d_type < sizeof(modes)/sizeof(modes[0]= +) &&

+

ARRAY_SIZE()

+

> + =C2=A0 =C2=A0 =C2=A0 modes[entry->d_type])
+> + =C2=A0 =C2=A0 =C2=A0 return modes[entry->d_type];
+> +#endif
+> +
+> + =C2=A0 =C2=A0abspath =3D talloc_asprintf (NULL, "%s/%s", p= +ath, entry->d_name);
+> + =C2=A0 =C2=A0if (!abspath)
+> + =C2=A0 =C2=A0 =C2=A0 return -1;

+

Does talloc set errno in this case? I suspect not.

+

> + =C2=A0 =C2=A0err =3D stat(abspath, &statbuf);
+> + =C2=A0 =C2=A0talloc_free (abspath);

+

This likely breaks your promise about errno. You can't trust talloc_= +free() not calling some function that sets errno.

+

> + =C2=A0 =C2=A0if (err < 0)
+> + =C2=A0 =C2=A0 =C2=A0 return -1;
+> + =C2=A0 =C2=A0return statbuf.st_mode & S_IFMT;
+> +}
+> +
+> =C2=A0/* Test if the directory looks like a Maildir directory.
+> =C2=A0*
+> =C2=A0* Search through the array of directory entries to see if we can= + find all
+> @@ -162,12 +200,12 @@ dirent_sort_strcmp_name (const struct dirent **a= +, const struct dirent **b)
+> =C2=A0* Return 1 if the directory looks like a Maildir and 0 otherwise= +.
+> =C2=A0*/
+> =C2=A0static int
+> -_entries_resemble_maildir (struct dirent **entries, int count)
+> +_entries_resemble_maildir (const char *path, struct dirent **entries,= + int count)
+> =C2=A0{
+> =C2=A0 =C2=A0 int i, found =3D 0;
+>
+> =C2=A0 =C2=A0 for (i =3D 0; i < count; i++) {
+> - =C2=A0 =C2=A0 =C2=A0 if (entries[i]->d_type !=3D DT_DIR &&= +; entries[i]->d_type !=3D DT_UNKNOWN)
+> + =C2=A0 =C2=A0 =C2=A0 if (dirent_type (path, entries[i]) !=3D S_IFDIR= +)
+> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0continue;
+>
+> =C2=A0 =C2=A0 =C2=A0 =C2=A0if (strcmp(entries[i]->d_name, "new= +") =3D=3D 0 ||
+> @@ -250,7 +288,7 @@ add_files_recursive (notmuch_database_t *notmuch,<= +br> +> =C2=A0 =C2=A0 notmuch_status_t status, ret =3D NOTMUCH_STATUS_SUCCESS;= +
+> =C2=A0 =C2=A0 notmuch_message_t *message =3D NULL;
+> =C2=A0 =C2=A0 struct dirent **fs_entries =3D NULL;
+> - =C2=A0 =C2=A0int i, num_fs_entries;
+> + =C2=A0 =C2=A0int i, num_fs_entries, entry_type;
+> =C2=A0 =C2=A0 notmuch_directory_t *directory;
+> =C2=A0 =C2=A0 notmuch_filenames_t *db_files =3D NULL;
+> =C2=A0 =C2=A0 notmuch_filenames_t *db_subdirs =3D NULL;
+> @@ -317,7 +355,7 @@ add_files_recursive (notmuch_database_t *notmuch,<= +br> +> =C2=A0 =C2=A0 }
+>
+> =C2=A0 =C2=A0 /* Pass 1: Recurse into all sub-directories. */
+> - =C2=A0 =C2=A0is_maildir =3D _entries_resemble_maildir (fs_entries, n= +um_fs_entries);
+> + =C2=A0 =C2=A0is_maildir =3D _entries_resemble_maildir (path, fs_entr= +ies, num_fs_entries);
+>
+> =C2=A0 =C2=A0 for (i =3D 0; i < num_fs_entries; i++) {
+> =C2=A0 =C2=A0 =C2=A0 =C2=A0if (interrupted)
+> @@ -325,17 +363,16 @@ add_files_recursive (notmuch_database_t *notmuch= +,
+>
+> =C2=A0 =C2=A0 =C2=A0 =C2=A0entry =3D fs_entries[i];
+>
+> - =C2=A0 =C2=A0 =C2=A0 /* We only want to descend into directories. +> - =C2=A0 =C2=A0 =C2=A0 =C2=A0* But symlinks can be to directories too,= + of course.
+> - =C2=A0 =C2=A0 =C2=A0 =C2=A0*
+> - =C2=A0 =C2=A0 =C2=A0 =C2=A0* And if the filesystem doesn't tell = +us the file type in the
+> - =C2=A0 =C2=A0 =C2=A0 =C2=A0* scandir results, then it might be a dir= +ectory (and if not,
+> - =C2=A0 =C2=A0 =C2=A0 =C2=A0* then we'll stat and return immediat= +ely in the next level of
+> - =C2=A0 =C2=A0 =C2=A0 =C2=A0* recursion). */
+> - =C2=A0 =C2=A0 =C2=A0 if (entry->d_type !=3D DT_DIR &&
+> - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 entry->d_type !=3D DT_LNK &= +;&
+> - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 entry->d_type !=3D DT_UNKNOWN)= +
+> - =C2=A0 =C2=A0 =C2=A0 {
+> + =C2=A0 =C2=A0 =C2=A0 /* We only want to descend into directories (an= +d symlinks to
+> + =C2=A0 =C2=A0 =C2=A0 =C2=A0* directories). */
+> + =C2=A0 =C2=A0 =C2=A0 entry_type =3D dirent_type (path, entry);
+> + =C2=A0 =C2=A0 =C2=A0 if (entry_type =3D=3D -1) {
+> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 /* Be pessimistic, e.g. so we don= +'t loose lots of mail

+

s/loose/lose/ ?

+

> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0* just because a user br= +oke a symlink. */
+> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 fprintf (stderr, "Error read= +ing file %s/%s: %s\n",
+> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= +=A0path, entry->d_name, strerror (errno));

+

You can't trust errno here, as explained above.

+

> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return NOTMUCH_STATUS_FILE_ERR= +OR;
+> + =C2=A0 =C2=A0 =C2=A0 } else if (entry_type !=3D S_IFDIR) {
+> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0continue;
+> =C2=A0 =C2=A0 =C2=A0 =C2=A0}
+>
+> @@ -425,31 +462,13 @@ add_files_recursive (notmuch_database_t *notmuch= +,
+> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0notmuch_filenames_move_to_nex= +t (db_subdirs);
+> =C2=A0 =C2=A0 =C2=A0 =C2=A0}
+>
+> - =C2=A0 =C2=A0 =C2=A0 /* If we're looking at a symlink, we only w= +ant to add it if it
+> - =C2=A0 =C2=A0 =C2=A0 =C2=A0* links to a regular file, (and not to a = +directory, say).
+> - =C2=A0 =C2=A0 =C2=A0 =C2=A0*
+> - =C2=A0 =C2=A0 =C2=A0 =C2=A0* Similarly, if the file is of unknown ty= +pe (due to filesystem
+> - =C2=A0 =C2=A0 =C2=A0 =C2=A0* limitations), then we also need to look= + closer.
+> - =C2=A0 =C2=A0 =C2=A0 =C2=A0*
+> - =C2=A0 =C2=A0 =C2=A0 =C2=A0* In either case, a stat does the trick.<= +br> +> - =C2=A0 =C2=A0 =C2=A0 =C2=A0*/
+> - =C2=A0 =C2=A0 =C2=A0 if (entry->d_type =3D=3D DT_LNK || entry->= +;d_type =3D=3D DT_UNKNOWN) {
+> - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 int err;
+> -
+> - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 next =3D talloc_asprintf (notmuch= +, "%s/%s", path, entry->d_name);
+> - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 err =3D stat (next, &st);
+> - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 talloc_free (next);
+> - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 next =3D NULL;
+> -
+> - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 /* Don't emit an error for a = +link pointing nowhere, since
+> - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0* the directory-traversal p= +ass will have already done
+> - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0* that. */
+> - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (err)
+> - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 continue;
+> -
+> - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (! S_ISREG (st.st_mode))
+> - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 continue;
+> - =C2=A0 =C2=A0 =C2=A0 } else if (entry->d_type !=3D DT_REG) {
+> + =C2=A0 =C2=A0 =C2=A0 /* Only add regular files (and symlinks to regu= +lar files). */
+> + =C2=A0 =C2=A0 =C2=A0 entry_type =3D dirent_type (path, entry);
+> + =C2=A0 =C2=A0 =C2=A0 if (entry_type =3D=3D -1) {
+> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 fprintf (stderr, "Error read= +ing file %s/%s: %s\n",
+> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= +=A0path, entry->d_name, strerror (errno));

+

Ditto.

+

> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return NOTMUCH_STATUS_FILE_ERR= +OR;
+> + =C2=A0 =C2=A0 =C2=A0 } else if (entry_type !=3D S_IFREG) {
+> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0continue;
+> =C2=A0 =C2=A0 =C2=A0 =C2=A0}
+>
+> diff --git a/test/new b/test/new
+> index 26253db..e3900f5 100755
+> --- a/test/new
+> +++ b/test/new
+> @@ -140,7 +140,7 @@ test_begin_subtest "Broken symlink aborts&quo= +t;
+> =C2=A0ln -s does-not-exist "${MAIL_DIR}/broken"
+> =C2=A0output=3D$(NOTMUCH_NEW 2>&1)
+> =C2=A0test_expect_equal "$output" \
+> -"Error reading directory /run/shm/nm/tmp.new/mail/broken: No suc= +h file or directory
+> +"Error reading file /run/shm/nm/tmp.new/mail/broken: No such fil= +e or directory
+> =C2=A0Note: A fatal error was encountered: Something went wrong trying= + to read or write a file
+> =C2=A0No new mail."
+> =C2=A0rm "${MAIL_DIR}/broken"
+> --
+> 1.7.10
+>
+> _______________________________________________
+> notmuch mailing list
+> notmuch@notmuchmail.org= +
+> http://not= +muchmail.org/mailman/listinfo/notmuch
+

+ +--047d7b33c9c65f7b8204bf78ac10-- -- 2.26.2