class Permissions(BaseModel):
owner: int = Field(default=0o7)
group: int = Field(default=0)
other: int = Field(default=0)
directory: bool = Field(default=False)
def to_mode(self) -> int:
mode = 0
for perms, shift in [(self.owner, 6), (self.group, 3), (self.other, 0)]:
mode |= int(perms) << shift
if self.directory:
mode |= stat.S_IFDIR
return mode
@classmethod
def from_mode(cls, mode: int) -> "Permissions":
return cls(
owner=(mode >> 6) & 0b111,
group=(mode >> 3) & 0b111,
other=(mode >> 0) & 0b111,
directory=bool(mode & stat.S_IFDIR),
)
@classmethod
def from_str(cls, perms: str) -> "Permissions":
if len(perms) == 11 and perms[-1] in {"@", "+"}:
perms = perms[:-1]
if len(perms) != 10:
raise ValueError(f"invalid permissions string length: {perms!r}")
directory = perms[0] == "d"
if perms[0] not in {"d", "-"}:
raise ValueError(f"invalid permissions type: {perms!r}")
def parse_triplet(triplet: str) -> int:
if len(triplet) != 3:
raise ValueError(f"invalid permissions triplet: {triplet!r}")
mask = 0
if triplet[0] == "r":
mask |= FileMode.READ
elif triplet[0] != "-":
raise ValueError(f"invalid read flag: {triplet!r}")
if triplet[1] == "w":
mask |= FileMode.WRITE
elif triplet[1] != "-":
raise ValueError(f"invalid write flag: {triplet!r}")
if triplet[2] == "x":
mask |= FileMode.EXEC
elif triplet[2] != "-":
raise ValueError(f"invalid exec flag: {triplet!r}")
return int(mask)
owner = parse_triplet(perms[1:4])
group = parse_triplet(perms[4:7])
other = parse_triplet(perms[7:10])
return cls(
owner=owner,
group=group,
other=other,
directory=directory,
)
def owner_can(self, mode: int) -> Self:
self.owner = mode
return self
def group_can(self, mode: int) -> Self:
self.group = mode
return self
def others_can(self, mode: int) -> Self:
self.other = mode
return self
def __repr__(self) -> str:
def fmt(perms: int) -> str:
return "".join(
c if perms & p else "-"
for p, c in [(FileMode.READ, "r"), (FileMode.WRITE, "w"), (FileMode.EXEC, "x")]
)
return ("d" if self.directory else "-") + "".join(
fmt(perms) for perms in (self.owner, self.group, self.other)
)
def __str__(self) -> str:
return repr(self)
def __eq__(self, other: object) -> bool:
if not isinstance(other, Permissions):
return NotImplemented
return self.to_mode() == other.to_mode()