~ chicken-core (chicken-5) 00ed675fef88ed931c16859947ea5a79f62b1bf5


commit 00ed675fef88ed931c16859947ea5a79f62b1bf5
Author:     Moritz Heidkamp <moritz@twoticketsplease.de>
AuthorDate: Sat May 25 17:08:09 2013 +0200
Commit:     Peter Bex <peter.bex@xs4all.nl>
CommitDate: Tue May 28 22:17:04 2013 +0200

    Improve read-symbolic-link canonicalization
    
    Passing #t for the CANONICALIZE option of read-symbolic-link now behaves
    like the --canonicalize option of readlink(1), i.e. it recursively
    follows every symlink in every component of the given path. When called
    like this, read-symbolic-link like readlink(1) now verifies that all
    components exist.
    
    Signed-off-by: Peter Bex <peter.bex@xs4all.nl>

diff --git a/posixunix.scm b/posixunix.scm
index a2776da3..27424fca 100644
--- a/posixunix.scm
+++ b/posixunix.scm
@@ -1241,21 +1241,36 @@ EOF
 
 (define-foreign-variable _filename_max int "FILENAME_MAX")
 
-(define read-symbolic-link
+(define ##sys#read-symbolic-link
   (let ((buf (make-string (fx+ _filename_max 1))))
-    (lambda (fname #!optional canonicalize)
-      (##sys#check-string fname 'read-symbolic-link)
-      (let ((len (##core#inline 
-		  "C_do_readlink"
-		  (##sys#make-c-string (##sys#expand-home-path fname) 'read-symbolic-link) buf)))
-	(if (fx< len 0)
-	    (if canonicalize
-		fname
-		(posix-error #:file-error 'read-symbolic-link "cannot read symbolic link" fname))
-	    (let ((pathname (substring buf 0 len)))
-	      (if (and canonicalize (symbolic-link? pathname))
-		  (read-symbolic-link pathname 'canonicalize)
-		  pathname ) ) ) ) ) ) )
+    (lambda (fname location)
+      (let ((len (##core#inline
+                  "C_do_readlink"
+                  (##sys#make-c-string fname location) buf)))
+        (if (fx< len 0)
+            (posix-error #:file-error location "cannot read symbolic link" fname)
+            (substring buf 0 len))))))
+
+(define (read-symbolic-link fname #!optional canonicalize)
+  (##sys#check-string fname 'read-symbolic-link)
+  (let ((fname (##sys#expand-home-path fname)))
+    (if canonicalize
+        (receive (base-origin base-directory directory-components) (decompose-directory fname)
+          (let loop ((components directory-components)
+                     (result (string-append (or base-origin "") (or base-directory ""))))
+            (if (null? components)
+                result
+                (let ((pathname (make-pathname result (car components))))
+                  (if (file-exists? pathname)
+                      (loop (cdr components)
+                            (if (symbolic-link? pathname)
+                                (let ((target (##sys#read-symbolic-link pathname 'read-symbolic-link)))
+                                  (if (absolute-pathname? target)
+                                      target
+                                      (make-pathname result target)))
+                                pathname))
+                      (##sys#signal-hook #:file-error 'read-symbolic-link "could not canonicalize path with symbolic links, component does not exist" pathname))))))
+        (##sys#read-symbolic-link fname 'read-symbolic-link))))
 
 (define file-link
   (let ([link (foreign-lambda int "link" c-string c-string)])
Trap