aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2013-03-05 14:35:41 -0800
committerPaul Eggert2013-03-05 14:35:41 -0800
commit707431575aef93ac3e9923d450a6cbf18192c933 (patch)
treec81ecb9af767baaea6876c956b6fc921ebb6ac9e /src
parent05e193f1706f5d9846530e734d0271b15b9a818c (diff)
downloademacs-707431575aef93ac3e9923d450a6cbf18192c933.tar.gz
emacs-707431575aef93ac3e9923d450a6cbf18192c933.zip
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
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog52
-rw-r--r--src/filelock.c439
-rw-r--r--src/w32.c18
-rw-r--r--src/w32.h2
4 files changed, 321 insertions, 190 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index c4b4703e59d..af03fa54291 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,55 @@
12013-03-05 Paul Eggert <eggert@cs.ucla.edu>
2
3 FILE's lock is now always .#FILE and may be a regular file (Bug#13807).
4 * filelock.c: Include <c-ctype.h>.
5 (MAX_LFINFO): New top-level constant.
6 (lock_info_type): Remove members pid, boot_time. Add members at,
7 dot, colon. Change user member to be the entire buffer, not a
8 pointer. This allows us to handle the case where a foreign
9 pid or boot time exceeds the local range. All uses changed.
10 (LINKS_MIGHT_NOT_WORK): New constant.
11 (FREE_LOCK_INFO): Remove, as the pieces no longer need freeing.
12 (defined_WINDOWSNT): Remove.
13 (MAKE_LOCK_NAME, file_in_lock_file_name):
14 Always use .#FILE (not .#-FILE) for the file lock,
15 even if it is a regular file.
16 (rename_lock_file): New function.
17 (create_lock_file): Use it.
18 (create_lock_file, read_lock_data):
19 Prefer a symbolic link for the lock file, falling back on a
20 regular file if symlinks don't work. Do not try to create
21 symlinks on MS-Windows, due to security hassles. Stick with
22 POSIXish functions (open, read, write, close, fchmod, readlink, symlink,
23 link, rename, unlink, mkstemp) when creating locks, as a GNUish
24 host may be using a Windowsish file system, and cannot use
25 MS-Windows-only system calls. Fall back on mktemp if mkstemp
26 doesn't work. Don't fail merely because of a symlink-contents
27 length limit in the current file system; fall back on regular
28 files. Increase the symlink contents length limit to 8 KiB, this
29 should be big enough for any real use and doesn't crunch the
30 stack.
31 (create_lock_file, lock_file_1, read_lock_data):
32 Simplify allocation of lock file buffers now that they fit in 8 KiB.
33 (lock_file_1): Return error number, not bool. All callers changed.
34 (ELOOP): New macro, if not already defined.
35 (read_lock_data): Return size of lock file contents, not Lisp object.
36 All callers changed. Handle a race condition if some other process
37 replaces a regular-file lock with a symlink lock or vice versa,
38 while we're trying to read the lock.
39 (current_lock_owner): Parse contents more carefully, to help avoid
40 confusing a regular-file lock with some other application's use
41 of the file. Check for lock file contents being too long, or
42 not parsing correctly.
43 (current_lock_owner, lock_file):
44 Allow foreign pid and boot times that exceed the local range.
45 (current_lock_owner, lock_if_free, lock_file):
46 Simplify allocation of lock file contents.
47 * w32.c (sys_rename_replace): New function, containing most of
48 the contents of the old sys_rename.
49 (sys_rename): Use it.
50 (fchmod): New dummy function.
51 * w32.h (sys_rename_replace, fchmod): New decls.
52
12013-03-05 Eli Zaretskii <eliz@gnu.org> 532013-03-05 Eli Zaretskii <eliz@gnu.org>
2 54
3 * bidi.c (bidi_resolve_explicit_1): Don't call CHAR_TO_BYTE or 55 * bidi.c (bidi_resolve_explicit_1): Don't call CHAR_TO_BYTE or
diff --git a/src/filelock.c b/src/filelock.c
index 14b9d4aaca5..32992896c2b 100644
--- a/src/filelock.c
+++ b/src/filelock.c
@@ -38,6 +38,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
38 38
39#include <errno.h> 39#include <errno.h>
40 40
41#include <c-ctype.h>
42
41#include "lisp.h" 43#include "lisp.h"
42#include "character.h" 44#include "character.h"
43#include "buffer.h" 45#include "buffer.h"
@@ -64,7 +66,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
64#define WTMP_FILE "/var/log/wtmp" 66#define WTMP_FILE "/var/log/wtmp"
65#endif 67#endif
66 68
67/* On non-MS-Windows systems, use a symbolic link to represent a lock. 69/* Normally use a symbolic link to represent a lock.
68 The strategy: to lock a file FN, create a symlink .#FN in FN's 70 The strategy: to lock a file FN, create a symlink .#FN in FN's
69 directory, with link data `user@host.pid'. This avoids a single 71 directory, with link data `user@host.pid'. This avoids a single
70 mount (== failure) point for lock files. 72 mount (== failure) point for lock files.
@@ -100,10 +102,21 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
100 102
101 --karl@cs.umb.edu/karl@hq.ileaf.com. 103 --karl@cs.umb.edu/karl@hq.ileaf.com.
102 104
103 On MS-Windows, symbolic links do not work well, so instead of a 105 On some file systems, notably those of MS-Windows, symbolic links
104 symlink .#FN -> 'user@host.pid', the lock is a regular file .#-FN 106 do not work well, so instead of a symlink .#FN -> 'user@host.pid',
105 with contents 'user@host.pid'. MS-Windows and non-MS-Windows 107 the lock is a regular file .#FN with contents 'user@host.pid'. To
106 versions of Emacs ignore each other's locks. */ 108 establish a lock, a nonce file is created and then renamed to .#FN.
109 On MS-Windows this renaming is atomic unless the lock is forcibly
110 acquired. On other systems the renaming is atomic if the lock is
111 forcibly acquired; if not, the renaming is done via hard links,
112 which is good enough for lock-file purposes.
113
114 To summarize, race conditions can occur with either:
115
116 * Forced locks on MS-Windows systems.
117
118 * Non-forced locks on non-MS-Windows systems that support neither
119 hard nor symbolic links. */
107 120
108 121
109/* Return the time of the last system boot. */ 122/* Return the time of the last system boot. */
@@ -284,30 +297,31 @@ get_boot_time_1 (const char *filename, bool newest)
284} 297}
285#endif /* BOOT_TIME */ 298#endif /* BOOT_TIME */
286 299
300/* An arbitrary limit on lock contents length. 8 K should be plenty
301 big enough in practice. */
302enum { MAX_LFINFO = 8 * 1024 };
303
287/* Here is the structure that stores information about a lock. */ 304/* Here is the structure that stores information about a lock. */
288 305
289typedef struct 306typedef struct
290{ 307{
291 char *user; 308 /* Location of '@', '.', ':' in USER. If there's no colon, COLON
292 char *host; 309 points to the end of USER. */
293 pid_t pid; 310 char *at, *dot, *colon;
294 time_t boot_time;
295} lock_info_type;
296
297/* Free the two dynamically-allocated pieces in PTR. */
298#define FREE_LOCK_INFO(i) do { xfree ((i).user); xfree ((i).host); } while (0)
299 311
300#ifdef WINDOWSNT 312 /* Lock file contents USER@HOST.PID with an optional :BOOT_TIME
301enum { defined_WINDOWSNT = 1 }; 313 appended. This memory is used as a lock file contents buffer, so
302#else 314 it needs room for MAX_LFINFO + 1 bytes. A string " (pid NNNN)"
303enum { defined_WINDOWSNT = 0 }; 315 may be appended to the USER@HOST while generating a diagnostic,
304#endif 316 so make room for its extra bytes (as opposed to ".NNNN") too. */
317 char user[MAX_LFINFO + 1 + sizeof " (pid )" - sizeof "."];
318} lock_info_type;
305 319
306/* Write the name of the lock file for FNAME into LOCKNAME. Length 320/* Write the name of the lock file for FNAME into LOCKNAME. Length
307 will be that of FNAME plus two more for the leading ".#", 321 will be that of FNAME plus two more for the leading ".#", plus one
308 plus one for "-" if MS-Windows, plus one for the null. */ 322 for the null. */
309#define MAKE_LOCK_NAME(lockname, fname) \ 323#define MAKE_LOCK_NAME(lockname, fname) \
310 (lockname = SAFE_ALLOCA (SBYTES (fname) + 2 + defined_WINDOWSNT + 1), \ 324 (lockname = SAFE_ALLOCA (SBYTES (fname) + 2 + 1), \
311 fill_in_lock_file_name (lockname, fname)) 325 fill_in_lock_file_name (lockname, fname))
312 326
313static void 327static void
@@ -319,70 +333,131 @@ fill_in_lock_file_name (char *lockfile, Lisp_Object fn)
319 memcpy (lockfile, SSDATA (fn), dirlen); 333 memcpy (lockfile, SSDATA (fn), dirlen);
320 lockfile[dirlen] = '.'; 334 lockfile[dirlen] = '.';
321 lockfile[dirlen + 1] = '#'; 335 lockfile[dirlen + 1] = '#';
322 if (defined_WINDOWSNT) 336 strcpy (lockfile + dirlen + 2, base);
323 lockfile[dirlen + 2] = '-';
324 strcpy (lockfile + dirlen + 2 + defined_WINDOWSNT, base);
325} 337}
326 338
339/* For some reason Linux kernels return EPERM on file systems that do
340 not support hard or symbolic links. This symbol documents the quirk.
341 There is no way to tell whether a symlink call fails due to
342 permissions issues or because links are not supported, but luckily
343 the lock file code should work either way. */
344enum { LINKS_MIGHT_NOT_WORK = EPERM };
345
346/* Rename OLD to NEW. If FORCE, replace any existing NEW.
347 It is OK if there are temporarily two hard links to OLD.
348 Return 0 if successful, -1 (setting errno) otherwise. */
327static int 349static int
328create_lock_file (char *lfname, char *lock_info_str, bool force) 350rename_lock_file (char const *old, char const *new, bool force)
329{ 351{
330 int err;
331
332#ifdef WINDOWSNT 352#ifdef WINDOWSNT
333 /* Symlinks are supported only by latest versions of Windows, and 353 return sys_rename_replace (old, new, force);
334 creating them is a privileged operation that often triggers UAC 354#else
335 elevation prompts. Therefore, instead of using symlinks, we 355 if (! force)
336 create a regular file with the lock info written as its 356 {
337 contents. */ 357 struct stat st;
338 {
339 /* Deny everybody else any kind of access to the file until we are
340 done writing it and close the handle. This makes the entire
341 open/write/close operation atomic, as far as other WINDOWSNT
342 processes are concerned. */
343 int fd = _sopen (lfname,
344 _O_WRONLY | _O_BINARY | _O_CREAT | _O_EXCL | _O_NOINHERIT,
345 _SH_DENYRW, S_IREAD | S_IWRITE);
346
347 if (fd < 0 && errno == EEXIST && force)
348 fd = _sopen (lfname, _O_WRONLY | _O_BINARY | _O_TRUNC |_O_NOINHERIT,
349 _SH_DENYRW, S_IREAD | S_IWRITE);
350 if (fd >= 0)
351 {
352 ssize_t lock_info_len = strlen (lock_info_str);
353 358
354 err = 0; 359 if (link (old, new) == 0)
355 if (emacs_write (fd, lock_info_str, lock_info_len) != lock_info_len) 360 return unlink (old) == 0 || errno == ENOENT ? 0 : -1;
356 err = -1; 361 if (errno != ENOSYS && errno != LINKS_MIGHT_NOT_WORK)
357 if (emacs_close (fd)) 362 return -1;
358 err = -1; 363
359 } 364 /* 'link' does not work on this file system. This can occur on
360 else 365 a GNU/Linux host mounting a FAT32 file system. Fall back on
361 err = -1; 366 'rename' after checking that NEW does not exist. There is a
362 } 367 potential race condition since some other process may create
368 NEW immediately after the existence check, but it's the best
369 we can portably do here. */
370 if (lstat (new, &st) == 0 || errno == EOVERFLOW)
371 {
372 errno = EEXIST;
373 return -1;
374 }
375 if (errno != ENOENT)
376 return -1;
377 }
378
379 return rename (old, new);
380#endif
381}
382
383/* Create the lock file FILE with contents CONTENTS. Return 0 if
384 successful, an errno value on failure. If FORCE, remove any
385 existing FILE if necessary. */
386
387static int
388create_lock_file (char *lfname, char *lock_info_str, bool force)
389{
390#ifdef WINDOWSNT
391 /* Symlinks are supported only by later versions of Windows, and
392 creating them is a privileged operation that often triggers
393 User Account Control elevation prompts. Avoid the problem by
394 pretending that 'symlink' does not work. */
395 int err = ENOSYS;
363#else 396#else
364 err = symlink (lock_info_str, lfname); 397 int err = symlink (lock_info_str, lfname) == 0 ? 0 : errno;
365 if (err != 0 && errno == EEXIST && force) 398#endif
399
400 if (err == EEXIST && force)
366 { 401 {
367 unlink (lfname); 402 unlink (lfname);
368 err = symlink (lock_info_str, lfname); 403 err = symlink (lock_info_str, lfname) == 0 ? 0 : errno;
369 } 404 }
405
406 if (err == ENOSYS || err == LINKS_MIGHT_NOT_WORK || err == ENAMETOOLONG)
407 {
408 static char const nonce_base[] = ".#-emacsXXXXXX";
409 char *last_slash = strrchr (lfname, '/');
410 ptrdiff_t lfdirlen = last_slash + 1 - lfname;
411 USE_SAFE_ALLOCA;
412 char *nonce = SAFE_ALLOCA (lfdirlen + sizeof nonce_base);
413 int fd;
414 bool need_fchmod;
415 mode_t world_readable = S_IRUSR | S_IRGRP | S_IROTH;
416 memcpy (nonce, lfname, lfdirlen);
417 strcpy (nonce + lfdirlen, nonce_base);
418
419#if HAVE_MKSTEMP
420 /* Prefer mkstemp if available, as it avoids a race between
421 mktemp and emacs_open. */
422 fd = mkstemp (nonce);
423 need_fchmod = 1;
424#else
425 mktemp (nonce);
426 fd = emacs_open (nonce, O_WRONLY | O_CREAT | O_EXCL | O_BINARY,
427 world_readable);
428 need_fchmod = 0;
370#endif 429#endif
371 430
431 if (fd < 0)
432 err = errno;
433 else
434 {
435 ptrdiff_t lock_info_len = strlen (lock_info_str);
436 err = 0;
437 if (emacs_write (fd, lock_info_str, lock_info_len) != lock_info_len
438 || (need_fchmod && fchmod (fd, world_readable) != 0))
439 err = errno;
440 if (emacs_close (fd) != 0)
441 err = errno;
442 if (!err && rename_lock_file (nonce, lfname, force) != 0)
443 err = errno;
444 if (err)
445 unlink (nonce);
446 }
447
448 SAFE_FREE ();
449 }
450
372 return err; 451 return err;
373} 452}
374 453
375/* Lock the lock file named LFNAME. 454/* Lock the lock file named LFNAME.
376 If FORCE, do so even if it is already locked. 455 If FORCE, do so even if it is already locked.
377 Return true if successful. */ 456 Return 0 if successful, an error number on failure. */
378 457
379static bool 458static int
380lock_file_1 (char *lfname, bool force) 459lock_file_1 (char *lfname, bool force)
381{ 460{
382 int err;
383 int symlink_errno;
384 USE_SAFE_ALLOCA;
385
386 /* Call this first because it can GC. */ 461 /* Call this first because it can GC. */
387 printmax_t boot = get_boot_time (); 462 printmax_t boot = get_boot_time ();
388 463
@@ -390,20 +465,16 @@ lock_file_1 (char *lfname, bool force)
390 char const *user_name = STRINGP (luser_name) ? SSDATA (luser_name) : ""; 465 char const *user_name = STRINGP (luser_name) ? SSDATA (luser_name) : "";
391 Lisp_Object lhost_name = Fsystem_name (); 466 Lisp_Object lhost_name = Fsystem_name ();
392 char const *host_name = STRINGP (lhost_name) ? SSDATA (lhost_name) : ""; 467 char const *host_name = STRINGP (lhost_name) ? SSDATA (lhost_name) : "";
393 ptrdiff_t lock_info_size = (strlen (user_name) + strlen (host_name) 468 char lock_info_str[MAX_LFINFO + 1];
394 + 2 * INT_STRLEN_BOUND (printmax_t)
395 + sizeof "@.:");
396 char *lock_info_str = SAFE_ALLOCA (lock_info_size);
397 printmax_t pid = getpid (); 469 printmax_t pid = getpid ();
398 470
399 esprintf (lock_info_str, boot ? "%s@%s.%"pMd":%"pMd : "%s@%s.%"pMd, 471 if (sizeof lock_info_str
400 user_name, host_name, pid, boot); 472 <= snprintf (lock_info_str, sizeof lock_info_str,
401 err = create_lock_file (lfname, lock_info_str, force); 473 boot ? "%s@%s.%"pMd":%"pMd : "%s@%s.%"pMd,
474 user_name, host_name, pid, boot))
475 return ENAMETOOLONG;
402 476
403 symlink_errno = errno; 477 return create_lock_file (lfname, lock_info_str, force);
404 SAFE_FREE ();
405 errno = symlink_errno;
406 return err == 0;
407} 478}
408 479
409/* Return true if times A and B are no more than one second apart. */ 480/* 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)
414 return (a - b >= -1 && a - b <= 1); 485 return (a - b >= -1 && a - b <= 1);
415} 486}
416 487
417static Lisp_Object 488/* On systems lacking ELOOP, test for an errno value that shouldn't occur. */
418read_lock_data (char *lfname) 489#ifndef ELOOP
419{ 490# define ELOOP (-1)
420#ifndef WINDOWSNT 491#endif
421 return emacs_readlinkat (AT_FDCWD, lfname);
422#else
423 int fd = emacs_open (lfname, O_RDONLY | O_BINARY, S_IREAD);
424 ssize_t nbytes;
425 /* 256 chars for user, 1024 chars for host, 10 digits for each of 2 int's. */
426 enum { MAX_LFINFO = 256 + 1024 + 10 + 10 + 2 };
427 char lfinfo[MAX_LFINFO + 1];
428 492
429 if (fd < 0) 493/* Read the data for the lock file LFNAME into LFINFO. Read at most
430 return Qnil; 494 MAX_LFINFO + 1 bytes. Return the number of bytes read, or -1
495 (setting errno) on error. */
431 496
432 nbytes = emacs_read (fd, lfinfo, MAX_LFINFO); 497static ptrdiff_t
433 emacs_close (fd); 498read_lock_data (char *lfname, char lfinfo[MAX_LFINFO + 1])
499{
500 ptrdiff_t nbytes;
434 501
435 if (nbytes > 0) 502 while ((nbytes = readlinkat (AT_FDCWD, lfname, lfinfo, MAX_LFINFO + 1)) < 0
503 && errno == EINVAL)
436 { 504 {
437 lfinfo[nbytes] = '\0'; 505 int fd = emacs_open (lfname, O_RDONLY | O_BINARY | O_NOFOLLOW, 0);
438 return build_string (lfinfo); 506 if (0 <= fd)
507 {
508 ptrdiff_t read_bytes = emacs_read (fd, lfinfo, MAX_LFINFO + 1);
509 int read_errno = errno;
510 if (emacs_close (fd) != 0)
511 return -1;
512 errno = read_errno;
513 return read_bytes;
514 }
515
516 if (errno != ELOOP)
517 return -1;
518
519 /* readlinkat saw a non-symlink, but emacs_open saw a symlink.
520 The former must have been removed and replaced by the latter.
521 Try again. */
522 QUIT;
439 } 523 }
440 else 524
441 return Qnil; 525 return nbytes;
442#endif
443} 526}
444 527
445/* Return 0 if nobody owns the lock file LFNAME or the lock is obsolete, 528/* Return 0 if nobody owns the lock file LFNAME or the lock is obsolete,
@@ -451,83 +534,78 @@ static int
451current_lock_owner (lock_info_type *owner, char *lfname) 534current_lock_owner (lock_info_type *owner, char *lfname)
452{ 535{
453 int ret; 536 int ret;
454 ptrdiff_t len;
455 lock_info_type local_owner; 537 lock_info_type local_owner;
456 intmax_t n; 538 ptrdiff_t lfinfolen;
457 char *at, *dot, *colon; 539 intmax_t pid, boot_time;
458 Lisp_Object lfinfo_object = read_lock_data (lfname); 540 char *at, *dot, *lfinfo_end;
459 char *lfinfo;
460 struct gcpro gcpro1;
461
462 /* If nonexistent lock file, all is well; otherwise, got strange error. */
463 if (NILP (lfinfo_object))
464 return errno == ENOENT ? 0 : -1;
465 lfinfo = SSDATA (lfinfo_object);
466 541
467 /* Even if the caller doesn't want the owner info, we still have to 542 /* Even if the caller doesn't want the owner info, we still have to
468 read it to determine return value. */ 543 read it to determine return value. */
469 if (!owner) 544 if (!owner)
470 owner = &local_owner; 545 owner = &local_owner;
471 546
547 /* If nonexistent lock file, all is well; otherwise, got strange error. */
548 lfinfolen = read_lock_data (lfname, owner->user);
549 if (lfinfolen < 0)
550 return errno == ENOENT ? 0 : -1;
551 if (MAX_LFINFO < lfinfolen)
552 return -1;
553 owner->user[lfinfolen] = 0;
554
472 /* Parse USER@HOST.PID:BOOT_TIME. If can't parse, return -1. */ 555 /* Parse USER@HOST.PID:BOOT_TIME. If can't parse, return -1. */
473 /* The USER is everything before the last @. */ 556 /* The USER is everything before the last @. */
474 at = strrchr (lfinfo, '@'); 557 owner->at = at = memrchr (owner->user, '@', lfinfolen);
475 dot = strrchr (lfinfo, '.'); 558 if (!at)
476 if (!at || !dot) 559 return -1;
560 owner->dot = dot = strrchr (at, '.');
561 if (!dot)
477 return -1; 562 return -1;
478 len = at - lfinfo;
479 GCPRO1 (lfinfo_object);
480 owner->user = xmalloc (len + 1);
481 memcpy (owner->user, lfinfo, len);
482 owner->user[len] = 0;
483 563
484 /* The PID is everything from the last `.' to the `:'. */ 564 /* The PID is everything from the last `.' to the `:'. */
565 if (! c_isdigit (dot[1]))
566 return -1;
485 errno = 0; 567 errno = 0;
486 n = strtoimax (dot + 1, NULL, 10); 568 pid = strtoimax (dot + 1, &owner->colon, 10);
487 owner->pid = 569 if (errno == ERANGE)
488 ((0 <= n && n <= TYPE_MAXIMUM (pid_t) 570 pid = -1;
489 && (TYPE_MAXIMUM (pid_t) < INTMAX_MAX || errno != ERANGE))
490 ? n : 0);
491 571
492 colon = strchr (dot + 1, ':');
493 /* After the `:', if there is one, comes the boot time. */ 572 /* After the `:', if there is one, comes the boot time. */
494 n = 0; 573 switch (owner->colon[0])
495 if (colon)
496 { 574 {
497 errno = 0; 575 case 0:
498 n = strtoimax (colon + 1, NULL, 10); 576 boot_time = 0;
577 lfinfo_end = owner->colon;
578 break;
579
580 case ':':
581 if (! c_isdigit (owner->colon[1]))
582 return -1;
583 boot_time = strtoimax (owner->colon + 1, &lfinfo_end, 10);
584 break;
585
586 default:
587 return -1;
499 } 588 }
500 owner->boot_time = 589 if (lfinfo_end != owner->user + lfinfolen)
501 ((0 <= n && n <= TYPE_MAXIMUM (time_t) 590 return -1;
502 && (TYPE_MAXIMUM (time_t) < INTMAX_MAX || errno != ERANGE))
503 ? n : 0);
504
505 /* The host is everything in between. */
506 len = dot - at - 1;
507 owner->host = xmalloc (len + 1);
508 memcpy (owner->host, at + 1, len);
509 owner->host[len] = 0;
510
511 /* We're done looking at the link info. */
512 UNGCPRO;
513 591
514 /* On current host? */ 592 /* On current host? */
515 if (STRINGP (Fsystem_name ()) 593 if (STRINGP (Vsystem_name)
516 && strcmp (owner->host, SSDATA (Fsystem_name ())) == 0) 594 && dot - (at + 1) == SBYTES (Vsystem_name)
595 && memcmp (at + 1, SSDATA (Vsystem_name), SBYTES (Vsystem_name)) == 0)
517 { 596 {
518 if (owner->pid == getpid ()) 597 if (pid == getpid ())
519 ret = 2; /* We own it. */ 598 ret = 2; /* We own it. */
520 else if (owner->pid > 0 599 else if (0 < pid && pid <= TYPE_MAXIMUM (pid_t)
521 && (kill (owner->pid, 0) >= 0 || errno == EPERM) 600 && (kill (pid, 0) >= 0 || errno == EPERM)
522 && (owner->boot_time == 0 601 && (boot_time == 0
523 || within_one_second (owner->boot_time, get_boot_time ()))) 602 || (boot_time <= TYPE_MAXIMUM (time_t)
603 && within_one_second (boot_time, get_boot_time ()))))
524 ret = 1; /* An existing process on this machine owns it. */ 604 ret = 1; /* An existing process on this machine owns it. */
525 /* The owner process is dead or has a strange pid (<=0), so try to 605 /* The owner process is dead or has a strange pid, so try to
526 zap the lockfile. */ 606 zap the lockfile. */
527 else if (unlink (lfname) < 0)
528 ret = -1;
529 else 607 else
530 ret = 0; 608 return unlink (lfname);
531 } 609 }
532 else 610 else
533 { /* If we wanted to support the check for stale locks on remote machines, 611 { /* 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)
535 ret = 1; 613 ret = 1;
536 } 614 }
537 615
538 /* Avoid garbage. */
539 if (owner == &local_owner || ret <= 0)
540 {
541 FREE_LOCK_INFO (*owner);
542 }
543 return ret; 616 return ret;
544} 617}
545 618
@@ -551,29 +624,25 @@ current_lock_owner (lock_info_type *owner, char *lfname)
551 Return -1 if cannot lock for any other reason. */ 624 Return -1 if cannot lock for any other reason. */
552 625
553static int 626static int
554lock_if_free (lock_info_type *clasher, register char *lfname) 627lock_if_free (lock_info_type *clasher, char *lfname)
555{ 628{
556 while (! lock_file_1 (lfname, 0)) 629 int err;
630 while ((err = lock_file_1 (lfname, 0)) == EEXIST)
557 { 631 {
558 int locker; 632 switch (current_lock_owner (clasher, lfname))
559 633 {
560 if (errno != EEXIST) 634 case 2:
561 return -1; 635 return 0; /* We ourselves locked it. */
562 636 case 1:
563 locker = current_lock_owner (clasher, lfname); 637 return 1; /* Someone else has it. */
564 if (locker == 2) 638 case -1:
565 { 639 return -1; /* current_lock_owner returned strange error. */
566 FREE_LOCK_INFO (*clasher); 640 }
567 return 0; /* We ourselves locked it. */
568 }
569 else if (locker == 1)
570 return 1; /* Someone else has it. */
571 else if (locker == -1)
572 return -1; /* current_lock_owner returned strange error. */
573 641
574 /* We deleted a stale lock; try again to lock the file. */ 642 /* We deleted a stale lock; try again to lock the file. */
575 } 643 }
576 return 0; 644
645 return err ? -1 : 0;
577} 646}
578 647
579/* lock_file locks file FN, 648/* lock_file locks file FN,
@@ -645,17 +714,16 @@ lock_file (Lisp_Object fn)
645 if (0 < lock_if_free (&lock_info, lfname)) 714 if (0 < lock_if_free (&lock_info, lfname))
646 { 715 {
647 /* Someone else has the lock. Consider breaking it. */ 716 /* Someone else has the lock. Consider breaking it. */
648 ptrdiff_t locker_size = (strlen (lock_info.user) + strlen (lock_info.host)
649 + INT_STRLEN_BOUND (printmax_t)
650 + sizeof "@ (pid )");
651 char *locker = SAFE_ALLOCA (locker_size);
652 printmax_t pid = lock_info.pid;
653 Lisp_Object attack; 717 Lisp_Object attack;
654 esprintf (locker, "%s@%s (pid %"pMd")", 718 char *dot = lock_info.dot;
655 lock_info.user, lock_info.host, pid); 719 ptrdiff_t pidlen = lock_info.colon - (dot + 1);
656 FREE_LOCK_INFO (lock_info); 720 static char const replacement[] = " (pid ";
657 721 int replacementlen = sizeof replacement - 1;
658 attack = call2 (intern ("ask-user-about-lock"), fn, build_string (locker)); 722 memmove (dot + replacementlen, dot + 1, pidlen);
723 strcpy (dot + replacementlen + pidlen, ")");
724 memcpy (dot, replacement, replacementlen);
725 attack = call2 (intern ("ask-user-about-lock"), fn,
726 build_string (lock_info.user));
659 /* Take the lock if the user said so. */ 727 /* Take the lock if the user said so. */
660 if (!NILP (attack)) 728 if (!NILP (attack))
661 lock_file_1 (lfname, 1); 729 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. */)
760 else if (owner == 2) 828 else if (owner == 2)
761 ret = Qt; 829 ret = Qt;
762 else 830 else
763 ret = build_string (locker.user); 831 ret = make_string (locker.user, locker.at - locker.user);
764
765 if (owner > 0)
766 FREE_LOCK_INFO (locker);
767 832
768 SAFE_FREE (); 833 SAFE_FREE ();
769 return ret; 834 return ret;
diff --git a/src/w32.c b/src/w32.c
index f42b83af605..5a6cb894f5f 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -3416,7 +3416,13 @@ sys_open (const char * path, int oflag, int mode)
3416} 3416}
3417 3417
3418int 3418int
3419sys_rename (const char * oldname, const char * newname) 3419fchmod (int fd, mode_t mode)
3420{
3421 return 0;
3422}
3423
3424int
3425sys_rename_replace (const char *oldname, const char *newname, BOOL force)
3420{ 3426{
3421 BOOL result; 3427 BOOL result;
3422 char temp[MAX_PATH]; 3428 char temp[MAX_PATH];
@@ -3472,7 +3478,7 @@ sys_rename (const char * oldname, const char * newname)
3472 return -1; 3478 return -1;
3473 } 3479 }
3474 3480
3475 /* Emulate Unix behavior - newname is deleted if it already exists 3481 /* If FORCE, emulate Unix behavior - newname is deleted if it already exists
3476 (at least if it is a file; don't do this for directories). 3482 (at least if it is a file; don't do this for directories).
3477 3483
3478 Since we mustn't do this if we are just changing the case of the 3484 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)
3490 3496
3491 result = rename (temp, newname); 3497 result = rename (temp, newname);
3492 3498
3493 if (result < 0) 3499 if (result < 0 && force)
3494 { 3500 {
3495 DWORD w32err = GetLastError (); 3501 DWORD w32err = GetLastError ();
3496 3502
@@ -3530,6 +3536,12 @@ sys_rename (const char * oldname, const char * newname)
3530} 3536}
3531 3537
3532int 3538int
3539sys_rename (char const *old, char const *new)
3540{
3541 return sys_rename_replace (old, new, TRUE);
3542}
3543
3544int
3533sys_rmdir (const char * path) 3545sys_rmdir (const char * path)
3534{ 3546{
3535 return _rmdir (map_w32_filename (path, NULL)); 3547 return _rmdir (map_w32_filename (path, NULL));
diff --git a/src/w32.h b/src/w32.h
index 6bf165f52ba..17da0778db1 100644
--- a/src/w32.h
+++ b/src/w32.h
@@ -186,6 +186,8 @@ extern BOOL init_winsock (int load_now);
186extern void srandom (int); 186extern void srandom (int);
187extern int random (void); 187extern int random (void);
188 188
189extern int fchmod (int, mode_t);
190extern int sys_rename_replace (char const *, char const *, BOOL);
189extern int sys_pipe (int *); 191extern int sys_pipe (int *);
190 192
191extern void set_process_dir (char *); 193extern void set_process_dir (char *);