Subject: bug#76323: 30.0.93; auth-source-pass: Annoying error when ~/.password-store doesn't exist

From: Naofumi Yasufuku <[email-masked]>
Date: Sun, 16 Feb 2025 22:57:01 +0900

Hi, Basil,

"Basil L. Contovounesios" <[email-masked]> writes:

> Naofumi Yasufuku [2025-02-16 14:30 +0900] wrote:
>
>> @@ -236,9 +236,10 @@ auth-source-pass--do-debug
>>  (defun auth-source-pass-entries ()
>>    "Return a list of all password store entries."
>>    (let ((store-dir (expand-file-name auth-source-pass-filename)))
>> -    (mapcar
>> -     (lambda (file) (file-name-sans-extension (file-relative-name file store-dir)))
>> -     (directory-files-recursively store-dir "\\.gpg\\'"))))
>> +    (when (file-directory-p store-dir)
>> +      (mapcar
>> +       (lambda (file) (file-name-sans-extension (file-relative-name file store-dir)))
>> +       (directory-files-recursively store-dir "\\.gpg\\'")))))
>
> Would it be any better to have the filesystem read and error check in a
> single atomic step?  For example:
>
> diff --git a/lisp/auth-source-pass.el b/lisp/auth-source-pass.el
> index b0b32ca263b..80e412e1697 100644
> --- a/lisp/auth-source-pass.el
> +++ b/lisp/auth-source-pass.el
> @@ -243,7 +243,8 @@ auth-source-pass-entries
>    (let ((store-dir (expand-file-name auth-source-pass-filename)))
>      (mapcar
>       (lambda (file) (file-name-sans-extension (file-relative-name file store-dir)))
> -     (directory-files-recursively store-dir "\\.gpg\\'"))))
> +     (ignore-error file-missing
> +       (directory-files-recursively store-dir "\\.gpg\\'")))))
>  
>  (defun auth-source-pass--find-match (hosts user port)
>    "Return password-store entry data matching HOSTS, USER and PORT.
>

Certainly.  I noticed that auth-source-pass-entries is called many times
for each search pattern, so as you mentioned, additional filesystem read
should be avoided as much as possible.

- Error-1: No ~/.password-store/

  rmdir ~/.password-store
  ./src/emacs -Q

  (setq auth-source-debug t)       ; enable debugging
  (require 'auth-source-pass)
  (add-to-list 'auth-sources 'password-store)
  (auth-source-search :host "host.example.com" :user "user")

-----------------------------------------------
diff --git a/lisp/auth-source-pass.el b/lisp/auth-source-pass.el
index 33786a14a87..64774739f09 100644
--- a/lisp/auth-source-pass.el
+++ b/lisp/auth-source-pass.el
@@ -241,7 +241,8 @@ auth-source-pass-entries
   (let ((store-dir (expand-file-name auth-source-pass-filename)))
     (mapcar
      (lambda (file) (file-name-sans-extension (file-relative-name file store-dir)))
-     (directory-files-recursively store-dir "\\.gpg\\'"))))
+     (with-demoted-errors "auth-source-pass: %S"
+       (directory-files-recursively store-dir "\\.gpg\\'")))))
 
 (defun auth-source-pass--find-match (hosts user port)
   "Return password-store entry data matching HOSTS, USER and PORT.
-----------------------------------------------

*Messages*
-----------------------------------------------
auth-source-pass: (file-missing "Opening directory" "No such file or directory" "/Users/naofumi/.password-store")
auth-source-pass: searching for entries matching hostname="host.example.com", user="user", port="443"
auth-source-pass: corresponding suffixes to search for: ("[email-masked]:443" "host.example.com:443/user" "[email-masked]" "host.example.com/user" "host.example.com:443" "host.example.com" "[email-masked]:443" "example.com:443/user" "[email-masked]" "example.com/user" "example.com:443" "example.com" "user@com:443" "com:443/user" "user@com" "com/user" "com:443" "com")
auth-source-pass: (file-missing "Opening directory" "No such file or directory" "/Users/naofumi/.password-store")
auth-source-pass: found no entries matching "[email-masked]:443"
auth-source-pass: (file-missing "Opening directory" "No such file or directory" "/Users/naofumi/.password-store")
auth-source-pass: found no entries matching "host.example.com:443/user"
auth-source-pass: (file-missing "Opening directory" "No such file or directory" "/Users/naofumi/.password-store")
auth-source-pass: found no entries matching "[email-masked]"
auth-source-pass: (file-missing "Opening directory" "No such file or directory" "/Users/naofumi/.password-store")
auth-source-pass: found no entries matching "host.example.com/user"
auth-source-pass: (file-missing "Opening directory" "No such file or directory" "/Users/naofumi/.password-store")
auth-source-pass: found no entries matching "host.example.com:443"
auth-source-pass: (file-missing "Opening directory" "No such file or directory" "/Users/naofumi/.password-store")
auth-source-pass: found no entries matching "host.example.com"
auth-source-pass: (file-missing "Opening directory" "No such file or directory" "/Users/naofumi/.password-store")
auth-source-pass: found no entries matching "[email-masked]:443"
auth-source-pass: (file-missing "Opening directory" "No such file or directory" "/Users/naofumi/.password-store")
auth-source-pass: found no entries matching "example.com:443/user"
auth-source-pass: (file-missing "Opening directory" "No such file or directory" "/Users/naofumi/.password-store")
auth-source-pass: found no entries matching "[email-masked]"
auth-source-pass: (file-missing "Opening directory" "No such file or directory" "/Users/naofumi/.password-store")
auth-source-pass: found no entries matching "example.com/user"
auth-source-pass: (file-missing "Opening directory" "No such file or directory" "/Users/naofumi/.password-store")
auth-source-pass: found no entries matching "example.com:443"
auth-source-pass: (file-missing "Opening directory" "No such file or directory" "/Users/naofumi/.password-store")
auth-source-pass: found no entries matching "example.com"
auth-source-pass: (file-missing "Opening directory" "No such file or directory" "/Users/naofumi/.password-store")
auth-source-pass: found no entries matching "user@com:443"
auth-source-pass: (file-missing "Opening directory" "No such file or directory" "/Users/naofumi/.password-store")
auth-source-pass: found no entries matching "com:443/user"
auth-source-pass: (file-missing "Opening directory" "No such file or directory" "/Users/naofumi/.password-store")
auth-source-pass: found no entries matching "user@com"
auth-source-pass: (file-missing "Opening directory" "No such file or directory" "/Users/naofumi/.password-store")
auth-source-pass: found no entries matching "com/user"
auth-source-pass: (file-missing "Opening directory" "No such file or directory" "/Users/naofumi/.password-store")
auth-source-pass: found no entries matching "com:443"
auth-source-pass: (file-missing "Opening directory" "No such file or directory" "/Users/naofumi/.password-store")
auth-source-pass: found no entries matching "com"
auth-source-search: found 0 results (max 1) matching (:host "host.example.com" :user "user")
-----------------------------------------------

I think it would be better to have just one additional dir check on
auth-source-pass-search instead of auth-source-pass-entries.
auth-source-pass backend just does nothing if password-store dir is not
available.  Could it be relatively reasonable cost?

-----------------------------------------------
diff --git a/lisp/auth-source-pass.el b/lisp/auth-source-pass.el
index 80ddb38fa88..33786a14a87 100644
--- a/lisp/auth-source-pass.el
+++ b/lisp/auth-source-pass.el
@@ -85,6 +85,9 @@ auth-source-pass-search
         ((null host)
          ;; Do not build a result, as none will match when HOST is nil
          nil)
+        ((not (file-directory-p (expand-file-name auth-source-pass-filename)))
+         ;; Do nothing if the password-store folder doesn't exist.
+         nil)
         (auth-source-pass-extra-query-keywords
          (auth-source-pass--build-result-many host port user require max))
         (t
-----------------------------------------------

*Messages*
-----------------------------------------------
auth-source-search: found 0 results (max 1) matching (:host "host.example.com" :user "user")
-----------------------------------------------

New patch file is also attached.

Best regards,
  Naofumi

>From c42a3abeb04b7c28f8532497fe9c9f0e50521a27 Mon Sep 17 00:00:00 2001
From: Naofumi Yasufuku <[email-masked]>
Date: Sun, 16 Feb 2025 21:12:17 +0900
Subject: [PATCH] auth-source-pass: Don't raise errors if ~/.password-store
 doesn't exist

* lisp/auth-source-pass.el (auth-source-pass-search):
If auth-source-pass-filename is not a directory, just do nothing to
avoid repeated errors raised by directory-files-recursively in
auth-source-pass-entries which is called for each search pattern.
(Bug#76323)
---
 lisp/auth-source-pass.el | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/lisp/auth-source-pass.el b/lisp/auth-source-pass.el
index 80ddb38fa88..33786a14a87 100644
--- a/lisp/auth-source-pass.el
+++ b/lisp/auth-source-pass.el
@@ -85,6 +85,9 @@ auth-source-pass-search
         ((null host)
          ;; Do not build a result, as none will match when HOST is nil
          nil)
+        ((not (file-directory-p (expand-file-name auth-source-pass-filename)))
+         ;; Do nothing if the password-store folder doesn't exist.
+         nil)
         (auth-source-pass-extra-query-keywords
          (auth-source-pass--build-result-many host port user require max))
         (t
-- 
2.48.1