[Ecls-list] open :supersede and rename-file advise
Geo Carncross
geocar at gmail.com
Mon Nov 26 16:54:18 UTC 2007
On Nov 26, 2007 11:17 AM, Mark Hoemmen <mark.hoemmen at gmail.com> wrote:
> On 11/26/07, Geo Carncross <geocar at gmail.com> wrote:
> > Under unix, robust applications tend to write to new files in the following way:
> >
> > fd = open(tempfile, O_EXCL|O_CREAT, 0600);
> > ... write to fd ...
> > if (fsync(fd) == -1) goto fail;
> > if (close(fd) == -1) goto fail; /* NFS can fail here */
> > if (rename(tempfile, realfile) == -1) goto fail;
> >
> > This has the benefit of having no points where "realfile" has
> > incomplete or invalid data.
>
> It's important here, I think, to put TEMPFILE in the same directory as
> REALFILE, rather than using TMPDIR. You could have problems if TMPDIR
> defaults to /tmp or something like it, and the desired file to create
> is large. /tmp or /var/tmp are typically on small partitions, so
> users may think they have enough space to create a file (say in their
> home directory), but find that the file write fails unexpectedly.
It's important to put tempfile in the same directory because otherwise
it doesn't work. rename() (or MoveFileEx) is only atomic when it's
changing the *name* of a file, and cannot move a file from one
filesystem to another (i.e. across mount points where stat.st_dev
changes). Additionally, (at least on unix) you cannot have permission
to rename a file into a directory, but simultaneously not have
permission to create a file in the same directory.
Actually, that last part may not be true. In a world of selinux and
posix-acls, and I don't know exactly how Windows deals with this, it
might be possible to have RENAME have different permissions than
open(O_TRUNC), but I doubt a good workaround could be coded into
CL:OPEN anyway, so any efforts would simply make it less predictable.
Maybe having a non-standard :temporary-pathname key (which defaulted
to the pathname, with :name and/or :type chosen randomly) would be the
right thing to do.
The temporary file, however, shouldn't "look" like a regular file-
give it a name like (format nil "temp,~a.~a.tmp" (get-universal-time)
(incf *some-process-counter*)) so that a cleaner can be written easily
(if anyone ever wants to).
More information about the ecl-devel
mailing list