commit:     59e9452fda79f69e9b5ab7e44ef918f6fb4d6161
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Wed Mar 25 05:11:06 2020 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Wed Mar 25 07:24:52 2020 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=59e9452f

_lockfile_was_removed: return fstat result (bug 714480)

Return a tuple that includes the fstat result, which can be used to
detect when there's an attempt to lock the same inode more than once
by the same process, since in that case the lock will not behave as
intended with the default fcntl.lockf function.

Bug: https://bugs.gentoo.org/714480
Signed-off-by: Zac Medico <zmedico <AT> gentoo.org>

 lib/portage/locks.py | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/lib/portage/locks.py b/lib/portage/locks.py
index 72ac2fc70..7bb0542dd 100644
--- a/lib/portage/locks.py
+++ b/lib/portage/locks.py
@@ -296,10 +296,9 @@ def _lockfile_iteration(mypath, wantnewlockfile=False, 
unlinkfile=False,
                else:
                        raise
 
-               
        if isinstance(lockfilename, basestring) and myfd != HARDLINK_FD and 
unlinkfile:
                try:
-                       removed = _lockfile_was_removed(myfd, lockfilename)
+                       (removed, fstat_result) = _lockfile_was_removed(myfd, 
lockfilename)
                except Exception:
                        # Do not leak the file descriptor here.
                        os.close(myfd)
@@ -341,14 +340,15 @@ def _lockfile_was_removed(lock_fd, lock_path):
        @param lock_path: path of lock file
        @type lock_path: str
        @rtype: bool
-       @return: True if lock_path exists and corresponds to lock_fd, False 
otherwise
+       @return: a tuple of (removed, fstat_result), where removed is True if
+               lock_path does not correspond to lock_fd, and False otherwise
        """
        try:
                fstat_st = os.fstat(lock_fd)
        except OSError as e:
                if e.errno not in (errno.ENOENT, errno.ESTALE):
                        _raise_exc(e)
-               return True
+               return (True, None)
 
        # Since stat is not reliable for removed files on NFS with the default
        # file attribute cache behavior ('ac' mount option), create a temporary
@@ -365,7 +365,7 @@ def _lockfile_was_removed(lock_fd, lock_path):
                except OSError as e:
                        if e.errno not in (errno.ENOENT, errno.ESTALE):
                                _raise_exc(e)
-                       return True
+                       return (True, None)
 
                hardlink_stat = os.stat(hardlink_path)
                if hardlink_stat.st_ino != fstat_st.st_ino or 
hardlink_stat.st_dev != fstat_st.st_dev:
@@ -383,13 +383,13 @@ def _lockfile_was_removed(lock_fd, lock_path):
                        except OSError as e:
                                if e.errno not in (errno.ENOENT, errno.ESTALE):
                                        _raise_exc(e)
-                               return True
+                               return (True, None)
                        else:
                                if not os.path.samefile(hardlink_path, 
inode_test):
                                        # This implies that inode numbers are 
not expected
                                        # to match for this file system, so use 
a simple
                                        # stat call to detect if lock_path has 
been removed.
-                                       return not os.path.exists(lock_path)
+                                       return (not os.path.exists(lock_path), 
fstat_st)
                        finally:
                                try:
                                        os.unlink(inode_test)
@@ -403,7 +403,7 @@ def _lockfile_was_removed(lock_fd, lock_path):
                except OSError as e:
                        if e.errno not in (errno.ENOENT, errno.ESTALE):
                                _raise_exc(e)
-       return False
+       return (False, fstat_st)
 
 
 def _fstat_nlink(fd):

Reply via email to