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?

Drew
  • 75,699
  • 9
  • 109
  • 225
PRouleau
  • 744
  • 3
  • 10
  • 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 Jul 19 '21 at 05: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 Jul 19 '21 at 05:13
  • 1
    @phils I submitted this report: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=49644 – PRouleau Jul 19 '21 at 15:06

1 Answers1

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.

db48x
  • 15,741
  • 1
  • 19
  • 23