diff options
Diffstat (limited to 'src/filelock.c')
| -rw-r--r-- | src/filelock.c | 86 |
1 files changed, 44 insertions, 42 deletions
diff --git a/src/filelock.c b/src/filelock.c index 46349a63e4a..ff25d6475de 100644 --- a/src/filelock.c +++ b/src/filelock.c | |||
| @@ -504,9 +504,9 @@ read_lock_data (char *lfname, char lfinfo[MAX_LFINFO + 1]) | |||
| 504 | } | 504 | } |
| 505 | 505 | ||
| 506 | /* Return 0 if nobody owns the lock file LFNAME or the lock is obsolete, | 506 | /* Return 0 if nobody owns the lock file LFNAME or the lock is obsolete, |
| 507 | 1 if another process owns it (and set OWNER (if non-null) to info), | 507 | -1 if another process owns it (and set OWNER (if non-null) to info), |
| 508 | 2 if the current process owns it, | 508 | -2 if the current process owns it, |
| 509 | or -1 if something is wrong with the locking mechanism. */ | 509 | or an errno value if something is wrong with the locking mechanism. */ |
| 510 | 510 | ||
| 511 | static int | 511 | static int |
| 512 | current_lock_owner (lock_info_type *owner, char *lfname) | 512 | current_lock_owner (lock_info_type *owner, char *lfname) |
| @@ -525,23 +525,23 @@ current_lock_owner (lock_info_type *owner, char *lfname) | |||
| 525 | /* If nonexistent lock file, all is well; otherwise, got strange error. */ | 525 | /* If nonexistent lock file, all is well; otherwise, got strange error. */ |
| 526 | lfinfolen = read_lock_data (lfname, owner->user); | 526 | lfinfolen = read_lock_data (lfname, owner->user); |
| 527 | if (lfinfolen < 0) | 527 | if (lfinfolen < 0) |
| 528 | return errno == ENOENT ? 0 : -1; | 528 | return errno == ENOENT ? 0 : errno; |
| 529 | if (MAX_LFINFO < lfinfolen) | 529 | if (MAX_LFINFO < lfinfolen) |
| 530 | return -1; | 530 | return ENAMETOOLONG; |
| 531 | owner->user[lfinfolen] = 0; | 531 | owner->user[lfinfolen] = 0; |
| 532 | 532 | ||
| 533 | /* Parse USER@HOST.PID:BOOT_TIME. If can't parse, return -1. */ | 533 | /* Parse USER@HOST.PID:BOOT_TIME. If can't parse, return EINVAL. */ |
| 534 | /* The USER is everything before the last @. */ | 534 | /* The USER is everything before the last @. */ |
| 535 | owner->at = at = memrchr (owner->user, '@', lfinfolen); | 535 | owner->at = at = memrchr (owner->user, '@', lfinfolen); |
| 536 | if (!at) | 536 | if (!at) |
| 537 | return -1; | 537 | return EINVAL; |
| 538 | owner->dot = dot = strrchr (at, '.'); | 538 | owner->dot = dot = strrchr (at, '.'); |
| 539 | if (!dot) | 539 | if (!dot) |
| 540 | return -1; | 540 | return EINVAL; |
| 541 | 541 | ||
| 542 | /* The PID is everything from the last '.' to the ':' or equivalent. */ | 542 | /* The PID is everything from the last '.' to the ':' or equivalent. */ |
| 543 | if (! c_isdigit (dot[1])) | 543 | if (! c_isdigit (dot[1])) |
| 544 | return -1; | 544 | return EINVAL; |
| 545 | errno = 0; | 545 | errno = 0; |
| 546 | pid = strtoimax (dot + 1, &owner->colon, 10); | 546 | pid = strtoimax (dot + 1, &owner->colon, 10); |
| 547 | if (errno == ERANGE) | 547 | if (errno == ERANGE) |
| @@ -562,20 +562,20 @@ current_lock_owner (lock_info_type *owner, char *lfname) | |||
| 562 | mistakenly transliterate ':' to U+F022 in symlink contents. | 562 | mistakenly transliterate ':' to U+F022 in symlink contents. |
| 563 | See <https://bugzilla.redhat.com/show_bug.cgi?id=1384153>. */ | 563 | See <https://bugzilla.redhat.com/show_bug.cgi?id=1384153>. */ |
| 564 | if (! (boot[0] == '\200' && boot[1] == '\242')) | 564 | if (! (boot[0] == '\200' && boot[1] == '\242')) |
| 565 | return -1; | 565 | return EINVAL; |
| 566 | boot += 2; | 566 | boot += 2; |
| 567 | FALLTHROUGH; | 567 | FALLTHROUGH; |
| 568 | case ':': | 568 | case ':': |
| 569 | if (! c_isdigit (boot[0])) | 569 | if (! c_isdigit (boot[0])) |
| 570 | return -1; | 570 | return EINVAL; |
| 571 | boot_time = strtoimax (boot, &lfinfo_end, 10); | 571 | boot_time = strtoimax (boot, &lfinfo_end, 10); |
| 572 | break; | 572 | break; |
| 573 | 573 | ||
| 574 | default: | 574 | default: |
| 575 | return -1; | 575 | return EINVAL; |
| 576 | } | 576 | } |
| 577 | if (lfinfo_end != owner->user + lfinfolen) | 577 | if (lfinfo_end != owner->user + lfinfolen) |
| 578 | return -1; | 578 | return EINVAL; |
| 579 | 579 | ||
| 580 | /* On current host? */ | 580 | /* On current host? */ |
| 581 | Lisp_Object system_name = Fsystem_name (); | 581 | Lisp_Object system_name = Fsystem_name (); |
| @@ -584,22 +584,22 @@ current_lock_owner (lock_info_type *owner, char *lfname) | |||
| 584 | && memcmp (at + 1, SSDATA (system_name), SBYTES (system_name)) == 0) | 584 | && memcmp (at + 1, SSDATA (system_name), SBYTES (system_name)) == 0) |
| 585 | { | 585 | { |
| 586 | if (pid == getpid ()) | 586 | if (pid == getpid ()) |
| 587 | ret = 2; /* We own it. */ | 587 | ret = -2; /* We own it. */ |
| 588 | else if (0 < pid && pid <= TYPE_MAXIMUM (pid_t) | 588 | else if (0 < pid && pid <= TYPE_MAXIMUM (pid_t) |
| 589 | && (kill (pid, 0) >= 0 || errno == EPERM) | 589 | && (kill (pid, 0) >= 0 || errno == EPERM) |
| 590 | && (boot_time == 0 | 590 | && (boot_time == 0 |
| 591 | || (boot_time <= TYPE_MAXIMUM (time_t) | 591 | || (boot_time <= TYPE_MAXIMUM (time_t) |
| 592 | && within_one_second (boot_time, get_boot_time ())))) | 592 | && within_one_second (boot_time, get_boot_time ())))) |
| 593 | ret = 1; /* An existing process on this machine owns it. */ | 593 | ret = -1; /* An existing process on this machine owns it. */ |
| 594 | /* The owner process is dead or has a strange pid, so try to | 594 | /* The owner process is dead or has a strange pid, so try to |
| 595 | zap the lockfile. */ | 595 | zap the lockfile. */ |
| 596 | else | 596 | else |
| 597 | return unlink (lfname); | 597 | return unlink (lfname) < 0 ? errno : 0; |
| 598 | } | 598 | } |
| 599 | else | 599 | else |
| 600 | { /* If we wanted to support the check for stale locks on remote machines, | 600 | { /* If we wanted to support the check for stale locks on remote machines, |
| 601 | here's where we'd do it. */ | 601 | here's where we'd do it. */ |
| 602 | ret = 1; | 602 | ret = -1; |
| 603 | } | 603 | } |
| 604 | 604 | ||
| 605 | return ret; | 605 | return ret; |
| @@ -608,9 +608,9 @@ current_lock_owner (lock_info_type *owner, char *lfname) | |||
| 608 | 608 | ||
| 609 | /* Lock the lock named LFNAME if possible. | 609 | /* Lock the lock named LFNAME if possible. |
| 610 | Return 0 in that case. | 610 | Return 0 in that case. |
| 611 | Return positive if some other process owns the lock, and info about | 611 | Return negative if some other process owns the lock, and info about |
| 612 | that process in CLASHER. | 612 | that process in CLASHER. |
| 613 | Return -1 if cannot lock for any other reason. */ | 613 | Return positive errno value if cannot lock for any other reason. */ |
| 614 | 614 | ||
| 615 | static int | 615 | static int |
| 616 | lock_if_free (lock_info_type *clasher, char *lfname) | 616 | lock_if_free (lock_info_type *clasher, char *lfname) |
| @@ -618,20 +618,18 @@ lock_if_free (lock_info_type *clasher, char *lfname) | |||
| 618 | int err; | 618 | int err; |
| 619 | while ((err = lock_file_1 (lfname, 0)) == EEXIST) | 619 | while ((err = lock_file_1 (lfname, 0)) == EEXIST) |
| 620 | { | 620 | { |
| 621 | switch (current_lock_owner (clasher, lfname)) | 621 | err = current_lock_owner (clasher, lfname); |
| 622 | if (err != 0) | ||
| 622 | { | 623 | { |
| 623 | case 2: | 624 | if (err < 0) |
| 624 | return 0; /* We ourselves locked it. */ | 625 | return -2 - err; /* We locked it, or someone else has it. */ |
| 625 | case 1: | 626 | break; /* current_lock_owner returned strange error. */ |
| 626 | return 1; /* Someone else has it. */ | ||
| 627 | case -1: | ||
| 628 | return -1; /* current_lock_owner returned strange error. */ | ||
| 629 | } | 627 | } |
| 630 | 628 | ||
| 631 | /* We deleted a stale lock; try again to lock the file. */ | 629 | /* We deleted a stale lock; try again to lock the file. */ |
| 632 | } | 630 | } |
| 633 | 631 | ||
| 634 | return err ? -1 : 0; | 632 | return err; |
| 635 | } | 633 | } |
| 636 | 634 | ||
| 637 | /* lock_file locks file FN, | 635 | /* lock_file locks file FN, |
| @@ -697,8 +695,9 @@ lock_file (Lisp_Object fn) | |||
| 697 | /* Create the name of the lock-file for file fn */ | 695 | /* Create the name of the lock-file for file fn */ |
| 698 | MAKE_LOCK_NAME (lfname, encoded_fn); | 696 | MAKE_LOCK_NAME (lfname, encoded_fn); |
| 699 | 697 | ||
| 700 | /* Try to lock the lock. */ | 698 | /* Try to lock the lock. FIXME: This ignores errors when |
| 701 | if (0 < lock_if_free (&lock_info, lfname)) | 699 | lock_if_free returns a positive errno value. */ |
| 700 | if (lock_if_free (&lock_info, lfname) < 0) | ||
| 702 | { | 701 | { |
| 703 | /* Someone else has the lock. Consider breaking it. */ | 702 | /* Someone else has the lock. Consider breaking it. */ |
| 704 | Lisp_Object attack; | 703 | Lisp_Object attack; |
| @@ -725,13 +724,16 @@ unlock_file (Lisp_Object fn) | |||
| 725 | char *lfname; | 724 | char *lfname; |
| 726 | USE_SAFE_ALLOCA; | 725 | USE_SAFE_ALLOCA; |
| 727 | 726 | ||
| 728 | fn = Fexpand_file_name (fn, Qnil); | 727 | Lisp_Object filename = Fexpand_file_name (fn, Qnil); |
| 729 | fn = ENCODE_FILE (fn); | 728 | fn = ENCODE_FILE (filename); |
| 730 | 729 | ||
| 731 | MAKE_LOCK_NAME (lfname, fn); | 730 | MAKE_LOCK_NAME (lfname, fn); |
| 732 | 731 | ||
| 733 | if (current_lock_owner (0, lfname) == 2) | 732 | int err = current_lock_owner (0, lfname); |
| 734 | unlink (lfname); | 733 | if (err == -2 && unlink (lfname) != 0 && errno != ENOENT) |
| 734 | err = errno; | ||
| 735 | if (0 < err) | ||
| 736 | report_file_errno ("Unlocking file", filename, err); | ||
| 735 | 737 | ||
| 736 | SAFE_FREE (); | 738 | SAFE_FREE (); |
| 737 | } | 739 | } |
| @@ -822,17 +824,17 @@ t if it is locked by you, else a string saying which user has locked it. */) | |||
| 822 | USE_SAFE_ALLOCA; | 824 | USE_SAFE_ALLOCA; |
| 823 | 825 | ||
| 824 | filename = Fexpand_file_name (filename, Qnil); | 826 | filename = Fexpand_file_name (filename, Qnil); |
| 825 | filename = ENCODE_FILE (filename); | 827 | Lisp_Object encoded_filename = ENCODE_FILE (filename); |
| 826 | 828 | MAKE_LOCK_NAME (lfname, encoded_filename); | |
| 827 | MAKE_LOCK_NAME (lfname, filename); | ||
| 828 | 829 | ||
| 829 | owner = current_lock_owner (&locker, lfname); | 830 | owner = current_lock_owner (&locker, lfname); |
| 830 | if (owner <= 0) | 831 | switch (owner) |
| 831 | ret = Qnil; | 832 | { |
| 832 | else if (owner == 2) | 833 | case -2: ret = Qt; break; |
| 833 | ret = Qt; | 834 | case -1: ret = make_string (locker.user, locker.at - locker.user); break; |
| 834 | else | 835 | case 0: ret = Qnil; break; |
| 835 | ret = make_string (locker.user, locker.at - locker.user); | 836 | default: report_file_errno ("Testing file lock", filename, owner); |
| 837 | } | ||
| 836 | 838 | ||
| 837 | SAFE_FREE (); | 839 | SAFE_FREE (); |
| 838 | return ret; | 840 | return ret; |