FILE's lock is now always .#FILE and may be a regular file.

* etc/NEWS: Document this.
* nt/inc/unistd.h (O_NOFOLLOW): New macro.
* src/filelock.c: Include <c-ctype.h>.
(MAX_LFINFO): New top-level constant.
(lock_info_type): Remove members pid, boot_time.  Add members at,
dot, colon.  Change user member to be the entire buffer, not a
pointer.  This allows us to handle the case where a foreign
pid or boot time exceeds the local range.  All uses changed.
(LINKS_MIGHT_NOT_WORK): New constant.
(FREE_LOCK_INFO): Remove, as the pieces no longer need freeing.
(defined_WINDOWSNT): Remove.
(MAKE_LOCK_NAME, file_in_lock_file_name):
Always use .#FILE (not .#-FILE) for the file lock,
even if it is a regular file.
(rename_lock_file): New function.
(create_lock_file): Use it.
(create_lock_file, read_lock_data):
Prefer a symbolic link for the lock file, falling back on a
regular file if symlinks don't work.  Do not try to create
symlinks on MS-Windows, due to security hassles.  Stick with
POSIXish functions (open, read, write, close, fchmod, readlink, symlink,
link, rename, unlink, mkstemp) when creating locks, as a GNUish
host may be using a Windowsish file system, and cannot use
MS-Windows-only system calls.  Fall back on mktemp if mkstemp
doesn't work.  Don't fail merely because of a symlink-contents
length limit in the current file system; fall back on regular
files.  Increase the symlink contents length limit to 8 KiB, this
should be big enough for any real use and doesn't crunch the
stack.
(create_lock_file, lock_file_1, read_lock_data):
Simplify allocation of lock file buffers now that they fit in 8 KiB.
(lock_file_1): Return error number, not bool.  All callers changed.
(ELOOP): New macro, if not already defined.
(read_lock_data): Return size of lock file contents, not Lisp object.
All callers changed.  Handle a race condition if some other process
replaces a regular-file lock with a symlink lock or vice versa,
while we're trying to read the lock.
(current_lock_owner): Parse contents more carefully, to help avoid
confusing a regular-file lock with some other application's use
of the file.  Check for lock file contents being too long, or
not parsing correctly.
(current_lock_owner, lock_file):
Allow foreign pid and boot times that exceed the local range.
(current_lock_owner, lock_if_free, lock_file):
Simplify allocation of lock file contents.
* src/w32.c (sys_rename_replace): New function, containing most of
the contents of the old sys_rename.
(sys_rename): Use it.
(fchmod): New dummy function.
* src/w32.h (sys_rename_replace, fchmod): New decls.

Fixes: debbugs:13807
This commit is contained in:
Paul Eggert 2013-03-05 14:35:41 -08:00
parent 05e193f170
commit 707431575a
9 changed files with 342 additions and 200 deletions

View file

@ -594,7 +594,8 @@ else
test "x$NON_GCC_TEST_OPTIONS" != x && CC="$CC $NON_GCC_TEST_OPTIONS"
fi
# Avoid gnulib's tests for O_NOATIME and O_NOFOLLOW, as we don't use them.
# Avoid gnulib's tests for HAVE_WORKING_O_NOATIME and HAVE_WORKING_O_NOFOLLOW,
# as we don't use them.
AC_DEFUN([gl_FCNTL_O_FLAGS])
# Avoid gnulib's threadlib module, as we do threads our own way.
AC_DEFUN([gl_THREADLIB])

View file

@ -1,3 +1,8 @@
2013-03-05 Paul Eggert <eggert@cs.ucla.edu>
FILE's lock is now always .#FILE and may be a regular file (Bug#13807).
* NEWS: Document this.
2013-03-02 Bill Wohler <wohler@newt.com>
Release MH-E version 8.5.

View file

@ -320,7 +320,7 @@ 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'.
** The lock for 'DIR/FILE' is now 'DIR/.#FILE' and may be a regular 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
@ -328,9 +328,8 @@ 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.
On file systems that do not support symbolic links, the lock is now a
regular file with contents being what would have been in the symlink.
** 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

View file

@ -1,3 +1,8 @@
2013-03-05 Paul Eggert <eggert@cs.ucla.edu>
FILE's lock is now always .#FILE and may be a regular file (Bug#13807).
* inc/unistd.h (O_NOFOLLOW): New macro.
2013-03-04 Juanma Barranquero <lekktu@gmail.com>
* config.nt: Sync with autogen/config.in.

View file

@ -27,8 +27,9 @@ extern int faccessat (int, char const *, int, int);
#define AT_EACCESS 4
#define AT_SYMLINK_NOFOLLOW 4096
#define O_NOCTTY 0
#define O_IGNORE_CTTY 0
#define O_NOCTTY 0
#define O_NOFOLLOW 0
/* This is normally on stdlib.h, but we don't override that header. */
extern int unsetenv (const char *);

View file

@ -1,3 +1,55 @@
2013-03-05 Paul Eggert <eggert@cs.ucla.edu>
FILE's lock is now always .#FILE and may be a regular file (Bug#13807).
* filelock.c: Include <c-ctype.h>.
(MAX_LFINFO): New top-level constant.
(lock_info_type): Remove members pid, boot_time. Add members at,
dot, colon. Change user member to be the entire buffer, not a
pointer. This allows us to handle the case where a foreign
pid or boot time exceeds the local range. All uses changed.
(LINKS_MIGHT_NOT_WORK): New constant.
(FREE_LOCK_INFO): Remove, as the pieces no longer need freeing.
(defined_WINDOWSNT): Remove.
(MAKE_LOCK_NAME, file_in_lock_file_name):
Always use .#FILE (not .#-FILE) for the file lock,
even if it is a regular file.
(rename_lock_file): New function.
(create_lock_file): Use it.
(create_lock_file, read_lock_data):
Prefer a symbolic link for the lock file, falling back on a
regular file if symlinks don't work. Do not try to create
symlinks on MS-Windows, due to security hassles. Stick with
POSIXish functions (open, read, write, close, fchmod, readlink, symlink,
link, rename, unlink, mkstemp) when creating locks, as a GNUish
host may be using a Windowsish file system, and cannot use
MS-Windows-only system calls. Fall back on mktemp if mkstemp
doesn't work. Don't fail merely because of a symlink-contents
length limit in the current file system; fall back on regular
files. Increase the symlink contents length limit to 8 KiB, this
should be big enough for any real use and doesn't crunch the
stack.
(create_lock_file, lock_file_1, read_lock_data):
Simplify allocation of lock file buffers now that they fit in 8 KiB.
(lock_file_1): Return error number, not bool. All callers changed.
(ELOOP): New macro, if not already defined.
(read_lock_data): Return size of lock file contents, not Lisp object.
All callers changed. Handle a race condition if some other process
replaces a regular-file lock with a symlink lock or vice versa,
while we're trying to read the lock.
(current_lock_owner): Parse contents more carefully, to help avoid
confusing a regular-file lock with some other application's use
of the file. Check for lock file contents being too long, or
not parsing correctly.
(current_lock_owner, lock_file):
Allow foreign pid and boot times that exceed the local range.
(current_lock_owner, lock_if_free, lock_file):
Simplify allocation of lock file contents.
* w32.c (sys_rename_replace): New function, containing most of
the contents of the old sys_rename.
(sys_rename): Use it.
(fchmod): New dummy function.
* w32.h (sys_rename_replace, fchmod): New decls.
2013-03-05 Eli Zaretskii <eliz@gnu.org>
* bidi.c (bidi_resolve_explicit_1): Don't call CHAR_TO_BYTE or

View file

@ -38,6 +38,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include <errno.h>
#include <c-ctype.h>
#include "lisp.h"
#include "character.h"
#include "buffer.h"
@ -64,7 +66,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#define WTMP_FILE "/var/log/wtmp"
#endif
/* On non-MS-Windows systems, use a symbolic link to represent a lock.
/* Normally 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.
@ -100,10 +102,21 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
--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. */
On some file systems, notably those of 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'. To
establish a lock, a nonce file is created and then renamed to .#FN.
On MS-Windows this renaming is atomic unless the lock is forcibly
acquired. On other systems the renaming is atomic if the lock is
forcibly acquired; if not, the renaming is done via hard links,
which is good enough for lock-file purposes.
To summarize, race conditions can occur with either:
* Forced locks on MS-Windows systems.
* Non-forced locks on non-MS-Windows systems that support neither
hard nor symbolic links. */
/* Return the time of the last system boot. */
@ -284,30 +297,31 @@ get_boot_time_1 (const char *filename, bool newest)
}
#endif /* BOOT_TIME */
/* An arbitrary limit on lock contents length. 8 K should be plenty
big enough in practice. */
enum { MAX_LFINFO = 8 * 1024 };
/* Here is the structure that stores information about a lock. */
typedef struct
{
char *user;
char *host;
pid_t pid;
time_t boot_time;
/* Location of '@', '.', ':' in USER. If there's no colon, COLON
points to the end of USER. */
char *at, *dot, *colon;
/* Lock file contents USER@HOST.PID with an optional :BOOT_TIME
appended. This memory is used as a lock file contents buffer, so
it needs room for MAX_LFINFO + 1 bytes. A string " (pid NNNN)"
may be appended to the USER@HOST while generating a diagnostic,
so make room for its extra bytes (as opposed to ".NNNN") too. */
char user[MAX_LFINFO + 1 + sizeof " (pid )" - sizeof "."];
} lock_info_type;
/* Free the two dynamically-allocated pieces in PTR. */
#define FREE_LOCK_INFO(i) do { xfree ((i).user); xfree ((i).host); } while (0)
#ifdef WINDOWSNT
enum { defined_WINDOWSNT = 1 };
#else
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. */
will be that of FNAME plus two more for the leading ".#", plus one
for the null. */
#define MAKE_LOCK_NAME(lockname, fname) \
(lockname = SAFE_ALLOCA (SBYTES (fname) + 2 + defined_WINDOWSNT + 1), \
(lockname = SAFE_ALLOCA (SBYTES (fname) + 2 + 1), \
fill_in_lock_file_name (lockname, fname))
static void
@ -319,70 +333,131 @@ fill_in_lock_file_name (char *lockfile, Lisp_Object fn)
memcpy (lockfile, SSDATA (fn), dirlen);
lockfile[dirlen] = '.';
lockfile[dirlen + 1] = '#';
if (defined_WINDOWSNT)
lockfile[dirlen + 2] = '-';
strcpy (lockfile + dirlen + 2 + defined_WINDOWSNT, base);
strcpy (lockfile + dirlen + 2, base);
}
/* For some reason Linux kernels return EPERM on file systems that do
not support hard or symbolic links. This symbol documents the quirk.
There is no way to tell whether a symlink call fails due to
permissions issues or because links are not supported, but luckily
the lock file code should work either way. */
enum { LINKS_MIGHT_NOT_WORK = EPERM };
/* Rename OLD to NEW. If FORCE, replace any existing NEW.
It is OK if there are temporarily two hard links to OLD.
Return 0 if successful, -1 (setting errno) otherwise. */
static int
rename_lock_file (char const *old, char const *new, bool force)
{
#ifdef WINDOWSNT
return sys_rename_replace (old, new, force);
#else
if (! force)
{
struct stat st;
if (link (old, new) == 0)
return unlink (old) == 0 || errno == ENOENT ? 0 : -1;
if (errno != ENOSYS && errno != LINKS_MIGHT_NOT_WORK)
return -1;
/* 'link' does not work on this file system. This can occur on
a GNU/Linux host mounting a FAT32 file system. Fall back on
'rename' after checking that NEW does not exist. There is a
potential race condition since some other process may create
NEW immediately after the existence check, but it's the best
we can portably do here. */
if (lstat (new, &st) == 0 || errno == EOVERFLOW)
{
errno = EEXIST;
return -1;
}
if (errno != ENOENT)
return -1;
}
return rename (old, new);
#endif
}
/* Create the lock file FILE with contents CONTENTS. Return 0 if
successful, an errno value on failure. If FORCE, remove any
existing FILE if necessary. */
static int
create_lock_file (char *lfname, char *lock_info_str, bool force)
{
int err;
#ifdef WINDOWSNT
/* Symlinks are supported only by latest versions of Windows, and
creating them is a privileged operation that often triggers UAC
elevation prompts. Therefore, instead of using symlinks, we
create a regular file with the lock info written as its
contents. */
{
/* 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 WINDOWSNT
processes are concerned. */
int fd = _sopen (lfname,
_O_WRONLY | _O_BINARY | _O_CREAT | _O_EXCL | _O_NOINHERIT,
_SH_DENYRW, S_IREAD | S_IWRITE);
if (fd < 0 && errno == EEXIST && force)
fd = _sopen (lfname, _O_WRONLY | _O_BINARY | _O_TRUNC |_O_NOINHERIT,
_SH_DENYRW, S_IREAD | S_IWRITE);
if (fd >= 0)
{
ssize_t lock_info_len = strlen (lock_info_str);
err = 0;
if (emacs_write (fd, lock_info_str, lock_info_len) != lock_info_len)
err = -1;
if (emacs_close (fd))
err = -1;
}
else
err = -1;
}
/* Symlinks are supported only by later versions of Windows, and
creating them is a privileged operation that often triggers
User Account Control elevation prompts. Avoid the problem by
pretending that 'symlink' does not work. */
int err = ENOSYS;
#else
err = symlink (lock_info_str, lfname);
if (err != 0 && errno == EEXIST && force)
int err = symlink (lock_info_str, lfname) == 0 ? 0 : errno;
#endif
if (err == EEXIST && force)
{
unlink (lfname);
err = symlink (lock_info_str, lfname);
err = symlink (lock_info_str, lfname) == 0 ? 0 : errno;
}
if (err == ENOSYS || err == LINKS_MIGHT_NOT_WORK || err == ENAMETOOLONG)
{
static char const nonce_base[] = ".#-emacsXXXXXX";
char *last_slash = strrchr (lfname, '/');
ptrdiff_t lfdirlen = last_slash + 1 - lfname;
USE_SAFE_ALLOCA;
char *nonce = SAFE_ALLOCA (lfdirlen + sizeof nonce_base);
int fd;
bool need_fchmod;
mode_t world_readable = S_IRUSR | S_IRGRP | S_IROTH;
memcpy (nonce, lfname, lfdirlen);
strcpy (nonce + lfdirlen, nonce_base);
#if HAVE_MKSTEMP
/* Prefer mkstemp if available, as it avoids a race between
mktemp and emacs_open. */
fd = mkstemp (nonce);
need_fchmod = 1;
#else
mktemp (nonce);
fd = emacs_open (nonce, O_WRONLY | O_CREAT | O_EXCL | O_BINARY,
world_readable);
need_fchmod = 0;
#endif
if (fd < 0)
err = errno;
else
{
ptrdiff_t lock_info_len = strlen (lock_info_str);
err = 0;
if (emacs_write (fd, lock_info_str, lock_info_len) != lock_info_len
|| (need_fchmod && fchmod (fd, world_readable) != 0))
err = errno;
if (emacs_close (fd) != 0)
err = errno;
if (!err && rename_lock_file (nonce, lfname, force) != 0)
err = errno;
if (err)
unlink (nonce);
}
SAFE_FREE ();
}
return err;
}
/* Lock the lock file named LFNAME.
If FORCE, do so even if it is already locked.
Return true if successful. */
Return 0 if successful, an error number on failure. */
static bool
static int
lock_file_1 (char *lfname, bool force)
{
int err;
int symlink_errno;
USE_SAFE_ALLOCA;
/* Call this first because it can GC. */
printmax_t boot = get_boot_time ();
@ -390,20 +465,16 @@ lock_file_1 (char *lfname, bool force)
char const *user_name = STRINGP (luser_name) ? SSDATA (luser_name) : "";
Lisp_Object lhost_name = Fsystem_name ();
char const *host_name = STRINGP (lhost_name) ? SSDATA (lhost_name) : "";
ptrdiff_t lock_info_size = (strlen (user_name) + strlen (host_name)
+ 2 * INT_STRLEN_BOUND (printmax_t)
+ sizeof "@.:");
char *lock_info_str = SAFE_ALLOCA (lock_info_size);
char lock_info_str[MAX_LFINFO + 1];
printmax_t pid = getpid ();
esprintf (lock_info_str, boot ? "%s@%s.%"pMd":%"pMd : "%s@%s.%"pMd,
user_name, host_name, pid, boot);
err = create_lock_file (lfname, lock_info_str, force);
if (sizeof lock_info_str
<= snprintf (lock_info_str, sizeof lock_info_str,
boot ? "%s@%s.%"pMd":%"pMd : "%s@%s.%"pMd,
user_name, host_name, pid, boot))
return ENAMETOOLONG;
symlink_errno = errno;
SAFE_FREE ();
errno = symlink_errno;
return err == 0;
return create_lock_file (lfname, lock_info_str, force);
}
/* Return true if times A and B are no more than one second apart. */
@ -414,32 +485,44 @@ within_one_second (time_t a, time_t b)
return (a - b >= -1 && a - b <= 1);
}
static Lisp_Object
read_lock_data (char *lfname)
{
#ifndef WINDOWSNT
return emacs_readlinkat (AT_FDCWD, 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)
return Qnil;
nbytes = emacs_read (fd, lfinfo, MAX_LFINFO);
emacs_close (fd);
if (nbytes > 0)
{
lfinfo[nbytes] = '\0';
return build_string (lfinfo);
}
else
return Qnil;
/* On systems lacking ELOOP, test for an errno value that shouldn't occur. */
#ifndef ELOOP
# define ELOOP (-1)
#endif
/* Read the data for the lock file LFNAME into LFINFO. Read at most
MAX_LFINFO + 1 bytes. Return the number of bytes read, or -1
(setting errno) on error. */
static ptrdiff_t
read_lock_data (char *lfname, char lfinfo[MAX_LFINFO + 1])
{
ptrdiff_t nbytes;
while ((nbytes = readlinkat (AT_FDCWD, lfname, lfinfo, MAX_LFINFO + 1)) < 0
&& errno == EINVAL)
{
int fd = emacs_open (lfname, O_RDONLY | O_BINARY | O_NOFOLLOW, 0);
if (0 <= fd)
{
ptrdiff_t read_bytes = emacs_read (fd, lfinfo, MAX_LFINFO + 1);
int read_errno = errno;
if (emacs_close (fd) != 0)
return -1;
errno = read_errno;
return read_bytes;
}
if (errno != ELOOP)
return -1;
/* readlinkat saw a non-symlink, but emacs_open saw a symlink.
The former must have been removed and replaced by the latter.
Try again. */
QUIT;
}
return nbytes;
}
/* Return 0 if nobody owns the lock file LFNAME or the lock is obsolete,
@ -451,83 +534,78 @@ static int
current_lock_owner (lock_info_type *owner, char *lfname)
{
int ret;
ptrdiff_t len;
lock_info_type local_owner;
intmax_t n;
char *at, *dot, *colon;
Lisp_Object lfinfo_object = read_lock_data (lfname);
char *lfinfo;
struct gcpro gcpro1;
/* If nonexistent lock file, all is well; otherwise, got strange error. */
if (NILP (lfinfo_object))
return errno == ENOENT ? 0 : -1;
lfinfo = SSDATA (lfinfo_object);
ptrdiff_t lfinfolen;
intmax_t pid, boot_time;
char *at, *dot, *lfinfo_end;
/* Even if the caller doesn't want the owner info, we still have to
read it to determine return value. */
if (!owner)
owner = &local_owner;
/* If nonexistent lock file, all is well; otherwise, got strange error. */
lfinfolen = read_lock_data (lfname, owner->user);
if (lfinfolen < 0)
return errno == ENOENT ? 0 : -1;
if (MAX_LFINFO < lfinfolen)
return -1;
owner->user[lfinfolen] = 0;
/* Parse USER@HOST.PID:BOOT_TIME. If can't parse, return -1. */
/* The USER is everything before the last @. */
at = strrchr (lfinfo, '@');
dot = strrchr (lfinfo, '.');
if (!at || !dot)
owner->at = at = memrchr (owner->user, '@', lfinfolen);
if (!at)
return -1;
owner->dot = dot = strrchr (at, '.');
if (!dot)
return -1;
len = at - lfinfo;
GCPRO1 (lfinfo_object);
owner->user = xmalloc (len + 1);
memcpy (owner->user, lfinfo, len);
owner->user[len] = 0;
/* The PID is everything from the last `.' to the `:'. */
if (! c_isdigit (dot[1]))
return -1;
errno = 0;
n = strtoimax (dot + 1, NULL, 10);
owner->pid =
((0 <= n && n <= TYPE_MAXIMUM (pid_t)
&& (TYPE_MAXIMUM (pid_t) < INTMAX_MAX || errno != ERANGE))
? n : 0);
pid = strtoimax (dot + 1, &owner->colon, 10);
if (errno == ERANGE)
pid = -1;
colon = strchr (dot + 1, ':');
/* After the `:', if there is one, comes the boot time. */
n = 0;
if (colon)
switch (owner->colon[0])
{
errno = 0;
n = strtoimax (colon + 1, NULL, 10);
case 0:
boot_time = 0;
lfinfo_end = owner->colon;
break;
case ':':
if (! c_isdigit (owner->colon[1]))
return -1;
boot_time = strtoimax (owner->colon + 1, &lfinfo_end, 10);
break;
default:
return -1;
}
owner->boot_time =
((0 <= n && n <= TYPE_MAXIMUM (time_t)
&& (TYPE_MAXIMUM (time_t) < INTMAX_MAX || errno != ERANGE))
? n : 0);
/* The host is everything in between. */
len = dot - at - 1;
owner->host = xmalloc (len + 1);
memcpy (owner->host, at + 1, len);
owner->host[len] = 0;
/* We're done looking at the link info. */
UNGCPRO;
if (lfinfo_end != owner->user + lfinfolen)
return -1;
/* On current host? */
if (STRINGP (Fsystem_name ())
&& strcmp (owner->host, SSDATA (Fsystem_name ())) == 0)
if (STRINGP (Vsystem_name)
&& dot - (at + 1) == SBYTES (Vsystem_name)
&& memcmp (at + 1, SSDATA (Vsystem_name), SBYTES (Vsystem_name)) == 0)
{
if (owner->pid == getpid ())
if (pid == getpid ())
ret = 2; /* We own it. */
else if (owner->pid > 0
&& (kill (owner->pid, 0) >= 0 || errno == EPERM)
&& (owner->boot_time == 0
|| within_one_second (owner->boot_time, get_boot_time ())))
else if (0 < pid && pid <= TYPE_MAXIMUM (pid_t)
&& (kill (pid, 0) >= 0 || errno == EPERM)
&& (boot_time == 0
|| (boot_time <= TYPE_MAXIMUM (time_t)
&& within_one_second (boot_time, get_boot_time ()))))
ret = 1; /* An existing process on this machine owns it. */
/* The owner process is dead or has a strange pid (<=0), so try to
/* The owner process is dead or has a strange pid, so try to
zap the lockfile. */
else if (unlink (lfname) < 0)
ret = -1;
else
ret = 0;
return unlink (lfname);
}
else
{ /* If we wanted to support the check for stale locks on remote machines,
@ -535,11 +613,6 @@ current_lock_owner (lock_info_type *owner, char *lfname)
ret = 1;
}
/* Avoid garbage. */
if (owner == &local_owner || ret <= 0)
{
FREE_LOCK_INFO (*owner);
}
return ret;
}
@ -551,29 +624,25 @@ current_lock_owner (lock_info_type *owner, char *lfname)
Return -1 if cannot lock for any other reason. */
static int
lock_if_free (lock_info_type *clasher, register char *lfname)
lock_if_free (lock_info_type *clasher, char *lfname)
{
while (! lock_file_1 (lfname, 0))
int err;
while ((err = lock_file_1 (lfname, 0)) == EEXIST)
{
int locker;
if (errno != EEXIST)
return -1;
locker = current_lock_owner (clasher, lfname);
if (locker == 2)
{
FREE_LOCK_INFO (*clasher);
return 0; /* We ourselves locked it. */
}
else if (locker == 1)
return 1; /* Someone else has it. */
else if (locker == -1)
return -1; /* current_lock_owner returned strange error. */
switch (current_lock_owner (clasher, lfname))
{
case 2:
return 0; /* We ourselves locked it. */
case 1:
return 1; /* Someone else has it. */
case -1:
return -1; /* current_lock_owner returned strange error. */
}
/* We deleted a stale lock; try again to lock the file. */
}
return 0;
return err ? -1 : 0;
}
/* lock_file locks file FN,
@ -645,17 +714,16 @@ lock_file (Lisp_Object fn)
if (0 < lock_if_free (&lock_info, lfname))
{
/* Someone else has the lock. Consider breaking it. */
ptrdiff_t locker_size = (strlen (lock_info.user) + strlen (lock_info.host)
+ INT_STRLEN_BOUND (printmax_t)
+ sizeof "@ (pid )");
char *locker = SAFE_ALLOCA (locker_size);
printmax_t pid = lock_info.pid;
Lisp_Object attack;
esprintf (locker, "%s@%s (pid %"pMd")",
lock_info.user, lock_info.host, pid);
FREE_LOCK_INFO (lock_info);
attack = call2 (intern ("ask-user-about-lock"), fn, build_string (locker));
char *dot = lock_info.dot;
ptrdiff_t pidlen = lock_info.colon - (dot + 1);
static char const replacement[] = " (pid ";
int replacementlen = sizeof replacement - 1;
memmove (dot + replacementlen, dot + 1, pidlen);
strcpy (dot + replacementlen + pidlen, ")");
memcpy (dot, replacement, replacementlen);
attack = call2 (intern ("ask-user-about-lock"), fn,
build_string (lock_info.user));
/* Take the lock if the user said so. */
if (!NILP (attack))
lock_file_1 (lfname, 1);
@ -760,10 +828,7 @@ t if it is locked by you, else a string saying which user has locked it. */)
else if (owner == 2)
ret = Qt;
else
ret = build_string (locker.user);
if (owner > 0)
FREE_LOCK_INFO (locker);
ret = make_string (locker.user, locker.at - locker.user);
SAFE_FREE ();
return ret;

View file

@ -3416,7 +3416,13 @@ sys_open (const char * path, int oflag, int mode)
}
int
sys_rename (const char * oldname, const char * newname)
fchmod (int fd, mode_t mode)
{
return 0;
}
int
sys_rename_replace (const char *oldname, const char *newname, BOOL force)
{
BOOL result;
char temp[MAX_PATH];
@ -3472,7 +3478,7 @@ sys_rename (const char * oldname, const char * newname)
return -1;
}
/* Emulate Unix behavior - newname is deleted if it already exists
/* If FORCE, emulate Unix behavior - newname is deleted if it already exists
(at least if it is a file; don't do this for directories).
Since we mustn't do this if we are just changing the case of the
@ -3490,7 +3496,7 @@ sys_rename (const char * oldname, const char * newname)
result = rename (temp, newname);
if (result < 0)
if (result < 0 && force)
{
DWORD w32err = GetLastError ();
@ -3529,6 +3535,12 @@ sys_rename (const char * oldname, const char * newname)
return result;
}
int
sys_rename (char const *old, char const *new)
{
return sys_rename_replace (old, new, TRUE);
}
int
sys_rmdir (const char * path)
{

View file

@ -186,6 +186,8 @@ extern BOOL init_winsock (int load_now);
extern void srandom (int);
extern int random (void);
extern int fchmod (int, mode_t);
extern int sys_rename_replace (char const *, char const *, BOOL);
extern int sys_pipe (int *);
extern void set_process_dir (char *);