diff options
| author | Eli Zaretskii | 2013-03-28 20:13:59 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2013-03-28 20:13:59 +0200 |
| commit | d76bf86f438d4f5f9fe493ab76f02ffc78f3ae2e (patch) | |
| tree | 04fa8bc7bd2058a316a7ee30f8741d25bfd0b060 /src/filelock.c | |
| parent | 2ef26ceb192c7683754cf0b4aa3087f501254332 (diff) | |
| parent | e74aeda863cd6896e06e92586f87b45d63d67d15 (diff) | |
| download | emacs-d76bf86f438d4f5f9fe493ab76f02ffc78f3ae2e.tar.gz emacs-d76bf86f438d4f5f9fe493ab76f02ffc78f3ae2e.zip | |
Merge from trunk and resolve conflicts.
Diffstat (limited to 'src/filelock.c')
| -rw-r--r-- | src/filelock.c | 489 |
1 files changed, 316 insertions, 173 deletions
diff --git a/src/filelock.c b/src/filelock.c index 17f3f253249..f17d3182eab 100644 --- a/src/filelock.c +++ b/src/filelock.c | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* Lock files for editing. | 1 | /* Lock files for editing. |
| 2 | Copyright (C) 1985-1987, 1993-1994, 1996, 1998-2012 | 2 | Copyright (C) 1985-1987, 1993-1994, 1996, 1998-2013 Free Software |
| 3 | Free Software Foundation, Inc. | 3 | Foundation, Inc. |
| 4 | 4 | ||
| 5 | This file is part of GNU Emacs. | 5 | This file is part of GNU Emacs. |
| 6 | 6 | ||
| @@ -38,11 +38,17 @@ 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" |
| 44 | #include "coding.h" | 46 | #include "coding.h" |
| 45 | #include "systime.h" | 47 | #include "systime.h" |
| 48 | #ifdef WINDOWSNT | ||
| 49 | #include <share.h> | ||
| 50 | #include "w32.h" /* for dostounix_filename */ | ||
| 51 | #endif | ||
| 46 | 52 | ||
| 47 | #ifdef CLASH_DETECTION | 53 | #ifdef CLASH_DETECTION |
| 48 | 54 | ||
| @@ -60,7 +66,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 60 | #define WTMP_FILE "/var/log/wtmp" | 66 | #define WTMP_FILE "/var/log/wtmp" |
| 61 | #endif | 67 | #endif |
| 62 | 68 | ||
| 63 | /* The strategy: to lock a file FN, create a symlink .#FN in FN's | 69 | /* Normally use a symbolic link to represent a lock. |
| 70 | The strategy: to lock a file FN, create a symlink .#FN in FN's | ||
| 64 | directory, with link data `user@host.pid'. This avoids a single | 71 | directory, with link data `user@host.pid'. This avoids a single |
| 65 | mount (== failure) point for lock files. | 72 | mount (== failure) point for lock files. |
| 66 | 73 | ||
| @@ -93,7 +100,23 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 93 | has contributed this implementation for Emacs), and was designed by | 100 | has contributed this implementation for Emacs), and was designed by |
| 94 | Ethan Jacobson, Kimbo Mundy, and others. | 101 | Ethan Jacobson, Kimbo Mundy, and others. |
| 95 | 102 | ||
| 96 | --karl@cs.umb.edu/karl@hq.ileaf.com. */ | 103 | --karl@cs.umb.edu/karl@hq.ileaf.com. |
| 104 | |||
| 105 | On some file systems, notably those of MS-Windows, symbolic links | ||
| 106 | do not work well, so instead of a symlink .#FN -> 'user@host.pid', | ||
| 107 | the lock is a regular file .#FN with contents 'user@host.pid'. To | ||
| 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. */ | ||
| 97 | 120 | ||
| 98 | 121 | ||
| 99 | /* Return the time of the last system boot. */ | 122 | /* Return the time of the last system boot. */ |
| @@ -274,72 +297,175 @@ get_boot_time_1 (const char *filename, bool newest) | |||
| 274 | } | 297 | } |
| 275 | #endif /* BOOT_TIME */ | 298 | #endif /* BOOT_TIME */ |
| 276 | 299 | ||
| 300 | /* An arbitrary limit on lock contents length. 8 K should be plenty | ||
| 301 | big enough in practice. */ | ||
| 302 | enum { MAX_LFINFO = 8 * 1024 }; | ||
| 303 | |||
| 277 | /* Here is the structure that stores information about a lock. */ | 304 | /* Here is the structure that stores information about a lock. */ |
| 278 | 305 | ||
| 279 | typedef struct | 306 | typedef struct |
| 280 | { | 307 | { |
| 281 | char *user; | 308 | /* Location of '@', '.', ':' in USER. If there's no colon, COLON |
| 282 | char *host; | 309 | points to the end of USER. */ |
| 283 | pid_t pid; | 310 | char *at, *dot, *colon; |
| 284 | time_t boot_time; | 311 | |
| 312 | /* Lock file contents USER@HOST.PID with an optional :BOOT_TIME | ||
| 313 | appended. This memory is used as a lock file contents buffer, so | ||
| 314 | it needs room for MAX_LFINFO + 1 bytes. A string " (pid NNNN)" | ||
| 315 | may be appended to the USER@HOST while generating a diagnostic, | ||
| 316 | so make room for its extra bytes (as opposed to ".NNNN") too. */ | ||
| 317 | char user[MAX_LFINFO + 1 + sizeof " (pid )" - sizeof "."]; | ||
| 285 | } lock_info_type; | 318 | } lock_info_type; |
| 286 | 319 | ||
| 287 | /* Free the two dynamically-allocated pieces in PTR. */ | 320 | /* Write the name of the lock file for FNAME into LOCKNAME. Length |
| 288 | #define FREE_LOCK_INFO(i) do { xfree ((i).user); xfree ((i).host); } while (0) | 321 | will be that of FNAME plus two more for the leading ".#", plus one |
| 322 | for the null. */ | ||
| 323 | #define MAKE_LOCK_NAME(lockname, fname) \ | ||
| 324 | (lockname = SAFE_ALLOCA (SBYTES (fname) + 2 + 1), \ | ||
| 325 | fill_in_lock_file_name (lockname, fname)) | ||
| 289 | 326 | ||
| 327 | static void | ||
| 328 | fill_in_lock_file_name (char *lockfile, Lisp_Object fn) | ||
| 329 | { | ||
| 330 | char *last_slash = memrchr (SSDATA (fn), '/', SBYTES (fn)); | ||
| 331 | char *base = last_slash + 1; | ||
| 332 | ptrdiff_t dirlen = base - SSDATA (fn); | ||
| 333 | memcpy (lockfile, SSDATA (fn), dirlen); | ||
| 334 | lockfile[dirlen] = '.'; | ||
| 335 | lockfile[dirlen + 1] = '#'; | ||
| 336 | strcpy (lockfile + dirlen + 2, base); | ||
| 337 | } | ||
| 290 | 338 | ||
| 291 | /* Write the name of the lock file for FN into LFNAME. Length will be | 339 | /* For some reason Linux kernels return EPERM on file systems that do |
| 292 | that of FN plus two more for the leading `.#' plus 1 for the | 340 | not support hard or symbolic links. This symbol documents the quirk. |
| 293 | trailing period plus one for the digit after it plus one for the | 341 | There is no way to tell whether a symlink call fails due to |
| 294 | null. */ | 342 | permissions issues or because links are not supported, but luckily |
| 295 | #define MAKE_LOCK_NAME(lock, file) \ | 343 | the lock file code should work either way. */ |
| 296 | (lock = alloca (SBYTES (file) + 2 + 1 + 1 + 1), \ | 344 | enum { LINKS_MIGHT_NOT_WORK = EPERM }; |
| 297 | fill_in_lock_file_name (lock, (file))) | ||
| 298 | 345 | ||
| 299 | static void | 346 | /* Rename OLD to NEW. If FORCE, replace any existing NEW. |
| 300 | fill_in_lock_file_name (register char *lockfile, register Lisp_Object fn) | 347 | It is OK if there are temporarily two hard links to OLD. |
| 348 | Return 0 if successful, -1 (setting errno) otherwise. */ | ||
| 349 | static int | ||
| 350 | rename_lock_file (char const *old, char const *new, bool force) | ||
| 301 | { | 351 | { |
| 302 | ptrdiff_t length = SBYTES (fn); | 352 | #ifdef WINDOWSNT |
| 303 | register char *p; | 353 | return sys_rename_replace (old, new, force); |
| 304 | struct stat st; | 354 | #else |
| 305 | int count = 0; | 355 | if (! force) |
| 356 | { | ||
| 357 | struct stat st; | ||
| 306 | 358 | ||
| 307 | strcpy (lockfile, SSDATA (fn)); | 359 | if (link (old, new) == 0) |
| 360 | return unlink (old) == 0 || errno == ENOENT ? 0 : -1; | ||
| 361 | if (errno != ENOSYS && errno != LINKS_MIGHT_NOT_WORK) | ||
| 362 | return -1; | ||
| 308 | 363 | ||
| 309 | /* Shift the nondirectory part of the file name (including the null) | 364 | /* 'link' does not work on this file system. This can occur on |
| 310 | right two characters. Here is one of the places where we'd have to | 365 | a GNU/Linux host mounting a FAT32 file system. Fall back on |
| 311 | do something to support 14-character-max file names. */ | 366 | 'rename' after checking that NEW does not exist. There is a |
| 312 | for (p = lockfile + length; p != lockfile && *p != '/'; p--) | 367 | potential race condition since some other process may create |
| 313 | p[2] = *p; | 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 | } | ||
| 314 | 378 | ||
| 315 | /* Insert the `.#'. */ | 379 | return rename (old, new); |
| 316 | p[1] = '.'; | 380 | #endif |
| 317 | p[2] = '#'; | 381 | } |
| 318 | 382 | ||
| 319 | p = p + length + 2; | 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. */ | ||
| 320 | 386 | ||
| 321 | while (lstat (lockfile, &st) == 0 && !S_ISLNK (st.st_mode)) | 387 | static int |
| 388 | create_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; | ||
| 396 | #else | ||
| 397 | int err = symlink (lock_info_str, lfname) == 0 ? 0 : errno; | ||
| 398 | #endif | ||
| 399 | |||
| 400 | if (err == EEXIST && force) | ||
| 401 | { | ||
| 402 | unlink (lfname); | ||
| 403 | err = symlink (lock_info_str, lfname) == 0 ? 0 : errno; | ||
| 404 | } | ||
| 405 | |||
| 406 | if (err == ENOSYS || err == LINKS_MIGHT_NOT_WORK || err == ENAMETOOLONG) | ||
| 322 | { | 407 | { |
| 323 | if (count > 9) | 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; | ||
| 429 | #endif | ||
| 430 | |||
| 431 | if (fd < 0) | ||
| 432 | err = errno; | ||
| 433 | else | ||
| 324 | { | 434 | { |
| 325 | *p = '\0'; | 435 | ptrdiff_t lock_info_len = strlen (lock_info_str); |
| 326 | return; | 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 | else | ||
| 441 | while (fsync (fd) != 0) | ||
| 442 | if (errno != EINTR) | ||
| 443 | { | ||
| 444 | if (errno != EINVAL) | ||
| 445 | err = errno; | ||
| 446 | break; | ||
| 447 | } | ||
| 448 | if (emacs_close (fd) != 0) | ||
| 449 | err = errno; | ||
| 450 | if (!err && rename_lock_file (nonce, lfname, force) != 0) | ||
| 451 | err = errno; | ||
| 452 | if (err) | ||
| 453 | unlink (nonce); | ||
| 327 | } | 454 | } |
| 328 | sprintf (p, ".%d", count++); | 455 | |
| 456 | SAFE_FREE (); | ||
| 329 | } | 457 | } |
| 458 | |||
| 459 | return err; | ||
| 330 | } | 460 | } |
| 331 | 461 | ||
| 332 | /* Lock the lock file named LFNAME. | 462 | /* Lock the lock file named LFNAME. |
| 333 | If FORCE, do so even if it is already locked. | 463 | If FORCE, do so even if it is already locked. |
| 334 | Return true if successful. */ | 464 | Return 0 if successful, an error number on failure. */ |
| 335 | 465 | ||
| 336 | static bool | 466 | static int |
| 337 | lock_file_1 (char *lfname, bool force) | 467 | lock_file_1 (char *lfname, bool force) |
| 338 | { | 468 | { |
| 339 | int err; | ||
| 340 | int symlink_errno; | ||
| 341 | USE_SAFE_ALLOCA; | ||
| 342 | |||
| 343 | /* Call this first because it can GC. */ | 469 | /* Call this first because it can GC. */ |
| 344 | printmax_t boot = get_boot_time (); | 470 | printmax_t boot = get_boot_time (); |
| 345 | 471 | ||
| @@ -347,26 +473,16 @@ lock_file_1 (char *lfname, bool force) | |||
| 347 | char const *user_name = STRINGP (luser_name) ? SSDATA (luser_name) : ""; | 473 | char const *user_name = STRINGP (luser_name) ? SSDATA (luser_name) : ""; |
| 348 | Lisp_Object lhost_name = Fsystem_name (); | 474 | Lisp_Object lhost_name = Fsystem_name (); |
| 349 | char const *host_name = STRINGP (lhost_name) ? SSDATA (lhost_name) : ""; | 475 | char const *host_name = STRINGP (lhost_name) ? SSDATA (lhost_name) : ""; |
| 350 | ptrdiff_t lock_info_size = (strlen (user_name) + strlen (host_name) | 476 | char lock_info_str[MAX_LFINFO + 1]; |
| 351 | + 2 * INT_STRLEN_BOUND (printmax_t) | ||
| 352 | + sizeof "@.:"); | ||
| 353 | char *lock_info_str = SAFE_ALLOCA (lock_info_size); | ||
| 354 | printmax_t pid = getpid (); | 477 | printmax_t pid = getpid (); |
| 355 | 478 | ||
| 356 | esprintf (lock_info_str, boot ? "%s@%s.%"pMd":%"pMd : "%s@%s.%"pMd, | 479 | if (sizeof lock_info_str |
| 357 | user_name, host_name, pid, boot); | 480 | <= snprintf (lock_info_str, sizeof lock_info_str, |
| 358 | 481 | boot ? "%s@%s.%"pMd":%"pMd : "%s@%s.%"pMd, | |
| 359 | err = symlink (lock_info_str, lfname); | 482 | user_name, host_name, pid, boot)) |
| 360 | if (errno == EEXIST && force) | 483 | return ENAMETOOLONG; |
| 361 | { | ||
| 362 | unlink (lfname); | ||
| 363 | err = symlink (lock_info_str, lfname); | ||
| 364 | } | ||
| 365 | 484 | ||
| 366 | symlink_errno = errno; | 485 | return create_lock_file (lfname, lock_info_str, force); |
| 367 | SAFE_FREE (); | ||
| 368 | errno = symlink_errno; | ||
| 369 | return err == 0; | ||
| 370 | } | 486 | } |
| 371 | 487 | ||
| 372 | /* Return true if times A and B are no more than one second apart. */ | 488 | /* Return true if times A and B are no more than one second apart. */ |
| @@ -377,6 +493,46 @@ within_one_second (time_t a, time_t b) | |||
| 377 | return (a - b >= -1 && a - b <= 1); | 493 | return (a - b >= -1 && a - b <= 1); |
| 378 | } | 494 | } |
| 379 | 495 | ||
| 496 | /* On systems lacking ELOOP, test for an errno value that shouldn't occur. */ | ||
| 497 | #ifndef ELOOP | ||
| 498 | # define ELOOP (-1) | ||
| 499 | #endif | ||
| 500 | |||
| 501 | /* Read the data for the lock file LFNAME into LFINFO. Read at most | ||
| 502 | MAX_LFINFO + 1 bytes. Return the number of bytes read, or -1 | ||
| 503 | (setting errno) on error. */ | ||
| 504 | |||
| 505 | static ptrdiff_t | ||
| 506 | read_lock_data (char *lfname, char lfinfo[MAX_LFINFO + 1]) | ||
| 507 | { | ||
| 508 | ptrdiff_t nbytes; | ||
| 509 | |||
| 510 | while ((nbytes = readlinkat (AT_FDCWD, lfname, lfinfo, MAX_LFINFO + 1)) < 0 | ||
| 511 | && errno == EINVAL) | ||
| 512 | { | ||
| 513 | int fd = emacs_open (lfname, O_RDONLY | O_BINARY | O_NOFOLLOW, 0); | ||
| 514 | if (0 <= fd) | ||
| 515 | { | ||
| 516 | ptrdiff_t read_bytes = emacs_read (fd, lfinfo, MAX_LFINFO + 1); | ||
| 517 | int read_errno = errno; | ||
| 518 | if (emacs_close (fd) != 0) | ||
| 519 | return -1; | ||
| 520 | errno = read_errno; | ||
| 521 | return read_bytes; | ||
| 522 | } | ||
| 523 | |||
| 524 | if (errno != ELOOP) | ||
| 525 | return -1; | ||
| 526 | |||
| 527 | /* readlinkat saw a non-symlink, but emacs_open saw a symlink. | ||
| 528 | The former must have been removed and replaced by the latter. | ||
| 529 | Try again. */ | ||
| 530 | QUIT; | ||
| 531 | } | ||
| 532 | |||
| 533 | return nbytes; | ||
| 534 | } | ||
| 535 | |||
| 380 | /* Return 0 if nobody owns the lock file LFNAME or the lock is obsolete, | 536 | /* 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), | 537 | 1 if another process owns it (and set OWNER (if non-null) to info), |
| 382 | 2 if the current process owns it, | 538 | 2 if the current process owns it, |
| @@ -386,85 +542,78 @@ static int | |||
| 386 | current_lock_owner (lock_info_type *owner, char *lfname) | 542 | current_lock_owner (lock_info_type *owner, char *lfname) |
| 387 | { | 543 | { |
| 388 | int ret; | 544 | int ret; |
| 389 | ptrdiff_t len; | ||
| 390 | lock_info_type local_owner; | 545 | lock_info_type local_owner; |
| 391 | intmax_t n; | 546 | ptrdiff_t lfinfolen; |
| 392 | char *at, *dot, *colon; | 547 | intmax_t pid, boot_time; |
| 393 | char readlink_buf[READLINK_BUFSIZE]; | 548 | char *at, *dot, *lfinfo_end; |
| 394 | char *lfinfo = emacs_readlink (lfname, readlink_buf); | ||
| 395 | |||
| 396 | /* If nonexistent lock file, all is well; otherwise, got strange error. */ | ||
| 397 | if (!lfinfo) | ||
| 398 | return errno == ENOENT ? 0 : -1; | ||
| 399 | 549 | ||
| 400 | /* Even if the caller doesn't want the owner info, we still have to | 550 | /* Even if the caller doesn't want the owner info, we still have to |
| 401 | read it to determine return value. */ | 551 | read it to determine return value. */ |
| 402 | if (!owner) | 552 | if (!owner) |
| 403 | owner = &local_owner; | 553 | owner = &local_owner; |
| 404 | 554 | ||
| 555 | /* If nonexistent lock file, all is well; otherwise, got strange error. */ | ||
| 556 | lfinfolen = read_lock_data (lfname, owner->user); | ||
| 557 | if (lfinfolen < 0) | ||
| 558 | return errno == ENOENT ? 0 : -1; | ||
| 559 | if (MAX_LFINFO < lfinfolen) | ||
| 560 | return -1; | ||
| 561 | owner->user[lfinfolen] = 0; | ||
| 562 | |||
| 405 | /* Parse USER@HOST.PID:BOOT_TIME. If can't parse, return -1. */ | 563 | /* Parse USER@HOST.PID:BOOT_TIME. If can't parse, return -1. */ |
| 406 | /* The USER is everything before the last @. */ | 564 | /* The USER is everything before the last @. */ |
| 407 | at = strrchr (lfinfo, '@'); | 565 | owner->at = at = memrchr (owner->user, '@', lfinfolen); |
| 408 | dot = strrchr (lfinfo, '.'); | 566 | if (!at) |
| 409 | if (!at || !dot) | 567 | return -1; |
| 410 | { | 568 | owner->dot = dot = strrchr (at, '.'); |
| 411 | if (lfinfo != readlink_buf) | 569 | if (!dot) |
| 412 | xfree (lfinfo); | 570 | return -1; |
| 413 | return -1; | ||
| 414 | } | ||
| 415 | len = at - lfinfo; | ||
| 416 | owner->user = xmalloc (len + 1); | ||
| 417 | memcpy (owner->user, lfinfo, len); | ||
| 418 | owner->user[len] = 0; | ||
| 419 | 571 | ||
| 420 | /* The PID is everything from the last `.' to the `:'. */ | 572 | /* The PID is everything from the last `.' to the `:'. */ |
| 573 | if (! c_isdigit (dot[1])) | ||
| 574 | return -1; | ||
| 421 | errno = 0; | 575 | errno = 0; |
| 422 | n = strtoimax (dot + 1, NULL, 10); | 576 | pid = strtoimax (dot + 1, &owner->colon, 10); |
| 423 | owner->pid = | 577 | if (errno == ERANGE) |
| 424 | ((0 <= n && n <= TYPE_MAXIMUM (pid_t) | 578 | pid = -1; |
| 425 | && (TYPE_MAXIMUM (pid_t) < INTMAX_MAX || errno != ERANGE)) | ||
| 426 | ? n : 0); | ||
| 427 | 579 | ||
| 428 | colon = strchr (dot + 1, ':'); | ||
| 429 | /* After the `:', if there is one, comes the boot time. */ | 580 | /* After the `:', if there is one, comes the boot time. */ |
| 430 | n = 0; | 581 | switch (owner->colon[0]) |
| 431 | if (colon) | ||
| 432 | { | 582 | { |
| 433 | errno = 0; | 583 | case 0: |
| 434 | n = strtoimax (colon + 1, NULL, 10); | 584 | boot_time = 0; |
| 435 | } | 585 | lfinfo_end = owner->colon; |
| 436 | owner->boot_time = | 586 | break; |
| 437 | ((0 <= n && n <= TYPE_MAXIMUM (time_t) | ||
| 438 | && (TYPE_MAXIMUM (time_t) < INTMAX_MAX || errno != ERANGE)) | ||
| 439 | ? n : 0); | ||
| 440 | 587 | ||
| 441 | /* The host is everything in between. */ | 588 | case ':': |
| 442 | len = dot - at - 1; | 589 | if (! c_isdigit (owner->colon[1])) |
| 443 | owner->host = xmalloc (len + 1); | 590 | return -1; |
| 444 | memcpy (owner->host, at + 1, len); | 591 | boot_time = strtoimax (owner->colon + 1, &lfinfo_end, 10); |
| 445 | owner->host[len] = 0; | 592 | break; |
| 446 | 593 | ||
| 447 | /* We're done looking at the link info. */ | 594 | default: |
| 448 | if (lfinfo != readlink_buf) | 595 | return -1; |
| 449 | xfree (lfinfo); | 596 | } |
| 597 | if (lfinfo_end != owner->user + lfinfolen) | ||
| 598 | return -1; | ||
| 450 | 599 | ||
| 451 | /* On current host? */ | 600 | /* On current host? */ |
| 452 | if (STRINGP (Fsystem_name ()) | 601 | if (STRINGP (Vsystem_name) |
| 453 | && strcmp (owner->host, SSDATA (Fsystem_name ())) == 0) | 602 | && dot - (at + 1) == SBYTES (Vsystem_name) |
| 603 | && memcmp (at + 1, SSDATA (Vsystem_name), SBYTES (Vsystem_name)) == 0) | ||
| 454 | { | 604 | { |
| 455 | if (owner->pid == getpid ()) | 605 | if (pid == getpid ()) |
| 456 | ret = 2; /* We own it. */ | 606 | ret = 2; /* We own it. */ |
| 457 | else if (owner->pid > 0 | 607 | else if (0 < pid && pid <= TYPE_MAXIMUM (pid_t) |
| 458 | && (kill (owner->pid, 0) >= 0 || errno == EPERM) | 608 | && (kill (pid, 0) >= 0 || errno == EPERM) |
| 459 | && (owner->boot_time == 0 | 609 | && (boot_time == 0 |
| 460 | || within_one_second (owner->boot_time, get_boot_time ()))) | 610 | || (boot_time <= TYPE_MAXIMUM (time_t) |
| 611 | && within_one_second (boot_time, get_boot_time ())))) | ||
| 461 | ret = 1; /* An existing process on this machine owns it. */ | 612 | ret = 1; /* An existing process on this machine owns it. */ |
| 462 | /* The owner process is dead or has a strange pid (<=0), so try to | 613 | /* The owner process is dead or has a strange pid, so try to |
| 463 | zap the lockfile. */ | 614 | zap the lockfile. */ |
| 464 | else if (unlink (lfname) < 0) | ||
| 465 | ret = -1; | ||
| 466 | else | 615 | else |
| 467 | ret = 0; | 616 | return unlink (lfname); |
| 468 | } | 617 | } |
| 469 | else | 618 | else |
| 470 | { /* If we wanted to support the check for stale locks on remote machines, | 619 | { /* If we wanted to support the check for stale locks on remote machines, |
| @@ -472,11 +621,6 @@ current_lock_owner (lock_info_type *owner, char *lfname) | |||
| 472 | ret = 1; | 621 | ret = 1; |
| 473 | } | 622 | } |
| 474 | 623 | ||
| 475 | /* Avoid garbage. */ | ||
| 476 | if (owner == &local_owner || ret <= 0) | ||
| 477 | { | ||
| 478 | FREE_LOCK_INFO (*owner); | ||
| 479 | } | ||
| 480 | return ret; | 624 | return ret; |
| 481 | } | 625 | } |
| 482 | 626 | ||
| @@ -488,29 +632,25 @@ current_lock_owner (lock_info_type *owner, char *lfname) | |||
| 488 | Return -1 if cannot lock for any other reason. */ | 632 | Return -1 if cannot lock for any other reason. */ |
| 489 | 633 | ||
| 490 | static int | 634 | static int |
| 491 | lock_if_free (lock_info_type *clasher, register char *lfname) | 635 | lock_if_free (lock_info_type *clasher, char *lfname) |
| 492 | { | 636 | { |
| 493 | while (! lock_file_1 (lfname, 0)) | 637 | int err; |
| 638 | while ((err = lock_file_1 (lfname, 0)) == EEXIST) | ||
| 494 | { | 639 | { |
| 495 | int locker; | 640 | switch (current_lock_owner (clasher, lfname)) |
| 496 | 641 | { | |
| 497 | if (errno != EEXIST) | 642 | case 2: |
| 498 | return -1; | 643 | return 0; /* We ourselves locked it. */ |
| 499 | 644 | case 1: | |
| 500 | locker = current_lock_owner (clasher, lfname); | 645 | return 1; /* Someone else has it. */ |
| 501 | if (locker == 2) | 646 | case -1: |
| 502 | { | 647 | return -1; /* current_lock_owner returned strange error. */ |
| 503 | FREE_LOCK_INFO (*clasher); | 648 | } |
| 504 | return 0; /* We ourselves locked it. */ | ||
| 505 | } | ||
| 506 | else if (locker == 1) | ||
| 507 | return 1; /* Someone else has it. */ | ||
| 508 | else if (locker == -1) | ||
| 509 | return -1; /* current_lock_owner returned strange error. */ | ||
| 510 | 649 | ||
| 511 | /* We deleted a stale lock; try again to lock the file. */ | 650 | /* We deleted a stale lock; try again to lock the file. */ |
| 512 | } | 651 | } |
| 513 | return 0; | 652 | |
| 653 | return err ? -1 : 0; | ||
| 514 | } | 654 | } |
| 515 | 655 | ||
| 516 | /* lock_file locks file FN, | 656 | /* lock_file locks file FN, |
| @@ -522,6 +662,7 @@ lock_if_free (lock_info_type *clasher, register char *lfname) | |||
| 522 | decided to go ahead without locking. | 662 | decided to go ahead without locking. |
| 523 | 663 | ||
| 524 | When this returns, either the lock is locked for us, | 664 | When this returns, either the lock is locked for us, |
| 665 | or lock creation failed, | ||
| 525 | or the user has said to go ahead without locking. | 666 | or the user has said to go ahead without locking. |
| 526 | 667 | ||
| 527 | If the file is locked by someone else, this calls | 668 | If the file is locked by someone else, this calls |
| @@ -533,11 +674,9 @@ lock_if_free (lock_info_type *clasher, register char *lfname) | |||
| 533 | void | 674 | void |
| 534 | lock_file (Lisp_Object fn) | 675 | lock_file (Lisp_Object fn) |
| 535 | { | 676 | { |
| 536 | register Lisp_Object attack, orig_fn, encoded_fn; | 677 | Lisp_Object orig_fn, encoded_fn; |
| 537 | register char *lfname, *locker; | 678 | char *lfname; |
| 538 | ptrdiff_t locker_size; | ||
| 539 | lock_info_type lock_info; | 679 | lock_info_type lock_info; |
| 540 | printmax_t pid; | ||
| 541 | struct gcpro gcpro1; | 680 | struct gcpro gcpro1; |
| 542 | USE_SAFE_ALLOCA; | 681 | USE_SAFE_ALLOCA; |
| 543 | 682 | ||
| @@ -554,6 +693,12 @@ lock_file (Lisp_Object fn) | |||
| 554 | orig_fn = fn; | 693 | orig_fn = fn; |
| 555 | GCPRO1 (fn); | 694 | GCPRO1 (fn); |
| 556 | fn = Fexpand_file_name (fn, Qnil); | 695 | fn = Fexpand_file_name (fn, Qnil); |
| 696 | #ifdef WINDOWSNT | ||
| 697 | /* Ensure we have only '/' separators, to avoid problems with | ||
| 698 | looking (inside fill_in_lock_file_name) for backslashes in file | ||
| 699 | names encoded by some DBCS codepage. */ | ||
| 700 | dostounix_filename (SSDATA (fn), 1); | ||
| 701 | #endif | ||
| 557 | encoded_fn = ENCODE_FILE (fn); | 702 | encoded_fn = ENCODE_FILE (fn); |
| 558 | 703 | ||
| 559 | /* Create the name of the lock-file for file fn */ | 704 | /* Create the name of the lock-file for file fn */ |
| @@ -572,38 +717,35 @@ lock_file (Lisp_Object fn) | |||
| 572 | call1 (intern ("ask-user-about-supersession-threat"), fn); | 717 | call1 (intern ("ask-user-about-supersession-threat"), fn); |
| 573 | 718 | ||
| 574 | } | 719 | } |
| 575 | UNGCPRO; | ||
| 576 | 720 | ||
| 577 | /* Try to lock the lock. */ | 721 | /* Try to lock the lock. */ |
| 578 | if (lock_if_free (&lock_info, lfname) <= 0) | 722 | if (0 < lock_if_free (&lock_info, lfname)) |
| 579 | /* Return now if we have locked it, or if lock creation failed */ | ||
| 580 | return; | ||
| 581 | |||
| 582 | /* Else consider breaking the lock */ | ||
| 583 | locker_size = (strlen (lock_info.user) + strlen (lock_info.host) | ||
| 584 | + INT_STRLEN_BOUND (printmax_t) | ||
| 585 | + sizeof "@ (pid )"); | ||
| 586 | locker = SAFE_ALLOCA (locker_size); | ||
| 587 | pid = lock_info.pid; | ||
| 588 | esprintf (locker, "%s@%s (pid %"pMd")", | ||
| 589 | lock_info.user, lock_info.host, pid); | ||
| 590 | FREE_LOCK_INFO (lock_info); | ||
| 591 | |||
| 592 | attack = call2 (intern ("ask-user-about-lock"), fn, build_string (locker)); | ||
| 593 | SAFE_FREE (); | ||
| 594 | if (!NILP (attack)) | ||
| 595 | /* User says take the lock */ | ||
| 596 | { | 723 | { |
| 597 | lock_file_1 (lfname, 1); | 724 | /* Someone else has the lock. Consider breaking it. */ |
| 598 | return; | 725 | Lisp_Object attack; |
| 726 | char *dot = lock_info.dot; | ||
| 727 | ptrdiff_t pidlen = lock_info.colon - (dot + 1); | ||
| 728 | static char const replacement[] = " (pid "; | ||
| 729 | int replacementlen = sizeof replacement - 1; | ||
| 730 | memmove (dot + replacementlen, dot + 1, pidlen); | ||
| 731 | strcpy (dot + replacementlen + pidlen, ")"); | ||
| 732 | memcpy (dot, replacement, replacementlen); | ||
| 733 | attack = call2 (intern ("ask-user-about-lock"), fn, | ||
| 734 | build_string (lock_info.user)); | ||
| 735 | /* Take the lock if the user said so. */ | ||
| 736 | if (!NILP (attack)) | ||
| 737 | lock_file_1 (lfname, 1); | ||
| 599 | } | 738 | } |
| 600 | /* User says ignore the lock */ | 739 | |
| 740 | UNGCPRO; | ||
| 741 | SAFE_FREE (); | ||
| 601 | } | 742 | } |
| 602 | 743 | ||
| 603 | void | 744 | void |
| 604 | unlock_file (register Lisp_Object fn) | 745 | unlock_file (Lisp_Object fn) |
| 605 | { | 746 | { |
| 606 | register char *lfname; | 747 | char *lfname; |
| 748 | USE_SAFE_ALLOCA; | ||
| 607 | 749 | ||
| 608 | fn = Fexpand_file_name (fn, Qnil); | 750 | fn = Fexpand_file_name (fn, Qnil); |
| 609 | fn = ENCODE_FILE (fn); | 751 | fn = ENCODE_FILE (fn); |
| @@ -612,6 +754,8 @@ unlock_file (register Lisp_Object fn) | |||
| 612 | 754 | ||
| 613 | if (current_lock_owner (0, lfname) == 2) | 755 | if (current_lock_owner (0, lfname) == 2) |
| 614 | unlink (lfname); | 756 | unlink (lfname); |
| 757 | |||
| 758 | SAFE_FREE (); | ||
| 615 | } | 759 | } |
| 616 | 760 | ||
| 617 | void | 761 | void |
| @@ -677,9 +821,10 @@ t if it is locked by you, else a string saying which user has locked it. */) | |||
| 677 | (Lisp_Object filename) | 821 | (Lisp_Object filename) |
| 678 | { | 822 | { |
| 679 | Lisp_Object ret; | 823 | Lisp_Object ret; |
| 680 | register char *lfname; | 824 | char *lfname; |
| 681 | int owner; | 825 | int owner; |
| 682 | lock_info_type locker; | 826 | lock_info_type locker; |
| 827 | USE_SAFE_ALLOCA; | ||
| 683 | 828 | ||
| 684 | filename = Fexpand_file_name (filename, Qnil); | 829 | filename = Fexpand_file_name (filename, Qnil); |
| 685 | 830 | ||
| @@ -691,11 +836,9 @@ t if it is locked by you, else a string saying which user has locked it. */) | |||
| 691 | else if (owner == 2) | 836 | else if (owner == 2) |
| 692 | ret = Qt; | 837 | ret = Qt; |
| 693 | else | 838 | else |
| 694 | ret = build_string (locker.user); | 839 | ret = make_string (locker.user, locker.at - locker.user); |
| 695 | |||
| 696 | if (owner > 0) | ||
| 697 | FREE_LOCK_INFO (locker); | ||
| 698 | 840 | ||
| 841 | SAFE_FREE (); | ||
| 699 | return ret; | 842 | return ret; |
| 700 | } | 843 | } |
| 701 | 844 | ||