diff options
| author | Paul Eggert | 2024-08-15 13:17:24 -0700 |
|---|---|---|
| committer | Paul Eggert | 2024-08-15 13:31:31 -0700 |
| commit | 775fa8443faa3d7f5ce7f7d0aa6e6fb53321715a (patch) | |
| tree | a53565522628bce87ff6f1c46b86045d631ee70a /src | |
| parent | 4b6b9a7acdc4f7d0594caaaa382e2e633f8f1225 (diff) | |
| download | emacs-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.c | 185 |
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 | |||
| 386 | current_lock_owner (lock_info_type *owner, Lisp_Object lfname) | 386 | current_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 | ||