Чтение umask (потокобезопасное)
Я знаю этот шаблон для чтения umask в Python:
current_umask = os.umask(0) # line1
os.umask(current_umask) # line2
return current_umask # line3
Но это не потокобезопасно.
Поток, который выполняется между строками 1 и 2, будет иметь другую umask.
Есть ли безопасный поток для чтения umask в Python?
Связано: https://bugs.python.org/issue35275
Ответы
Ответ 1
если ваша система имеет поле Umask
в /proc/[pid]/status
, вы можете прочитать по нему:
import os
def getumask():
pid = os.getpid()
with open(f'/proc/{pid}/status') as f:
for l in f:
if l.startswith('Umask'):
return int(l.split()[1], base=8)
return None
протестировано под CentOS 7.5, Debian 9.6.
или вы можете добавить блокировку потока :)
Ответ 2
umask наследуется дочерними процессами. Вы можете создать канал, развить дочерний процесс, получить там umask и записать результат в канал, чтобы родитель мог его прочитать.
Довольно дорого, но без особых требований, таких как /proc
виртуальная файловая система. Пример с только низкоуровневыми вызовами ОС (все асинхронные) и без ошибок:
import os
import struct
def get_umask():
pipe = os.pipe()
pid = os.fork()
if pid == 0:
os.close(pipe[0])
umask = os.umask(0)
os.write(pipe[1], struct.pack('H', umask))
os.close(pipe[1])
os._exit(0)
else:
os.close(pipe[1])
value = os.read(pipe[0], 2)
os.close(pipe[0])
os.waitpid(pid, 0)
return struct.unpack('H', value)[0]
print("umask {:03o}".format(get_umask()))
Ответ 3
Можно определить umask, создав временный файл и проверив его разрешения. Это должно работать на всех системах * nix:
def get_umask():
import os, os.path, random, tempfile
while True:
# Generate a random name
name = 'test'
for _ in range(8):
name += chr(random.randint(ord('a'), ord('z')))
path = os.path.join(tempfile.gettempdir(), name)
# Attempt to create a file with full permissions
try:
fd = os.open(path, os.O_RDONLY|os.O_CREAT|os.O_EXCL, 0o777)
except FileExistsError:
# File exists, try again
continue
try:
# Deduce umask from the file permission bits
return 0o777 & ~os.stat(fd).st_mode
finally:
os.close(fd)
os.unlink(path)
Ответ 4
Единственный, по-настоящему, однозначно ниточный, я знаю, это назвать новый процесс.
import subprocess
umask_cmd = ('python', '-c', 'import os; print(os.umask(0777))')
umask = int(subprocess.check_output(umask_cmd))
Обратите внимание, что если у вас есть bash или другая оболочка, вы также можете это назвать. Так как это может быть в странной системе, я решил использовать подпроцесс python в umask_cmd
, так как у вас должен быть python. Если вы используете не-странную систему * nix, то вместо этого вы можете использовать sh или bash.