safely.lisp: More on the CLisp RENAME-FILE mess.
authorMark Wooding <mdw@distorted.org.uk>
Sun, 17 Jul 2011 20:51:16 +0000 (21:51 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sun, 17 Jul 2011 20:51:16 +0000 (21:51 +0100)
The :IF-EXISTS option is only in very new versions of CLisp.  It turns
out that the bizarre double-pathname-merging bug in POSIX:COPY-FILE
doesn't cause trouble if the source is absolute (unsurprising, in
retrospect) so I could use TRUENAME to dig my way out of this mess; but
COPY-FILE will clobber the target file before looking to see whether the
source succeeds (unless persuaded otherwise with :IF-EXISTS, which only
works if RENAME-FILE understands that option).

Give up, and use rename(2) through the FFI.

safely.lisp

index 9b4ab45..0674429 100644 (file)
          (safely-trail safe))
     stream))
 
+#+clisp
+(progn
+  (ffi:def-call-out %rename (:name "rename")
+    (:language :stdc)
+    (:arguments (from ffi:c-string)
+               (to ffi:c-string))
+    (:return-type ffi:int)))
+
 (declaim (inline rename))
 (defun rename (old new)
+  #-clisp
   (let ((target (make-pathname :directory '(:relative)
                               :defaults new)))
-    #-clisp (rename-file old target)
-    #+clisp (rename-file old target :if-exists :overwrite)))
+    (rename-file old target))
+
+  #+clisp
+  (let ((rc (%rename (namestring old) (namestring new))))
+    (when (= rc -1)
+      (error "Failed to rename ~S to ~S: ~A" old new (posix:strerror)))))
 
 (defun delete-file-without-moaning (file)
   "Delete the FILE, ignoring errors."