Yes, chmod
is usually not working on Windows.
It is better to use the proper tools from command line: cacls
for old versions of windows (Windows XP or below), or icacls
for most versions of Windows.
The following code could allow to change permissions (with an additional context manager to change temporarily if needed):
"""
Prototype of script to modify access rights with "icacls" in Windows
"""
from contextlib import contextmanager
from enum import Enum
from subprocess import check_output
from pathlib import Path
from typing import Generator, List
class AccessRight(Enum):
"""Access Rights for files/folders"""
DELETE = "D"
FULL = "F" # Edit Permissions + Create + Delete + Read + Write
NO_ACCESS = "N"
MODIFY = "M" # Create + Delete + Read + Write
READ_EXECUTE = "RX"
READ_ONLY = "R"
WRITE_ONLY = "W"
@contextmanager
def set_access_right(file: Path, access: AccessRight) -> Generator[Path, None, None]:
"""Context Manager to temporarily set a given access rights to a file and reset"""
def cmd(access_right: AccessRight) -> List[str]:
return [
"icacls",
str(file),
"/inheritance:r",
"/grant:r",
f"Everyone:{access_right.value}",
]
try:
check_output(cmd(access))
yield file
finally:
check_output(cmd(AccessRight.FULL))
# We create a file (if it does not exist) with empty content
toto = Path("toto.txt")
toto.touch()
# We temporarily set access rights of the
with set_access_right(toto, AccessRight.WRITE_ONLY) as path:
path.write_text("My name is Toto")
try:
content = path.read_text()
print(f":( Should not be able to read content of file but read: {content}")
except PermissionError:
print("Cannot read toto: YEAH!")
# We check that access rights have been restored (and delete the file to stay clean)
print(path.read_text())
toto.unlink()
[Edit March 2023] -> Alternate solution using os.chmod
, which might be more complex but is cross-platform
Based on a remark from @L4ZZA and from this answer, we could also use the permissions defined in stat
:
import os
import stat
# If you want to set new permisions (i.e. replace)
os.chmod('my_file.txt', <stat mask>)
# If you want to add new permissions
st = os.stat('somefile')
os.chmod('my_file.txt', st.st_mode | <stat mask>)
With the mask stat mask
being one or several of the following (if several, join them with a |
):
stat.S_ISUID
: set UID bit
stat.S_ISGID
: set GID bit
stat.S_ENFMT
: file locking enforcement
stat.S_ISVTX
: sticky bit
stat.S_IREAD
: Unix V7 synonym for S_IRUSR
stat.S_IWRITE
: Unix V7 synonym for S_IWUSR
stat.S_IEXEC
: Unix V7 synonym for S_IXUSR
stat.S_IRWXU
: mask for owner permissions
stat.S_IRUSR
: read by owner
stat.S_IWUSR
: write by owner
stat.S_IXUSR
: execute by owner
stat.S_IRWXG
: mask for group permissions
stat.S_IRGRP
: read by group
stat.S_IWGRP
: write by group
stat.S_IXGRP
: execute by group
stat.S_IRWXO
: mask for others (not in group) permissions
stat.S_IROTH
: read by others
stat.S_IWOTH
: write by others
stat.S_IXOTH
: execute by others