aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2024-08-15 13:17:24 -0700
committerPaul Eggert2024-08-15 13:31:31 -0700
commit775fa8443faa3d7f5ce7f7d0aa6e6fb53321715a (patch)
treea53565522628bce87ff6f1c46b86045d631ee70a /src
parent4b6b9a7acdc4f7d0594caaaa382e2e633f8f1225 (diff)
downloademacs-775fa8443faa3d7f5ce7f7d0aa6e6fb53321715a.tar.gz
emacs-775fa8443faa3d7f5ce7f7d0aa6e6fb53321715a.zip
Refactor current_lock_owner
* src/filelock.c (current_lock_owner): Refactor to make further changes easier. This should not affect behavior.
Diffstat (limited to 'src')
-rw-r--r--src/filelock.c185
1 files changed, 95 insertions, 90 deletions
diff --git a/src/filelock.c b/src/filelock.c
index cdf9e6f0ffc..c68aacc46fb 100644
--- a/src/filelock.c
+++ b/src/filelock.c
@@ -386,9 +386,6 @@ static int
386current_lock_owner (lock_info_type *owner, Lisp_Object lfname) 386current_lock_owner (lock_info_type *owner, Lisp_Object lfname)
387{ 387{
388 lock_info_type local_owner; 388 lock_info_type local_owner;
389 ptrdiff_t lfinfolen;
390 intmax_t pid, boot_time;
391 char *at, *dot, *lfinfo_end;
392 389
393 /* Even if the caller doesn't want the owner info, we still have to 390 /* Even if the caller doesn't want the owner info, we still have to
394 read it to determine return value. */ 391 read it to determine return value. */
@@ -396,104 +393,112 @@ current_lock_owner (lock_info_type *owner, Lisp_Object lfname)
396 owner = &local_owner; 393 owner = &local_owner;
397 394
398 /* If nonexistent lock file, all is well; otherwise, got strange error. */ 395 /* If nonexistent lock file, all is well; otherwise, got strange error. */
399 lfinfolen = read_lock_data (SSDATA (lfname), owner->user); 396 ptrdiff_t lfinfolen = read_lock_data (SSDATA (lfname), owner->user);
400 if (lfinfolen < 0) 397 if (lfinfolen < 0)
401 return errno == ENOENT || errno == ENOTDIR ? 0 : errno; 398 return errno == ENOENT || errno == ENOTDIR ? 0 : errno;
402 if (MAX_LFINFO < lfinfolen) 399
403 return ENAMETOOLONG; 400 /* Examine lock file contents. */
404 owner->user[lfinfolen] = 0; 401 if (true)
405
406 /* Parse USER@HOST.PID:BOOT_TIME. If can't parse, return EINVAL. */
407 /* The USER is everything before the last @. */
408 owner->at = at = memrchr (owner->user, '@', lfinfolen);
409 if (!at)
410 return EINVAL;
411 owner->dot = dot = strrchr (at, '.');
412 if (!dot)
413 return EINVAL;
414
415 /* The PID is everything from the last '.' to the ':' or equivalent. */
416 if (! integer_prefixed (dot + 1))
417 return EINVAL;
418 errno = 0;
419 pid = strtoimax (dot + 1, &owner->colon, 10);
420 if (errno == ERANGE)
421 pid = -1;
422
423 /* After the ':' or equivalent, if there is one, comes the boot time. */
424 char *boot = owner->colon + 1;
425 switch (owner->colon[0])
426 { 402 {
427 case 0: 403 if (MAX_LFINFO < lfinfolen)
428 boot_time = 0; 404 return ENAMETOOLONG;
429 lfinfo_end = owner->colon; 405 owner->user[lfinfolen] = 0;
430 break;
431 406
432 case '\357': 407 /* Parse USER@HOST.PID:BOOT_TIME. If can't parse, return EINVAL. */
433 /* Treat "\357\200\242" (U+F022 in UTF-8) as if it were ":" (Bug#24656). 408 /* The USER is everything before the last @. */
434 This works around a bug in the Linux CIFS kernel client, which can 409 char *at = memrchr (owner->user, '@', lfinfolen);
435 mistakenly transliterate ':' to U+F022 in symlink contents. 410 if (!at)
436 See <https://bugzilla.redhat.com/show_bug.cgi?id=1384153>. */
437 if (! (boot[0] == '\200' && boot[1] == '\242'))
438 return EINVAL; 411 return EINVAL;
439 boot += 2; 412 owner->at = at;
440 FALLTHROUGH; 413 char *dot = strrchr (at, '.');
441 case ':': 414 if (!dot)
442 if (! integer_prefixed (boot))
443 return EINVAL; 415 return EINVAL;
444 boot_time = strtoimax (boot, &lfinfo_end, 10); 416 owner->dot = dot;
445 break;
446 417
447 default: 418 /* The PID is everything from the last '.' to the ':' or equivalent. */
448 return EINVAL; 419 if (! integer_prefixed (dot + 1))
449 } 420 return EINVAL;
450 if (lfinfo_end != owner->user + lfinfolen) 421 errno = 0;
451 return EINVAL; 422 intmax_t pid = strtoimax (dot + 1, &owner->colon, 10);
452 423 if (errno == ERANGE)
453 char *linkhost = at + 1; 424 pid = -1;
454 ptrdiff_t linkhostlen = dot - linkhost; 425
455 Lisp_Object system_name = Fsystem_name (); 426 /* After the ':' or equivalent, if there is one, comes the boot time. */
456 /* If `system-name' returns nil, that means we're in a 427 intmax_t boot_time;
457 --no-build-details Emacs, and the name part of the link (e.g., 428 char *boot = owner->colon + 1, *lfinfo_end;
458 .#test.txt -> larsi@.118961:1646577954) is an empty string. */ 429 switch (owner->colon[0])
459 bool on_current_host;
460 if (NILP (system_name))
461 on_current_host = linkhostlen == 0;
462 else
463 {
464 on_current_host = linkhostlen == SBYTES (system_name);
465 if (on_current_host)
466 { 430 {
467 /* Protect against the extremely unlikely case of the host 431 case 0:
468 name containing '@'. */ 432 boot_time = 0;
469 char *sysname = SSDATA (system_name); 433 lfinfo_end = owner->colon;
470 for (ptrdiff_t i = 0; i < linkhostlen; i++) 434 break;
471 if (linkhost[i] != (sysname[i] == '@' ? '-' : sysname[i])) 435
472 { 436 case '\357':
473 on_current_host = false; 437 /* Treat "\357\200\242" (U+F022 in UTF-8) like ":" (Bug#24656).
474 break; 438 This works around a bug in the Linux CIFS kernel client, which can
475 } 439 mistakenly transliterate ':' to U+F022 in symlink contents.
440 See <https://bugzilla.redhat.com/show_bug.cgi?id=1384153>. */
441 if (! (boot[0] == '\200' && boot[1] == '\242'))
442 return EINVAL;
443 boot += 2;
444 FALLTHROUGH;
445 case ':':
446 if (! integer_prefixed (boot))
447 return EINVAL;
448 boot_time = strtoimax (boot, &lfinfo_end, 10);
449 break;
450
451 default:
452 return EINVAL;
476 } 453 }
477 } 454 if (lfinfo_end != owner->user + lfinfolen)
478 if (on_current_host) 455 return EINVAL;
479 { 456
480 if (pid == getpid ()) 457 char *linkhost = at + 1;
481 return I_OWN_IT; 458 ptrdiff_t linkhostlen = dot - linkhost;
482 else if (VALID_PROCESS_ID (pid) 459 Lisp_Object system_name = Fsystem_name ();
483 && (kill (pid, 0) >= 0 || errno == EPERM) 460 /* If `system-name' returns nil, that means we're in a
484 && (boot_time == 0 461 --no-build-details Emacs, and the name part of the link (e.g.,
485 || within_one_second (boot_time, get_boot_sec ()))) 462 .#test.txt -> larsi@.118961:1646577954) is an empty string. */
486 return ANOTHER_OWNS_IT; 463 bool on_current_host;
487 /* The owner process is dead or has a strange pid, so try to 464 if (NILP (system_name))
488 zap the lockfile. */ 465 on_current_host = linkhostlen == 0;
489 else 466 else
490 return emacs_unlink (SSDATA (lfname)) < 0 ? errno : 0; 467 {
491 } 468 on_current_host = linkhostlen == SBYTES (system_name);
492 else 469 if (on_current_host)
493 { /* If we wanted to support the check for stale locks on remote machines, 470 {
494 here's where we'd do it. */ 471 /* Protect against the extremely unlikely case of the host
495 return ANOTHER_OWNS_IT; 472 name containing '@'. */
473 char *sysname = SSDATA (system_name);
474 for (ptrdiff_t i = 0; i < linkhostlen; i++)
475 if (linkhost[i] != (sysname[i] == '@' ? '-' : sysname[i]))
476 {
477 on_current_host = false;
478 break;
479 }
480 }
481 }
482 if (!on_current_host)
483 {
484 /* Not on current host. If we wanted to support the check for
485 stale locks on remote machines, here's where we'd do it. */
486 return ANOTHER_OWNS_IT;
487 }
488
489 if (pid == getpid ())
490 return I_OWN_IT;
491
492 if (VALID_PROCESS_ID (pid)
493 && ! (kill (pid, 0) < 0 && errno != EPERM)
494 && (boot_time == 0
495 || within_one_second (boot_time, get_boot_sec ())))
496 return ANOTHER_OWNS_IT;
496 } 497 }
498
499 /* The owner process is dead or has a strange pid.
500 Try to zap the lockfile. */
501 return emacs_unlink (SSDATA (lfname)) < 0 ? errno : 0;
497} 502}
498 503
499 504