Hi,

I recently noticed that directory* follows symlinks on ECL, whereas it would be desirable if it didn't. ECLs directory* function follows symlinks by default, but can be instructed not to.

Please see below for the tweak and a suggested test case, which I based on test-symlink-loop.script.

Thank you,

Moritz Petersen

>From d93a43fdfd5871aef285b76d60781048a42d9949 Mon Sep 17 00:00:00 2001
From: Moritz Petersen <moritz.peter...@freenet.de>
Date: Fri, 9 Oct 2020 19:46:49 +0200
Subject: [PATCH] Ask ECL not to follow symlinks in #'directory

ECLs implementation of directory defaults to resolving symlinks, but can be
instructed to do otherwise by passing a keyword argument.

Tweak directory* function and add general test case based on
test-symlink-loop.script
---
 ...est-directory-no-symlink-resolution.script | 28 +++++++++++++++++++
 uiop/filesystem.lisp                          |  1 +
 2 files changed, 29 insertions(+)
 create mode 100644 test/test-directory-no-symlink-resolution.script

diff --git a/test/test-directory-no-symlink-resolution.script b/test/test-directory-no-symlink-resolution.script
new file mode 100644
index 000000000000..4661f95413e5
--- /dev/null
+++ b/test/test-directory-no-symlink-resolution.script
@@ -0,0 +1,28 @@
+;;; -*- Lisp -*-
+
+;;; Make sure that directory* (and, by extension, directory-files)
+;;; doesn't follow symlinks
+
+(in-package :asdf-test)
+
+;; since symlinks only somewhat exist on Windows, we don't test there.
+(when (uiop:os-windows-p)
+  (exit-lisp 0))
+
+(let ((scratch-dir (namestring (make-sub-pathname :directory '(:relative "symlink-scratch")
+                                                  :defaults *test-directory*))))
+  (unwind-protect
+       (progn
+         ;; create target file and symlink
+         (uiop:run-program (format nil "mkdir ~a" scratch-dir))
+         (uiop:run-program (format nil "mkdir ~a/subdir" scratch-dir))
+         (uiop:run-program (format nil "touch ~a/subdir/target" scratch-dir))
+         (uiop:run-program (format nil "ln -s ~a/subdir/target ~a/link"
+                                   scratch-dir scratch-dir))
+         (DBG "Ensuring directory-files doesn't folllow symlinks.")
+         (assert-equal (merge-pathnames (make-pathname :name "link")
+                                        scratch-dir)
+                       (car (uiop:directory-files scratch-dir))))
+    ;; clean up
+    (DBG "Cleaning up")
+    (uiop:delete-directory-tree scratch-dir :validate (lambda (x) (subpathp x *test-directory*)))))
diff --git a/uiop/filesystem.lisp b/uiop/filesystem.lisp
index b0c184538963..bd1c4e768200 100644
--- a/uiop/filesystem.lisp
+++ b/uiop/filesystem.lisp
@@ -172,6 +172,7 @@ Try to override the defaults to not resolving symlinks, if implementation allows
                                #+(or clozure digitool) '(:follow-links nil)
                                #+clisp '(:circle t :if-does-not-exist :ignore)
                                #+(or cmucl scl) '(:follow-links nil :truenamep nil)
+                               #+ecl '(:resolve-symlinks nil)
                                #+lispworks '(:link-transparency nil)
                                #+sbcl (when (find-symbol* :resolve-symlinks '#:sb-impl nil)
                                         '(:resolve-symlinks nil))))))
-- 
2.28.0

Reply via email to