@subsubheading File Locking

@noindent
Unix file-locking is focussed on write permissions for segments of a
existing file.  While this might be employed for (binary) database
access, it is not used for everyday contention (between users) for
text files.

@noindent
Microsoft has several file-locking protocols.  Their model denies
write access to a file if any reader has it open.  This is too
restrictive.  Write access is denied even when the reader has
reached end-of-file.  And tracking read access (which is much more
common than write access) causes havoc when remote hosts crash or
disconnect.

@noindent
It is bizarre that the concept of multi-user contention for
modifying files has not been adequately addressed by either of the
large operating system development efforts.  There is further irony
that both camps support contention detection and resolution only
through weak conventions of some their document editing programs.

@noindent
@cindex file-lock
The @dfn{file-lock} procedures implement a transaction method for file
@cindex file-lock
replacement compatible with the methods used by the GNU @dfn{emacs}
@cindex emacs
text editor on Unix systems and the Microsoft @dfn{Word} editor.
@cindex Word
@cindex emacs

@noindent
@cindex certificate
Both protocols employ what I term a @dfn{certificate} containing the
@cindex certificate
user, hostname, time, and (on Unix) process-id.
Intent to replace @var{file} is indicated by adding to @var{file}'s
directory a certificate object whose name is derived from
@var{file}.

@noindent
The Microsoft Word certificate is contained in a 162 byte file named
for the visited @var{file} with a @samp{~$} prefix.
Emacs/Unix creates a symbolic link to a certificate named for the
visited @var{file} prefixed with @samp{.#}.
Because Unix systems can import Microsoft file systems, these
routines maintain and check both Emacs and Word certificates.


@defun file-lock-owner path

Returns the string @samp{@var{user}@@@var{hostname}} associated with
the lock owner of file @var{path} if locked; and #f otherwise.
@end defun


@deffn {Procedure} file-lock! path email


@deffnx {Procedure} file-lock! path

@var{path} must be a string naming the file to be locked.  If supplied, @var{email}
must be a string formatted as @samp{@var{user}@@@var{hostname}}.  If
absent, @var{email} defaults to the value returned by @code{user-email-address}.

If @var{path} is already locked, then @code{file-lock!} returns @samp{#f}.  If @var{path} is
unlocked, then @code{file-lock!} returns the certificate string associated with the
new lock for file @var{path}.
@end deffn


@deffn {Procedure} file-unlock! path certificate

@var{path} must be a string naming the file to be unlocked.  @var{certificate} must be the
string returned by @code{file-lock!} for @var{path}.

If @var{path} is locked with @var{certificate}, then @code{file-unlock!} removes the locks and returns
@samp{#t}.  Otherwise, @code{file-unlock!} leaves the file system unaltered and returns
@samp{#f}.
@end deffn


@defun describe-file-lock path prefix


@defunx describe-file-lock path
@var{path} must be a string naming a file.  Optional argument @var{prefix} is a string
printed before each line of the message.  @code{describe-file-lock} prints to
@code{(current-error-port)} that @var{path} is locked for writing and lists
its lock-files.

@example
(describe-file-lock "my.txt" ">> ")
@print{}
>> "my.txt" is locked for writing by 'luser@@no.com.4829:1200536423'
>> (lock files are "~$my.txt" and ".#my.txt")
@end example
@end defun

@subsubheading File Transactions


@defun emacs:backup-name path backup-style

@var{path} must be a string.  @var{backup-style} must be a symbol.  Depending on @var{backup-style}, @code{emacs:backup-name}
returns:
@table @r
@item none
#f
@item simple
the string "@var{path}~"
@item numbered
the string "@var{path}.~@var{n}~", where @var{n} is one greater than the
highest number appearing in a filename matching "@var{path}.~*~".  @var{n}
defauls to 1 when no filename matches.
@item existing
the string "@var{path}.~@var{n}~" if a numbered backup already exists in
this directory; otherwise. "@var{path}~"
@item orig
the string "@var{path}.orig"
@item bak
the string "@var{path}.bak"
@end table
@end defun


@defun transact-file-replacement proc path backup-style certificate


@defunx transact-file-replacement proc path backup-style

@defunx transact-file-replacement proc path

@var{path} must be a string naming an existing file.  @var{backup-style} is one of the
symbols @r{none}, @r{simple}, @r{numbered}, @r{existing}, @r{orig},
@r{bak} or @r{#f}; with meanings described above; or a string naming
the location of a backup file.  @var{backup-style} defaults to @r{#f}.  If supplied,
@var{certificate} is the certificate with which @var{path} is locked.

@var{proc} must be a procedure taking two string arguments:
@itemize @bullet
@item
@var{path}, the original filename (to be read); and
@item
a temporary file-name.
@end itemize

If @var{path} is locked by other than @var{certificate}, or if @var{certificate} is supplied and @var{path} is not
locked, then @code{transact-file-replacement} returns #f.  If @var{certificate} is not supplied, then, @code{transact-file-replacement} creates
temporary (Emacs and Word) locks for @var{path} during the transaction.  The
lock status of @var{path} will be restored before @code{transact-file-replacement} returns.

@code{transact-file-replacement} calls @var{proc} with @var{path} (which should not be modified) and a temporary
file path to be written.
If @var{proc} returns any value other than @r{#t}, then the file named by @var{path}
is not altered and @code{transact-file-replacement} returns @r{#f}.
Otherwise, @code{emacs:backup-name} is called with @var{path} and @var{backup-style}.  If it
returns a string, then @var{path} is renamed to it.

Finally, the temporary file is renamed @var{path}.
@code{transact-file-replacement} returns #t if @var{path} was successfully replaced; and #f otherwise.
@end defun

@subsubheading Identification


@defun user-email-address

@code{user-email-address} returns a string of the form @samp{username@r{@@}hostname}.  If
this e-mail address cannot be obtained, #f is returned.
@end defun

