Commit b5029e23 authored by Paul Eggert's avatar Paul Eggert
Browse files

The lock for FILE is now .#FILE or .#-FILE.

The old approach, which fell back on DIR/.#FILE.0 through
DIR/.#FILE.9, had race conditions that could not be easily fixed.
If DIR/.#FILE is a non-symlink file, Emacs now does not create a
lock file for DIR/FILE; that is, DIR/FILE is no longer partly
protected by a lock if DIR/.#FILE is a non-symlink file ("partly"
because the locking mechanism was never reliable in that case).
This patch fixes this and other bugs discovered by a code
inspection that was prompted by
<http://lists.gnu.org/archive/html/emacs-devel/2013-02/msg00531.html>.
Also, this patch switches to .#-FILE (not .#FILE) on MS-Windows,
to avoid interoperability problems between the MS-Windows and
non-MS-Windows implementations.  MS-Windows and non-MS-Windows
instances of Emacs now ignore each others' locks.
* etc/NEWS: Document this.
* src/filelock.c (defined_WINDOWSNT): New constant.
(MAKE_LOCK_NAME, fill_in_lock_file_name):
Don't create DIR/.#FILE.0 through DIR/.#FILE.9.  Instead, create
DIR/.#FILE symlinks on non-MS-Windows hosts, and DIR/.#-FILE
regular files on MS-Windows hosts.
(MAKE_LOCK_NAME, unlock_file, Ffile_locked_p):
Use SAFE_ALLOCA to avoid problems with long file names.
(MAX_LFINFO): Now a local constant, not a global macro.
(IS_LOCK_FILE): Remove.
(lock_file_1): Don't inspect errno if symlink call succeeds;
that's not portable.
(lock_file): Document that this function can return if lock
creation fails.

Fixes: debbugs:13807
parent 06b583de
2013-03-02 Paul Eggert <eggert@cs.ucla.edu>
* NEWS: The lock for FILE is now .#FILE or .#-FILE (Bug#13807).
2013-03-01 Michael Albinus <michael.albinus@gmx.de>
* NEWS: Fix Tramp "adb" entry. Extend list of discontinued Tramp
......
......@@ -320,6 +320,18 @@ text-property on the first char.
** The `defalias-fset-function' property lets you catch calls to defalias
and redirect them to your own function instead of `fset'.
** The lock for 'DIR/FILE' is now 'DIR/.#FILE' or 'DIR/.#-FILE'.
When you edit DIR/FILE, Emacs normally creates a symbolic link
DIR/.#FILE as a lock that warns other instances of Emacs that DIR/FILE
is being edited. Formerly, if there was already a non-symlink file
named DIR/.#FILE, Emacs fell back on the lock names DIR/.#FILE.0
through DIR/.#FILE.9. These fallbacks have been removed, so that
Emacs now no longer locks DIR/FILE in that case.
On MS-Windows the lock is a regular file DIR/.#-FILE, not a symlink.
MS-Windows and non-MS-Windows implementations of Emacs ignore each
other's locks.
** The 9th element returned by `file-attributes' is now unspecified.
Formerly, it was t if the file's gid would change if file were deleted
and recreated. This value has been inaccurate for years on many
......
2013-03-02 Paul Eggert <eggert@cs.ucla.edu>
The lock for FILE is now .#FILE or .#-FILE (Bug#13807).
The old approach, which fell back on DIR/.#FILE.0 through
DIR/.#FILE.9, had race conditions that could not be easily fixed.
If DIR/.#FILE is a non-symlink file, Emacs now does not create a
lock file for DIR/FILE; that is, DIR/FILE is no longer partly
protected by a lock if DIR/.#FILE is a non-symlink file ("partly"
because the locking mechanism was never reliable in that case).
This patch fixes this and other bugs discovered by a code
inspection that was prompted by
<http://lists.gnu.org/archive/html/emacs-devel/2013-02/msg00531.html>.
Also, this patch switches to .#-FILE (not .#FILE) on MS-Windows,
to avoid interoperability problems between the MS-Windows and
non-MS-Windows implementations. MS-Windows and non-MS-Windows
instances of Emacs now ignore each others' locks.
* filelock.c (defined_WINDOWSNT): New constant.
(MAKE_LOCK_NAME, fill_in_lock_file_name):
Don't create DIR/.#FILE.0 through DIR/.#FILE.9. Instead, create
DIR/.#FILE symlinks on non-MS-Windows hosts, and DIR/.#-FILE
regular files on MS-Windows hosts.
(MAKE_LOCK_NAME, unlock_file, Ffile_locked_p):
Use SAFE_ALLOCA to avoid problems with long file names.
(MAX_LFINFO): Now a local constant, not a global macro.
(IS_LOCK_FILE): Remove.
(lock_file_1): Don't inspect errno if symlink call succeeds;
that's not portable.
(lock_file): Document that this function can return if lock
creation fails.
2013-03-02 Andreas Schwab <schwab@linux-m68k.org>
* lisp.h (XPNTR) [!USE_LSB_TAG]: Remove extra paren. (Bug#13734)
......
......@@ -64,7 +64,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#define WTMP_FILE "/var/log/wtmp"
#endif
/* The strategy: to lock a file FN, create a symlink .#FN in FN's
/* On non-MS-Windows systems, use a symbolic link to represent a lock.
The strategy: to lock a file FN, create a symlink .#FN in FN's
directory, with link data `user@host.pid'. This avoids a single
mount (== failure) point for lock files.
......@@ -97,7 +98,12 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
has contributed this implementation for Emacs), and was designed by
Ethan Jacobson, Kimbo Mundy, and others.
--karl@cs.umb.edu/karl@hq.ileaf.com. */
--karl@cs.umb.edu/karl@hq.ileaf.com.
On MS-Windows, symbolic links do not work well, so instead of a
symlink .#FN -> 'user@host.pid', the lock is a regular file .#-FN
with contents 'user@host.pid'. MS-Windows and non-MS-Windows
versions of Emacs ignore each other's locks. */
/* Return the time of the last system boot. */
......@@ -291,55 +297,31 @@ typedef struct
/* Free the two dynamically-allocated pieces in PTR. */
#define FREE_LOCK_INFO(i) do { xfree ((i).user); xfree ((i).host); } while (0)
/* Write the name of the lock file for FNAME into LOCKNAME. Length
will be that of FN plus two more for the leading `.#' plus 1 for
the trailing period plus one for the digit after it plus one for
the null. */
#define MAKE_LOCK_NAME(LOCKNAME, FNAME) \
(LOCKNAME = alloca (SBYTES (FNAME) + 2 + 1 + 1 + 1), \
fill_in_lock_file_name (LOCKNAME, (FNAME)))
#ifdef WINDOWSNT
/* 256 chars for user, 1024 chars for host, 10 digits for each of 2 int's. */
#define MAX_LFINFO (256 + 1024 + 10 + 10 + 2)
/* min size: .@PID */
#define IS_LOCK_FILE(ST) (MAX_LFINFO >= (ST).st_size && (ST).st_size >= 3)
enum { defined_WINDOWSNT = 1 };
#else
#define IS_LOCK_FILE(ST) S_ISLNK ((ST).st_mode)
enum { defined_WINDOWSNT = 0 };
#endif
/* Write the name of the lock file for FNAME into LOCKNAME. Length
will be that of FNAME plus two more for the leading ".#",
plus one for "-" if MS-Windows, plus one for the null. */
#define MAKE_LOCK_NAME(lockname, fname) \
(lockname = SAFE_ALLOCA (SBYTES (fname) + 2 + defined_WINDOWSNT + 1), \
fill_in_lock_file_name (lockname, fname))
static void
fill_in_lock_file_name (register char *lockfile, register Lisp_Object fn)
fill_in_lock_file_name (char *lockfile, Lisp_Object fn)
{
ptrdiff_t length = SBYTES (fn);
register char *p;
struct stat st;
int count = 0;
strcpy (lockfile, SSDATA (fn));
/* Shift the nondirectory part of the file name (including the null)
right two characters. Here is one of the places where we'd have to
do something to support 14-character-max file names. */
for (p = lockfile + length; p != lockfile && *p != '/'; p--)
p[2] = *p;
/* Insert the `.#'. */
p[1] = '.';
p[2] = '#';
p = lockfile + length + 2;
while (lstat (lockfile, &st) == 0 && !IS_LOCK_FILE (st))
{
if (count > 9)
{
*p = '\0';
return;
}
sprintf (p, ".%d", count++);
}
char *last_slash = memrchr (SSDATA (fn), '/', SBYTES (fn));
char *base = last_slash + 1;
ptrdiff_t dirlen = base - SSDATA (fn);
memcpy (lockfile, SSDATA (fn), dirlen);
lockfile[dirlen] = '.';
lockfile[dirlen + 1] = '#';
if (defined_WINDOWSNT)
lockfile[dirlen + 2] = '-';
strcpy (lockfile + dirlen + 2 + defined_WINDOWSNT, base);
}
static int
......@@ -356,8 +338,8 @@ create_lock_file (char *lfname, char *lock_info_str, bool force)
{
/* Deny everybody else any kind of access to the file until we are
done writing it and close the handle. This makes the entire
open/write/close operation atomic, as far as other processes
are concerned. */
open/write/close operation atomic, as far as other WINDOWSNT
processes are concerned. */
int fd = _sopen (lfname,
_O_WRONLY | _O_BINARY | _O_CREAT | _O_EXCL | _O_NOINHERIT,
_SH_DENYRW, S_IREAD | S_IWRITE);
......@@ -380,7 +362,7 @@ create_lock_file (char *lfname, char *lock_info_str, bool force)
}
#else
err = symlink (lock_info_str, lfname);
if (errno == EEXIST && force)
if (err != 0 && errno == EEXIST && force)
{
unlink (lfname);
err = symlink (lock_info_str, lfname);
......@@ -440,6 +422,8 @@ read_lock_data (char *lfname)
#else
int fd = emacs_open (lfname, O_RDONLY | O_BINARY, S_IREAD);
ssize_t nbytes;
/* 256 chars for user, 1024 chars for host, 10 digits for each of 2 int's. */
enum { MAX_LFINFO = 256 + 1024 + 10 + 10 + 2 };
char lfinfo[MAX_LFINFO + 1];
if (fd < 0)
......@@ -601,6 +585,7 @@ lock_if_free (lock_info_type *clasher, register char *lfname)
decided to go ahead without locking.
When this returns, either the lock is locked for us,
or lock creation failed,
or the user has said to go ahead without locking.
If the file is locked by someone else, this calls
......@@ -686,9 +671,10 @@ lock_file (Lisp_Object fn)
}
void
unlock_file (register Lisp_Object fn)
unlock_file (Lisp_Object fn)
{
register char *lfname;
char *lfname;
USE_SAFE_ALLOCA;
fn = Fexpand_file_name (fn, Qnil);
fn = ENCODE_FILE (fn);
......@@ -697,6 +683,8 @@ unlock_file (register Lisp_Object fn)
if (current_lock_owner (0, lfname) == 2)
unlink (lfname);
SAFE_FREE ();
}
void
......@@ -762,9 +750,10 @@ t if it is locked by you, else a string saying which user has locked it. */)
(Lisp_Object filename)
{
Lisp_Object ret;
register char *lfname;
char *lfname;
int owner;
lock_info_type locker;
USE_SAFE_ALLOCA;
filename = Fexpand_file_name (filename, Qnil);
......@@ -781,6 +770,7 @@ t if it is locked by you, else a string saying which user has locked it. */)
if (owner > 0)
FREE_LOCK_INFO (locker);
SAFE_FREE ();
return ret;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment