[Openmcl-devel] Weblocks-Demo Permission Denied Win32
gb at clozure.com
Sun Jan 10 17:15:12 PST 2010
On Sun, 10 Jan 2010, John Federico wrote:
> Thanks for the detailed explanation Gary. That gives me some place to
> look. I must confess some ignorance, getting weblocks to work is my
> excuse to learn lisp (getting asdf and asdf-install to work on Windows
> was the initial challenge).
> Just a thought. If the temp file names are derived from the file's
> write date, is it possible for the write dates to be so close as to
> cause a naming conflict?
It's in fact likely, so the code tries to create the temporary file in
a way that's supposed to fail quietly if the file already exists. On
Unix systems, that involves passing the #$O_EXCL flag to #_open; on
Windows, it involves passing #$CREATE_NEW to #_CreateFileA or #_CreateFileW.
we're supposed to get a "file exists" error when #$CREATE_NEW is set
and the file exists; apparently, that would make too much sense, and
Windows returns some sort of permission error when the file exists
but can't be accessed (because it's in some waiting-to-be-deleted
It wouldn't be a bad idea to use something more unique/random to
come up with a candidate temporary file name, but that just increases
the chance of winning on the first attempt.
Trying to create a file that doesn't already exist is something like
(unless (probe-file path)
but doing the probe and creation as separate operations doesn't guarantee
that the file was newly-created (some other thread or process may have
created the file between the probe and create.) CREATE-FILE with :IF-EXISTS
NIL tries to arrange to do the probe and create atomically, but is apparently
confused by the third state ("existence", "non-existence", and "Windows-specific").
> I tried the MAKE-FILE-STREAM command with
> two different files with the same date modified, and it tried to
> create a .tem file with the same name for both of them. If the
> deletes are scheduled and CCL tries to create a .tem file with the
> same name as one that is scheduled for deletion - but not yet deleted,
> would that create the problem?
? (create-file "home:junk1")
? (defvar *s* (open *))
? (delete-file **)
? (probe-file "home:junk1")
? (create-file * :if-exists nil)
> Error: Permission denied : #P"C:/Users/gb/junk1"
> While executing: %CREATE-FILE, in process listener(1).
> Type :POP to abort, :R for a list of available restarts.
> Type :? for other options.
? (close *s*)
? (probe-file *)
That seems to be what's happening here, and it shows that a file
isn't really deleted (but remains in a sort of limbo) until the last
open stream (Windows file handle) associated with the file is closed.
I can't think of a reason for there to be a lisp stream open on the
temporary files created by :IF-EXISTS :SUPERSEDE.
(The function CCL:OPEN-FILE-STREAMS returns a list of ... open lisp
file streams; it'd be interesting to see whether or not there's a lisp
stream open on a (deleted) temp file when the error occurs.)
> On Sun, Jan 10, 2010 at 5:44 PM, Gary Byers <gb at clozure.com> wrote:
>> The file in question (with a name like "nnnnnnnn.tem") is a sort of backup
>> file created when an existing file is opened with :IF-EXISTS :SUPERSEDE.
>> The original file is renamed as the temporary file and a new file with
>> the original name is created. If the new file is closed normally the backup
>> file is deleted; if the new file is closed with :ABORT T the
>> new file is deleted and the temporary file's renamed to have the original
>> file name.
>> That's more-or-less how things are supposed to work, how they seem to
>> work on Unix-based systems, and how they seem to -usually- work on
>> Windows, but on Windows there's some additional constraint. (If I
>> remembered exactly what that constraint was, there's a fairly good
>> chance that this problem would be gone, but my recollection is that
>> Windows doesn't like to delete or rename files that're open, but
>> instead schedules the file to be renamed/deleted after it's closed.
>> (Again, that may not be entirely accurate, but I think that it's
>> close to being accurate, in some handwavy sense ...)
>> When the file is in this state (on death row ...), it can't be opened
>> again or deleted or renamed, and attempts to perform these operations
>> will fail with a "permission error"; this has nothing to do with the
>> bits or other attributes associated with the file that ordinarily
>> control who can do what.
>> That generally seems to be what you're seeing, but I don't understand
>> the issue well enough to understand what sequence of operations causes
>> this (or how to make CCL's filesystem code avoid that sequence.)
>> The names used for temporary files aren't very well-chosen (the numeric
>> part is just derived from the file's write date, and the fact that
>> file name conflicts are likely seems to trigger the bug in your case.)
>> Code is trying to see if the proposed temporary file name is available
>> by calling CREATE-FILE ... :IF-EXISTS NIL, and rather than getting
>> a "file exists" error and returning NIL, we're getting some sort of
>> permission error that could as easily mean "you don't have the right
>> to create files in this directory." I think that the real problem
>> is that the file has entered the realm of the undead, and we need
>> to better understand how zombies are created.
>> Some tests in the test suite that we use fail on Windows for what seem
>> to be similar reasons; I generally can't reproduce that behavior when
>> the tests are run again, so the failures seem to be sensitive to
>> context in some way. I've also seen it happen very, very occasionally
>> outside of that test suite, but have never isolated the cause (and
>> the things that seem to be involved - opening/closing/renaming/deleting
>> files - happen all the time and seem to behave correctly.
> Openmcl-devel mailing list
> Openmcl-devel at clozure.com
More information about the Openmcl-devel