Чтение масок (потокобезопасно) - PullRequest
0 голосов
/ 09 ноября 2018

Я знаю этот шаблон для чтения umask в Python:

current_umask = os.umask(0)  # line1
os.umask(current_umask)      # line2
return current_umask         # line3

Но это не потокобезопасно.

Поток, который выполняется между line1 и line2, будет иметь другой umask.

Есть ли потокобезопасный способ чтения umask в Python?

Похожие: https://bugs.python.org/issue35275

Ответы [ 4 ]

0 голосов
/ 18 ноября 2018

Единственный, по-настоящему, однозначно поточно-ориентированный способ, который я знаю, - это вызывать новый процесс.

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.

0 голосов
/ 13 ноября 2018

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()))
0 голосов
/ 16 ноября 2018

Определить 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's permission bits
            return 0o777 & ~os.stat(fd).st_mode
        finally:
            os.close(fd)
            os.unlink(path)
0 голосов
/ 12 ноября 2018

если в вашей системе есть поле 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.

или, вы можете добавить блокировку потока:)

...