From: Jock Cooper
Subject: CLOSE with :abort t
Date: 
Message-ID: <m365wigiyz.fsf@jcooper02.sagepub.com>
Maybe I am not understanding the following from the page for 
CLOSE from the Hyperspec:

"If abort is true, an attempt is made to clean up any side 
effects of having created stream. If stream performs output 
to a file that was created when the stream was created, the 
file is deleted and any previously existing file is not superseded."

To me it sounds like 
a) if the file was created then on close with :abort t it will be deleted
b) if there was a prior existing file which was to be superseded, it 
  would still be intact if the file was closed with :abort t

I wrote the following test code:

(defun test-close-abort ()
  (let ((filename "testfile.txt"))
    (labels ((open-file () (open filename :direction :output :if-does-not-exist :create :if-exists :supersede))
	     (probe ()
	       (let ((pf (probe-file filename)))
		 (format t "probe file returns ~w~%" pf)
		 (when pf
		   (with-open-file (in filename :direction :input)
		     (let ((len (file-length in)))
		       (format t "length is ~a" len)
		       (unless (zerop len)
			 (format t ", contents are: ~a" (read-line in)))
		       (terpri))))))
	     (writefile (string-to-write abortp)
	       (format t "open, write \"~a\", close with abort ~a~%" string-to-write abortp)
	       (close (let ((file (open-file))) (format file "~a~%" string-to-write) file) :abort abortp)
	       (probe)))
      
      (writefile "First Open" t)
      (writefile "Second Open" nil)
      (writefile "Third Open" t))))

If my assumptions are true then neither CMU, CLISP, or ACL handle this correctly. 
Here is the output from each:

CMU 18C
* (test-close-abort)
open, write "First Open", close with abort T
probe file returns NIL
open, write "Second Open", close with abort NIL
probe file returns #p"/home/jockc/testfile.txt"
length is 12, contents are: Second Open

open, write "Third Open", close with abort T
probe file returns NIL        ; <== per (b) above should exist with contents "Second Open"
NIL

CLISP 2000-03-06 (March 2000)
[2]> (test-close-abort)
open, write "First Open", close with abort T
probe file returns #P"/home/jockc/testfile.txt"
length is 11, contents are: First Open         ; <== file should have been deleted

open, write "Second Open", close with abort NIL
probe file returns #P"/home/jockc/testfile.txt"
length is 12, contents are: Second Open

open, write "Third Open", close with abort T
probe file returns #P"/home/jockc/testfile.txt"
length is 11, contents are: Third Open         ; <== should be Second Open

NIL


CLISP seem to just ignore it completely.


ACL 6.1
open, write "First Open", close with abort T
probe file returns #p"C:\\PROGRA~1\\acl61\\testfile.txt"
length is 0                    ; <== sets size to zero but should delete

open, write "Second Open", close with abort NIL
probe file returns #p"C:\\PROGRA~1\\acl61\\testfile.txt"
length is 13, contents are: Second Open

open, write "Third Open", close with abort T
probe file returns #p"C:\\PROGRA~1\\acl61\\testfile.txt" 
length is 0                  


Am I just misinterpereting the wording in CLHS?

Jock

From: Tim Bradshaw
Subject: Re: CLOSE with :abort t
Date: 
Message-ID: <ey3u1k2gfyd.fsf@cley.com>
* Jock Cooper wrote:

> "If abort is true, an attempt is made to clean up any side 

I think the crucial point is that *an attempt* is made.  No promises
are given, and given the nature of Unixoid filesystems, it's quite
hard to do everything you might want.

> CMU 18C
* (test-close-abort)
> open, write "First Open", close with abort T
> probe file returns NIL
> open, write "Second Open", close with abort NIL
> probe file returns #p"/home/jockc/testfile.txt"
> length is 12, contents are: Second Open

> open, write "Third Open", close with abort T
> probe file returns NIL        ; <== per (b) above should exist with contents "Second Open"
> NIL

This is the kind of reasonable-best-attempt that I'd expect a
unix-based implementation to make: if the file was created, then a
CLOSE with ABORT T deletes it, but if it was being superseded then you
lose, because in order to do this right under Unix you'd have to write
to some temporary file and then, on close, delete the existing file
and rename the temporary file.  This in turn raises all sorts of
exciting issues - for instance things can fail *at close time* which
you might well not expect (this is rather similar to the case with
NFS, where things can fail when the file is closed in a way which many
programs do not check...).

Really, the issue is that Unix doesn't have a notion of superseding a
file.  In a versioned filesystem, for instance, superseding a file is
often easy - you just write a new version in the standard way, and if
you want to not do that after all, you delete the new version, leaving
all the old versions intact.

> Am I just misinterpereting the wording in CLHS?

Yes, i think so.

--tim
From: Vassil Nikolov
Subject: Re: CLOSE with :abort t
Date: 
Message-ID: <usmzlz5cb.fsf@poboxes.com>
    On 04 Oct 2002 20:30:02 +0100, Tim Bradshaw <···@cley.com> said:

    [...]
    TB> This is the kind of reasonable-best-attempt that I'd expect a
    TB> unix-based implementation to make: if the file was created, then a
    TB> CLOSE with ABORT T deletes it, but if it was being superseded then you
    TB> lose, because in order to do this right under Unix you'd have to write
    TB> to some temporary file and then, on close, delete the existing file
    TB> and rename the temporary file.  This in turn raises all sorts of
    TB> exciting issues - for instance things can fail *at close time* which
    TB> you might well not expect

I think it deserves to be noted that there are quite a few exciting
issues to be dealt with even if we ignore, for the sake of
argument, dealing with failures (of course, it may be true that
nothing excites like a failure):

* `unlink and rename' requires write access to the directory;

* `unlink and rename' is in general incompatible with preserving
  the ownership and permissions of the original file;

* `unlink and rename' is incompatible with preserving hard links
  (of course, it is possible to write to a temporary file first,
  and on (normal) closing copy its contents into the original
  file...).

On the other hand, without write access to the file, but with write
access to the directory, `unlink and rename' would be the only way
to rewrite the original file.  Is doing that OK?  Is it OK if it
happens silently, as a side effect of choosing `unlink and rename'?

One good think about the Common Lisp semantics of OPEN and CLOSE is
that, even though written with the experience from other file
systems in mind, and allowing the implementation to take full
advantage of what they offer, it does not impose undue constraints
that would render a Unix implementation damaged.

---Vassil.
From: Vassil Nikolov
Subject: Re: CLOSE with :abort t
Date: 
Message-ID: <uofa9z51x.fsf@poboxes.com>
    On 04 Oct 2002 20:30:02 +0100, Tim Bradshaw <···@cley.com> said:

    [...]
    TB> This is the kind of reasonable-best-attempt that I'd expect a
    TB> unix-based implementation to make: if the file was created, then a
    TB> CLOSE with ABORT T deletes it, but if it was being superseded then you
    TB> lose, because in order to do this right under Unix you'd have to write
    TB> to some temporary file and then, on close, delete the existing file
    TB> and rename the temporary file.  This in turn raises all sorts of
    TB> exciting issues - for instance things can fail *at close time* which
    TB> you might well not expect

I think it deserves to be noted that there are quite a few exciting
issues to be dealt with even if we ignore, for the sake of
argument, dealing with failures (of course, it may be true that
nothing excites like a failure):

* `unlink and rename' requires write access to the directory;

* `unlink and rename' is in general incompatible with preserving
  the ownership and permissions of the original file;

* `unlink and rename' is incompatible with preserving hard links
  (of course, it is possible to write to a temporary file first,
  and on (normal) closing copy its contents into the original
  file...).

On the other hand, without write access to the file, but with write
access to the directory, `unlink and rename' would be the only way
to rewrite the original file.  Is doing that OK?  Is it OK if it
happens silently, as a side effect of choosing `unlink and rename'?

One good think about the Common Lisp semantics of OPEN and CLOSE is
that, even though written with the experience from other file
systems in mind, and allowing the implementation to take full
advantage of what they offer, it does not impose undue constraints
that would render a Unix implementation damaged.

---Vassil.
From: Vassil Nikolov
Subject: Re: CLOSE with :abort t
Date: 
Message-ID: <uk7kxz4xy.fsf@poboxes.com>
    On 04 Oct 2002 20:30:02 +0100, Tim Bradshaw <···@cley.com> said:

    [...]
    TB> This is the kind of reasonable-best-attempt that I'd expect a
    TB> unix-based implementation to make: if the file was created, then a
    TB> CLOSE with ABORT T deletes it, but if it was being superseded then you
    TB> lose, because in order to do this right under Unix you'd have to write
    TB> to some temporary file and then, on close, delete the existing file
    TB> and rename the temporary file.  This in turn raises all sorts of
    TB> exciting issues - for instance things can fail *at close time* which
    TB> you might well not expect

I think it deserves to be noted that there are quite a few exciting
issues to be dealt with even if we ignore, for the sake of
argument, dealing with failures (of course, it may be true that
nothing excites like a failure):

* `unlink and rename' requires write access to the directory;

* `unlink and rename' is in general incompatible with preserving
  the ownership and permissions of the original file;

* `unlink and rename' is incompatible with preserving hard links
  (of course, it is possible to write to a temporary file first,
  and on (normal) closing copy its contents into the original
  file...).

On the other hand, without write access to the file, but with write
access to the directory, `unlink and rename' would be the only way
to rewrite the original file.  Is doing that OK?  Is it OK if it
happens silently, as a side effect of choosing `unlink and rename'?

One good think about the Common Lisp semantics of OPEN and CLOSE is
that, even though written with the experience from other file
systems in mind, and allowing the implementation to take full
advantage of what they offer, it does not impose undue constraints
that would render a Unix implementation damaged.

---Vassil.