fix initial FILE-POSITION for OPEN :IF-EXISTS :APPEND
authorWilliam Halliburton <whalliburton@gmail.com>
Sun, 13 Feb 2011 19:01:17 +0000 (12:01 -0700)
committerNikodemus Siivola <nikodemus@sb-studio.net>
Wed, 10 Aug 2011 09:42:10 +0000 (12:42 +0300)
  For O_APPEND opened files, lseek returns 0 until first write.
  So we jump ahead initially.

  lp#561642

NEWS
src/code/fd-stream.lisp
src/code/unix.lisp
tests/stream.impure.lisp

diff --git a/NEWS b/NEWS
index 82484cb..ff52c7d 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -33,6 +33,8 @@ changes relative to sbcl-1.0.50:
     type information associated with the VALUES form.
   * bug fix: broken warnings/errors for type-errors involving LOAD-TIME-VALUE
     forms. (lp#823014)
+  * bug fix: OPEN :IF-EXISTS :APPEND now returns correct FILE-POSITION before
+    first write (lp#561642).
 
 changes in sbcl-1.0.50 relative to sbcl-1.0.49:
   * enhancement: errors from FD handlers now provide a restart to remove
index 7fda172..69505b8 100644 (file)
             (cond ((numberp fd)
                    (case direction
                      ((:input :output :io)
+                      ;; For O_APPEND opened files, lseek returns 0 until first write.
+                      ;; So we jump ahead here.
+                      (when (eq if-exists :append)
+                        (sb!unix:unix-lseek fd 0 sb!unix:l_xtnd))
                       (make-fd-stream fd
                                       :input input
                                       :output output
index 32f7716..64db7ed 100644 (file)
@@ -276,6 +276,7 @@ corresponds to NAME, or NIL if there is none."
   (void-syscall ("access" c-string int) path mode))
 
 ;;; values for the second argument to UNIX-LSEEK
+;;; Note that nowadays these are called SEEK_SET, SEEK_CUR, and SEEK_END
 (defconstant l_set 0) ; to set the file pointer
 (defconstant l_incr 1) ; to increment the file pointer
 (defconstant l_xtnd 2) ; to extend the file size
index 6f2e0f4..fd3f8df 100644 (file)
              (assert (eql (file-length f) 9))))
       (ignore-errors (delete-file name)))))
 
+(with-test (:name :bug-561642)
+  (let ((p "bug-561642-test.tmp"))
+    (unwind-protect
+         (progn
+           (with-open-file (f p
+                              :if-exists :supersede
+                              :if-does-not-exist :create
+                              :direction :output)
+             (write-line "FOOBAR" f))
+           (with-open-file (f p
+                              :if-exists :append
+                              :direction :output)
+             (let ((p0 (file-position f))
+                   (p1 (progn
+                         (write-char #\newline f)
+                         (file-position f)))
+                   (p2 (progn
+                         (write-char #\newline f)
+                         (finish-output f)
+                         (file-position f))))
+               (assert (eql 7 p0))
+               (assert (eql 8 p1))
+               (assert (eql 9 p2)))))
+      (ignore-errors (delete-file p)))))
+
 ;;; success