From 96ed82b64ac4b0c680f529973a83e37af28c9748 Mon Sep 17 00:00:00 2001
From: Helmut Grohne <helmut@subdivi.de>
Date: Tue, 20 May 2025 08:14:22 +0200
Subject: syscalls.py: simplify MountFlags implementation

The "mustnegate" field was a bit strange and it was only ever set in the
default value used for the lookup. Remove it and express its semantics
in code instead.
---
 linuxnamespaces/syscalls.py | 79 +++++++++++++++++++++++----------------------
 1 file changed, 41 insertions(+), 38 deletions(-)

(limited to 'linuxnamespaces/syscalls.py')

diff --git a/linuxnamespaces/syscalls.py b/linuxnamespaces/syscalls.py
index ad8eb78..604135e 100644
--- a/linuxnamespaces/syscalls.py
+++ b/linuxnamespaces/syscalls.py
@@ -152,39 +152,38 @@ class MountFlags(enum.IntFlag):
     # Map each flag to:
     # * The flag value
     # * Whether the flag value is negated
-    # * Whether the flag must be negated
     # * Whether the flag can be negated
     __flagstrmap = {
-        "acl": (POSIXACL, False, False, False),
-        "async": (SYNCHRONOUS, True, False, False),
-        "atime": (NOATIME, True, False, True),
-        "bind": (BIND, False, False, False),
-        "dev": (NODEV, True, False, True),
-        "diratime": (NODIRATIME, True, False, True),
-        "dirsync": (DIRSYNC, False, False, False),
-        "exec": (NOEXEC, True, False, True),
-        "iversion": (I_VERSION, False, False, True),
-        "lazytime": (LAZYTIME, False, False, True),
-        "loud": (SILENT, True, False, False),
-        "mand": (MANDLOCK, False, False, True),
-        "private": (PRIVATE, False, False, False),
-        "rbind": (BIND | REC, False, False, False),
-        "relatime": (RELATIME, False, False, True),
-        "remount": (REMOUNT, False, False, True),
-        "ro": (RDONLY, False, False, False),
-        "rprivate": (PRIVATE | REC, False, False, False),
-        "rshared": (SHARED | REC, False, False, False),
-        "rslave": (SLAVE | REC, False, False, False),
-        "runbindable": (UNBINDABLE | REC, False, False, False),
-        "rw": (RDONLY, True, False, False),
-        "shared": (SHARED, False, False, False),
-        "silent": (SILENT, False, False, False),
-        "slave": (SLAVE, False, False, False),
-        "strictatime": (STRICTATIME, False, False, True),
-        "suid": (NOSUID, True, False, True),
-        "symfollow": (NOSYMFOLLOW, True, False, True),
-        "sync": (SYNCHRONOUS, False, False, False),
-        "unbindable": (UNBINDABLE, False, False, False),
+        "acl": (POSIXACL, False, False),
+        "async": (SYNCHRONOUS, True, False),
+        "atime": (NOATIME, True, True),
+        "bind": (BIND, False, False),
+        "dev": (NODEV, True, True),
+        "diratime": (NODIRATIME, True, True),
+        "dirsync": (DIRSYNC, False, False),
+        "exec": (NOEXEC, True, True),
+        "iversion": (I_VERSION, False, True),
+        "lazytime": (LAZYTIME, False, True),
+        "loud": (SILENT, True, False),
+        "mand": (MANDLOCK, False, True),
+        "private": (PRIVATE, False, False),
+        "rbind": (BIND | REC, False, False),
+        "relatime": (RELATIME, False, True),
+        "remount": (REMOUNT, False, True),
+        "ro": (RDONLY, False, False),
+        "rprivate": (PRIVATE | REC, False, False),
+        "rshared": (SHARED | REC, False, False),
+        "rslave": (SLAVE | REC, False, False),
+        "runbindable": (UNBINDABLE | REC, False, False),
+        "rw": (RDONLY, True, False),
+        "shared": (SHARED, False, False),
+        "silent": (SILENT, False, False),
+        "slave": (SLAVE, False, False),
+        "strictatime": (STRICTATIME, False, True),
+        "suid": (NOSUID, True, True),
+        "symfollow": (NOSYMFOLLOW, True, True),
+        "sync": (SYNCHRONOUS, False, False),
+        "unbindable": (UNBINDABLE, False, False),
     }
 
     def change(self, flagsstr: str) -> "MountFlags":
@@ -196,19 +195,23 @@ class MountFlags(enum.IntFlag):
         for flagstr in flagsstr.split(","):
             if not flagstr:
                 continue
-            flag, negated, mustnegate, cannegate = self.__flagstrmap.get(
-                flagstr.removeprefix("no"),
-                (MountFlags.NONE, False, True, False),
-            )
-            if mustnegate <= flagstr.startswith("no") <= cannegate:
+            try:
+                flag, negated, cannegate = self.__flagstrmap[
+                    flagstr.removeprefix("no")
+                ]
+            except KeyError:
+                raise ValueError(
+                    f"not a valid mount flag: {flagstr!r}"
+                ) from None
+            else:
+                if flagstr.startswith("no") > cannegate:
+                    raise ValueError(f"not a valid mount flag: {flagstr!r}")
                 if negated ^ flagstr.startswith("no"):
                     ret &= ~flag
                 else:
                     if flag & MountFlags.PROPAGATION_FLAGS:
                         ret &= ~MountFlags.PROPAGATION_FLAGS
                     ret |= flag
-            else:
-                raise ValueError(f"not a valid mount flag: {flagstr!r}")
         return ret
 
     @staticmethod
-- 
cgit v1.2.3