diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 28 | ||||
| -rw-r--r-- | src/filelock.c | 113 | ||||
| -rw-r--r-- | src/makefile.w32-in | 1 | ||||
| -rw-r--r-- | src/w32.c | 11 | ||||
| -rw-r--r-- | src/w32proc.c | 32 |
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 @@ | |||
| 1 | 2013-02-25 Eli Zaretskii <eliz@gnu.org> | 1 | 2013-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 | ||
| 299 | static void | 311 | static void |
| 300 | fill_in_lock_file_name (register char *lockfile, register Lisp_Object fn) | 312 | fill_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 | ||
| 344 | static int | ||
| 345 | create_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 | ||
| 429 | static Lisp_Object | ||
| 430 | read_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 \ |
| @@ -3402,10 +3402,13 @@ int | |||
| 3402 | sys_open (const char * path, int oflag, int mode) | 3402 | sys_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 | { |