aboutsummaryrefslogtreecommitdiffstats
path: root/src
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
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')
-rw-r--r--src/ChangeLog28
-rw-r--r--src/filelock.c113
-rw-r--r--src/makefile.w32-in1
-rw-r--r--src/w32.c11
-rw-r--r--src/w32proc.c32
5 files changed, 164 insertions, 21 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index dc9b97c3c03..135d4d48b41 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,5 +1,33 @@
12013-02-25 Eli Zaretskii <eliz@gnu.org> 12013-02-25 Eli Zaretskii <eliz@gnu.org>
2 2
3 Implement CLASH_DETECTION for MS-Windows.
4
5 * filelock.c [WINDOWSNT]: Include w32.h.
6 (MAKE_LOCK_NAME): Don't use 'lock', it clashes with MS runtime
7 function of that name. Up-case the macro arguments.
8 (IS_LOCK_FILE): New macro.
9 (fill_in_lock_file_name): Use IS_LOCK_FILE instead of S_ISLNK.
10 (create_lock_file): New function, with body extracted from
11 lock_file_1.
12 [WINDOWSNT]: Implement lock files by writing a regular file with
13 the lock information as its contents.
14 (read_lock_data): New function, on Posix platforms just calls
15 emacs_readlinkat.
16 [WINDOWSNT]: Read the lock info from the file.
17 (current_lock_owner): Call read_lock_data instead of calling
18 emacs_readlinkat directly.
19 (lock_file) [WINDOWSNT]: Run the file name through
20 dostounix_filename.
21
22 * w32proc.c (sys_kill): Support the case of SIG = 0, in which case
23 just check if the process by that PID exists.
24
25 * w32.c (sys_open): Don't reset the _O_CREAT flag if _O_EXCL is
26 also present, as doing so will fail to error out if the file
27 already exists.
28
29 * makefile.w32-in ($(BLD)/filelock.$(O)): Depend on src/w32.h.
30
3 * textprop.c (Fadd_text_properties, Fremove_text_properties) 31 * textprop.c (Fadd_text_properties, Fremove_text_properties)
4 (Fremove_list_of_text_properties): Skip all of the intervals in 32 (Fremove_list_of_text_properties): Skip all of the intervals in
5 the region between START and END that already have resp. don't 33 the region between START and END that already have resp. don't
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 */
diff --git a/src/makefile.w32-in b/src/makefile.w32-in
index d60331198db..93f12900dde 100644
--- a/src/makefile.w32-in
+++ b/src/makefile.w32-in
@@ -864,6 +864,7 @@ $(BLD)/fileio.$(O) : \
864 864
865$(BLD)/filelock.$(O) : \ 865$(BLD)/filelock.$(O) : \
866 $(SRC)/filelock.c \ 866 $(SRC)/filelock.c \
867 $(SRC)/w32.h \
867 $(NT_INC)/pwd.h \ 868 $(NT_INC)/pwd.h \
868 $(NT_INC)/sys/file.h \ 869 $(NT_INC)/sys/file.h \
869 $(NT_INC)/sys/stat.h \ 870 $(NT_INC)/sys/stat.h \
diff --git a/src/w32.c b/src/w32.c
index 5011642adf2..aff9771e4bb 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -3402,10 +3402,13 @@ int
3402sys_open (const char * path, int oflag, int mode) 3402sys_open (const char * path, int oflag, int mode)
3403{ 3403{
3404 const char* mpath = map_w32_filename (path, NULL); 3404 const char* mpath = map_w32_filename (path, NULL);
3405 /* Try to open file without _O_CREAT, to be able to write to hidden 3405 int res = -1;
3406 and system files. Force all file handles to be 3406
3407 non-inheritable. */ 3407 /* If possible, try to open file without _O_CREAT, to be able to
3408 int res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode); 3408 write to existing hidden and system files. Force all file
3409 handles to be non-inheritable. */
3410 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
3411 res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
3409 if (res < 0) 3412 if (res < 0)
3410 res = _open (mpath, oflag | _O_NOINHERIT, mode); 3413 res = _open (mpath, oflag | _O_NOINHERIT, mode);
3411 if (res >= 0 && res < MAXDESC) 3414 if (res >= 0 && res < MAXDESC)
diff --git a/src/w32proc.c b/src/w32proc.c
index 961791a40ed..84589388cd7 100644
--- a/src/w32proc.c
+++ b/src/w32proc.c
@@ -2263,12 +2263,42 @@ sys_kill (pid_t pid, int sig)
2263 pid = -pid; 2263 pid = -pid;
2264 2264
2265 /* Only handle signals that will result in the process dying */ 2265 /* Only handle signals that will result in the process dying */
2266 if (sig != SIGINT && sig != SIGKILL && sig != SIGQUIT && sig != SIGHUP) 2266 if (sig != 0
2267 && sig != SIGINT && sig != SIGKILL && sig != SIGQUIT && sig != SIGHUP)
2267 { 2268 {
2268 errno = EINVAL; 2269 errno = EINVAL;
2269 return -1; 2270 return -1;
2270 } 2271 }
2271 2272
2273 if (sig == 0)
2274 {
2275 /* It will take _some_ time before PID 4 or less on Windows will
2276 be Emacs... */
2277 if (pid <= 4)
2278 {
2279 errno = EPERM;
2280 return -1;
2281 }
2282 proc_hand = OpenProcess (PROCESS_QUERY_INFORMATION, 0, pid);
2283 if (proc_hand == NULL)
2284 {
2285 DWORD err = GetLastError ();
2286
2287 switch (err)
2288 {
2289 case ERROR_ACCESS_DENIED: /* existing process, but access denied */
2290 errno = EPERM;
2291 return -1;
2292 case ERROR_INVALID_PARAMETER: /* process PID does not exist */
2293 errno = ESRCH;
2294 return -1;
2295 }
2296 }
2297 else
2298 CloseHandle (proc_hand);
2299 return 0;
2300 }
2301
2272 cp = find_child_pid (pid); 2302 cp = find_child_pid (pid);
2273 if (cp == NULL) 2303 if (cp == NULL)
2274 { 2304 {