diff options
| author | Paul Eggert | 2013-03-05 14:35:41 -0800 |
|---|---|---|
| committer | Paul Eggert | 2013-03-05 14:35:41 -0800 |
| commit | 707431575aef93ac3e9923d450a6cbf18192c933 (patch) | |
| tree | c81ecb9af767baaea6876c956b6fc921ebb6ac9e /src | |
| parent | 05e193f1706f5d9846530e734d0271b15b9a818c (diff) | |
| download | emacs-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/ChangeLog | 52 | ||||
| -rw-r--r-- | src/filelock.c | 439 | ||||
| -rw-r--r-- | src/w32.c | 18 | ||||
| -rw-r--r-- | src/w32.h | 2 |
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 @@ | |||
| 1 | 2013-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 | |||
| 1 | 2013-03-05 Eli Zaretskii <eliz@gnu.org> | 53 | 2013-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. */ | ||
| 302 | enum { 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 | ||
| 289 | typedef struct | 306 | typedef 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 |
| 301 | enum { 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)" |
| 303 | enum { 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 | ||
| 313 | static void | 327 | static 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. */ | ||
| 344 | enum { 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. */ | ||
| 327 | static int | 349 | static int |
| 328 | create_lock_file (char *lfname, char *lock_info_str, bool force) | 350 | rename_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 | |||
| 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; | ||
| 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 | ||
| 379 | static bool | 458 | static int |
| 380 | lock_file_1 (char *lfname, bool force) | 459 | lock_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 | ||
| 417 | static Lisp_Object | 488 | /* On systems lacking ELOOP, test for an errno value that shouldn't occur. */ |
| 418 | read_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); | 497 | static ptrdiff_t |
| 433 | emacs_close (fd); | 498 | read_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 | |||
| 451 | current_lock_owner (lock_info_type *owner, char *lfname) | 534 | current_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 | ||
| 553 | static int | 626 | static int |
| 554 | lock_if_free (lock_info_type *clasher, register char *lfname) | 627 | lock_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; |
| @@ -3416,7 +3416,13 @@ sys_open (const char * path, int oflag, int mode) | |||
| 3416 | } | 3416 | } |
| 3417 | 3417 | ||
| 3418 | int | 3418 | int |
| 3419 | sys_rename (const char * oldname, const char * newname) | 3419 | fchmod (int fd, mode_t mode) |
| 3420 | { | ||
| 3421 | return 0; | ||
| 3422 | } | ||
| 3423 | |||
| 3424 | int | ||
| 3425 | sys_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 | ||
| 3532 | int | 3538 | int |
| 3539 | sys_rename (char const *old, char const *new) | ||
| 3540 | { | ||
| 3541 | return sys_rename_replace (old, new, TRUE); | ||
| 3542 | } | ||
| 3543 | |||
| 3544 | int | ||
| 3533 | sys_rmdir (const char * path) | 3545 | sys_rmdir (const char * path) |
| 3534 | { | 3546 | { |
| 3535 | return _rmdir (map_w32_filename (path, NULL)); | 3547 | return _rmdir (map_w32_filename (path, NULL)); |
| @@ -186,6 +186,8 @@ extern BOOL init_winsock (int load_now); | |||
| 186 | extern void srandom (int); | 186 | extern void srandom (int); |
| 187 | extern int random (void); | 187 | extern int random (void); |
| 188 | 188 | ||
| 189 | extern int fchmod (int, mode_t); | ||
| 190 | extern int sys_rename_replace (char const *, char const *, BOOL); | ||
| 189 | extern int sys_pipe (int *); | 191 | extern int sys_pipe (int *); |
| 190 | 192 | ||
| 191 | extern void set_process_dir (char *); | 193 | extern void set_process_dir (char *); |