0

I need to copy a directory tree that holds Unix socket files somewhere inside. As Unix sockets cannot be copied, when I use copy-directory, the copy-file function used by copy-directory throws an error because it cannot copy the Unix socket file.

In an attempt to resolve that problem I wrote a advice for copy-file, called copy-only-file that copies only files, and skip Unix sockets:

(defun copy-only-file (file newname
                            &optional
                            ok-if-already-exists
                            keep-time
                            preserve-uid-gid
                            preserve-permissions)
  "Copy files but not Unix sockets."
  (unless (unix-socket-p file)
    (copy-file file newname ok-if-already-exists keep-time
                        preserve-uid-gid preserve-permissions)))

Then later, inside another function, the code sets up the advice temporarily to copy the directory tree:

          ;; inside some function...
          (advice-add 'copy-file :override #'copy-only-file)
          (copy-directory (directory-file-name source-dirpath)
                          (directory-file-name destination-dirpath))
          (advice-remove 'copy-file #'copy-only-file)

This being a recursive call, running the code causes too many recursions and the code eventually fails with the error (error Lisp nesting exceeds ‘max-lisp-eval-depth’)

I thought of using a :before advice to filter out files that would be Unix socket files, but then is it possible to not call the function being advised when some criteria is met? Or would I have to pass the same file to the FILE and NEWFILE argument of copy-file so that no copy is done because OK-IF-ALREADY-EXISTS would be nil?

I have also thought about re-defining the function using defalias to keep access to the original copy-file:


(defalias 'original-copy-file #'copy-file)

(defun copy-file (file newname
                       &optional
                       ok-if-already-exists
                       keep-time
                       preserve-uid-gid
                       preserve-permissions)
  "Copy files but not Unix sockets."
  (unless (socket-p file)
    (original-copy-file file newname ok-if-already-exists keep-time preserve-uid-gid preserve-permissions)))

That seems to work, but is it guaranteed to always work? It feels like a kludge to me. And I'm not clear on how I would restore the original copy-file.

What is the proper way to handle this type of scenario?

3
  • You can add and remove :override advice to clobber a function definition and subsequently restore it. There are other options, but that's the nicest method IMO, as it's both easy and visible.
    – phils
    Commented Jul 19, 2021 at 5:00
  • I would M-x report-emacs-bug if I were you. It seems reasonable to provide users with a way to handle the presence of sockets and/or other similar things.
    – phils
    Commented Jul 19, 2021 at 5:13
  • 1
    @phils I submitted this report: debbugs.gnu.org/cgi/bugreport.cgi?bug=49644
    – PRouleau
    Commented Jul 19, 2021 at 15:06

1 Answer 1

1

:override replaces the advised function with your own function, so when your function tries to call the original it is actually calling itself. I recommend using :around advice instead.

(defun copy-only-file (original-copy-file file &rest args)
  "Copy files but not Unix sockets."
  (unless (unix-socket-p file)
    (apply original-copy-file
           file
           args)))

Then to add the advice run (advice-add 'copy-file :around #'copy-only-file)

See chapter 13.11.3 Ways to compose advice in the Elisp manual for all the different ways to compose advice.

1
  • 1
    Thanks! You are correct on both accounts! I should have read the manual a little bit more :-)
    – PRouleau
    Commented Jul 19, 2021 at 12:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.