aboutsummaryrefslogtreecommitdiffstats
path: root/src/filelock.c
diff options
context:
space:
mode:
authorEli Zaretskii2013-02-25 19:36:03 +0200
committerEli Zaretskii2013-02-25 19:36:03 +0200
commit343a2aefb528ce3c978ba2145705b9e37bfbe02a (patch)
tree4672030eea98dfc9bd077ac58400271d1c812918 /src/filelock.c
parentaec32f66d0db82b562e904dfe7bb6d54796fe773 (diff)
downloademacs-343a2aefb528ce3c978ba2145705b9e37bfbe02a.tar.gz
emacs-343a2aefb528ce3c978ba2145705b9e37bfbe02a.zip
Implement CLASH_DETECTION for MS-Windows.
src/filelock.c [WINDOWSNT]: Include w32.h. (MAKE_LOCK_NAME): Don't use 'lock', it clashes with MS runtime function of that name. Up-case the macro arguments. (IS_LOCK_FILE): New macro. (fill_in_lock_file_name): Use IS_LOCK_FILE instead of S_ISLNK. (create_lock_file): New function, with body extracted from lock_file_1. [WINDOWSNT]: Implement lock files by writing a regular file with the lock information as its contents. (read_lock_data): New function, on Posix platforms just calls emacs_readlinkat. [WINDOWSNT]: Read the lock info from the file. (current_lock_owner): Call read_lock_data instead of calling emacs_readlinkat directly. (lock_file) [WINDOWSNT]: Run the file name through dostounix_filename. src/w32proc.c (sys_kill): Support the case of SIG = 0, in which case just check if the process by that PID exists. src/w32.c (sys_open): Don't reset the _O_CREAT flag if _O_EXCL is also present, as doing so will fail to error out if the file already exists. src/makefile.w32-in ($(BLD)/filelock.$(O)): Depend on src/w32.h. nt/inc/ms-w32.h (BOOT_TIME_FILE): Define. nt/config.nt (CLASH_DETECTION): Define to 1. lisp/emacs-lisp/bytecomp.el (byte-recompile-directory): Reject files that match "\`\.#", to avoid compiling lock files, even if they are readable (as they are on MS-Windows). doc/emacs/files.texi (Interlocking): Don't refer to symlinks as the exclusive means of locking files. etc/NEWS: Mention support for lock files on MS-Windows.
Diffstat (limited to 'src/filelock.c')
-rw-r--r--src/filelock.c113
1 files changed, 97 insertions, 16 deletions
diff --git a/src/filelock.c b/src/filelock.c
index cd2cd2e53a2..4d556de2454 100644
--- a/src/filelock.c
+++ b/src/filelock.c
@@ -43,6 +43,9 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
43#include "buffer.h" 43#include "buffer.h"
44#include "coding.h" 44#include "coding.h"
45#include "systime.h" 45#include "systime.h"
46#ifdef WINDOWSNT
47#include "w32.h" /* for dostounix_filename */
48#endif
46 49
47#ifdef CLASH_DETECTION 50#ifdef CLASH_DETECTION
48 51
@@ -288,13 +291,22 @@ typedef struct
288#define FREE_LOCK_INFO(i) do { xfree ((i).user); xfree ((i).host); } while (0) 291#define FREE_LOCK_INFO(i) do { xfree ((i).user); xfree ((i).host); } while (0)
289 292
290 293
291/* Write the name of the lock file for FN into LFNAME. Length will be 294/* Write the name of the lock file for FNAME into LOCKNAME. Length
292 that of FN plus two more for the leading `.#' plus 1 for the 295 will be that of FN plus two more for the leading `.#' plus 1 for
293 trailing period plus one for the digit after it plus one for the 296 the trailing period plus one for the digit after it plus one for
294 null. */ 297 the null. */
295#define MAKE_LOCK_NAME(lock, file) \ 298#define MAKE_LOCK_NAME(LOCKNAME, FNAME) \
296 (lock = alloca (SBYTES (file) + 2 + 1 + 1 + 1), \ 299 (LOCKNAME = alloca (SBYTES (FNAME) + 2 + 1 + 1 + 1), \
297 fill_in_lock_file_name (lock, (file))) 300 fill_in_lock_file_name (LOCKNAME, (FNAME)))
301
302#ifdef WINDOWSNT
303/* 256 chars for user, 1024 chars for host, 10 digits for each of 2 int's. */
304#define MAX_LFINFO (256 + 1024 + 10 + 10 + 2)
305 /* min size: .@PID */
306#define IS_LOCK_FILE(ST) (MAX_LFINFO >= (ST).st_size && (ST).st_size >= 3)
307#else
308#define IS_LOCK_FILE(ST) S_ISLNK ((ST).st_mode)
309#endif
298 310
299static void 311static void
300fill_in_lock_file_name (register char *lockfile, register Lisp_Object fn) 312fill_in_lock_file_name (register char *lockfile, register Lisp_Object fn)
@@ -318,7 +330,7 @@ fill_in_lock_file_name (register char *lockfile, register Lisp_Object fn)
318 330
319 p = lockfile + length + 2; 331 p = lockfile + length + 2;
320 332
321 while (lstat (lockfile, &st) == 0 && !S_ISLNK (st.st_mode)) 333 while (lstat (lockfile, &st) == 0 && !IS_LOCK_FILE (st))
322 { 334 {
323 if (count > 9) 335 if (count > 9)
324 { 336 {
@@ -329,6 +341,49 @@ fill_in_lock_file_name (register char *lockfile, register Lisp_Object fn)
329 } 341 }
330} 342}
331 343
344static int
345create_lock_file (char *lfname, char *lock_info_str, bool force)
346{
347 int err;
348
349#ifdef WINDOWSNT
350 /* Symlinks are supported only by latest versions of Windows, and
351 creating them is a privileged operation that often triggers UAC
352 elevation prompts. Therefore, instead of using symlinks, we
353 create a regular file with the lock info written as its
354 contents. */
355 {
356 int fd = emacs_open (lfname, O_WRONLY | O_BINARY | O_CREAT | O_EXCL,
357 S_IREAD | S_IWRITE);
358
359 if (fd < 0 && errno == EEXIST && force)
360 fd = emacs_open (lfname, O_WRONLY | O_BINARY | O_TRUNC,
361 S_IREAD | S_IWRITE);
362 if (fd >= 0)
363 {
364 ssize_t lock_info_len = strlen (lock_info_str);
365
366 err = 0;
367 if (emacs_write (fd, lock_info_str, lock_info_len) != lock_info_len)
368 err = -1;
369 if (emacs_close (fd))
370 err = -1;
371 }
372 else
373 err = -1;
374 }
375#else
376 err = symlink (lock_info_str, lfname);
377 if (errno == EEXIST && force)
378 {
379 unlink (lfname);
380 err = symlink (lock_info_str, lfname);
381 }
382#endif
383
384 return err;
385}
386
332/* Lock the lock file named LFNAME. 387/* Lock the lock file named LFNAME.
333 If FORCE, do so even if it is already locked. 388 If FORCE, do so even if it is already locked.
334 Return true if successful. */ 389 Return true if successful. */
@@ -355,13 +410,7 @@ lock_file_1 (char *lfname, bool force)
355 410
356 esprintf (lock_info_str, boot ? "%s@%s.%"pMd":%"pMd : "%s@%s.%"pMd, 411 esprintf (lock_info_str, boot ? "%s@%s.%"pMd":%"pMd : "%s@%s.%"pMd,
357 user_name, host_name, pid, boot); 412 user_name, host_name, pid, boot);
358 413 err = create_lock_file (lfname, lock_info_str, force);
359 err = symlink (lock_info_str, lfname);
360 if (errno == EEXIST && force)
361 {
362 unlink (lfname);
363 err = symlink (lock_info_str, lfname);
364 }
365 414
366 symlink_errno = errno; 415 symlink_errno = errno;
367 SAFE_FREE (); 416 SAFE_FREE ();
@@ -377,6 +426,32 @@ within_one_second (time_t a, time_t b)
377 return (a - b >= -1 && a - b <= 1); 426 return (a - b >= -1 && a - b <= 1);
378} 427}
379 428
429static Lisp_Object
430read_lock_data (char *lfname)
431{
432#ifndef WINDOWSNT
433 return emacs_readlinkat (AT_FDCWD, lfname);
434#else
435 int fd = emacs_open (lfname, O_RDONLY | O_BINARY, S_IREAD);
436 ssize_t nbytes;
437 char lfinfo[MAX_LFINFO + 1];
438
439 if (fd < 0)
440 return Qnil;
441
442 nbytes = emacs_read (fd, lfinfo, MAX_LFINFO);
443 emacs_close (fd);
444
445 if (nbytes > 0)
446 {
447 lfinfo[nbytes] = '\0';
448 return build_string (lfinfo);
449 }
450 else
451 return Qnil;
452#endif
453}
454
380/* Return 0 if nobody owns the lock file LFNAME or the lock is obsolete, 455/* Return 0 if nobody owns the lock file LFNAME or the lock is obsolete,
381 1 if another process owns it (and set OWNER (if non-null) to info), 456 1 if another process owns it (and set OWNER (if non-null) to info),
382 2 if the current process owns it, 457 2 if the current process owns it,
@@ -390,7 +465,7 @@ current_lock_owner (lock_info_type *owner, char *lfname)
390 lock_info_type local_owner; 465 lock_info_type local_owner;
391 intmax_t n; 466 intmax_t n;
392 char *at, *dot, *colon; 467 char *at, *dot, *colon;
393 Lisp_Object lfinfo_object = emacs_readlinkat (AT_FDCWD, lfname); 468 Lisp_Object lfinfo_object = read_lock_data (lfname);
394 char *lfinfo; 469 char *lfinfo;
395 struct gcpro gcpro1; 470 struct gcpro gcpro1;
396 471
@@ -552,6 +627,12 @@ lock_file (Lisp_Object fn)
552 orig_fn = fn; 627 orig_fn = fn;
553 GCPRO1 (fn); 628 GCPRO1 (fn);
554 fn = Fexpand_file_name (fn, Qnil); 629 fn = Fexpand_file_name (fn, Qnil);
630#ifdef WINDOWSNT
631 /* Ensure we have only '/' separators, to avoid problems with
632 looking (inside fill_in_lock_file_name) for backslashes in file
633 names encoded by some DBCS codepage. */
634 dostounix_filename (SSDATA (fn), 1);
635#endif
555 encoded_fn = ENCODE_FILE (fn); 636 encoded_fn = ENCODE_FILE (fn);
556 637
557 /* Create the name of the lock-file for file fn */ 638 /* Create the name of the lock-file for file fn */