Эквивалент Python для чтения файлов Perl (-r), записываемых (-w) и исполняемых (-x) операторов

Я был Google, чтобы попытаться найти эквивалент в Python некоторым из операторов проверки файлов Perl.

Большинство операторов тестовых файлов - это просто прямое питонирование основного вызова os 'stat. Например, os.stat('file').st_ctime просто считывает время изменения inode в качестве утилиты * nix stat или ls -l.

Некоторые из операторов проверки файлов Perl я не могу найти эквивалент в Python. Например, у меня есть дерево данных из 85 000 файлов изображений, созданных различными приложениями. Некоторые из файлов имеют эффективный UID, установленный таким образом, который является nettlesome и сбой модификации для проблемы разрешения. Поэтому для этих файлов мне нужно запустить что-то вроде:

$ find . -type f -print0 | perl -0 -lnE 'say unless -w' | change euid...

Так как я не нашел эквивалент в Python, мне нужно выложить на Perl, чтобы найти эти файлы. Я нашел эту таблицу, которая предполагает отсутствие прямого эквивалента. Правда?

Ответ 1

Глядя на вывод strace, perl выполняет вызов stat(), за которым следует getgroups(), чтобы получить идентификаторы дополнительных групп процесса perl. Похоже, он просто проверяет результаты вызова stat() против идентификаторов EUID, EGID и дополнительных групп.

Python имеет функцию getgroups() в os, поэтому я уверен, что вы можете сделать то же самое.

EDIT: вы можете попробовать что-то подобное, если никто не придет к лучшему ответу. (Жестко проверено):

def effectively_readable(path):
    import os, stat

    uid = os.getuid()
    euid = os.geteuid()
    gid = os.getgid()
    egid = os.getegid()

    # This is probably true most of the time, so just let os.access()
    # handle it.  Avoids potential bugs in the rest of this function.
    if uid == euid and gid == egid:
        return os.access(path, os.R_OK)

    st = os.stat(path)

    # This may be wrong depending on the semantics of your OS.
    # i.e. if the file is -------r--, does the owner have access or not?
    if st.st_uid == euid:
        return st.st_mode & stat.S_IRUSR != 0

    # See comment for UID check above.
    groups = os.getgroups()
    if st.st_gid == egid or st.st_gid in groups:
        return st.st_mode & stat.S_IRGRP != 0

    return st.st_mode & stat.S_IROTH != 0

Очевидно, что -w будет почти идентичным, но с W_OK, S_IWUSR и т.д.

Ответ 2

Начиная с Python 3.3 вы можете сделать это с помощью os.access:

Изменено в версии 3.3: Добавлены dir_fd, effective_ids и follow_symlinks.

Если значение effective_ids равно True, access() выполнит проверку доступа используя эффективный uid/gid вместо реального uid/gid. effective_ids может не поддерживаться на вашей платформе; вы можете проверить, действительно ли это доступен с помощью os.supports_effective_ids. Если он недоступен, используя его, вы получите NotImplementedError.

Ответ 3

Чтобы проверить, может ли ваш эффективный пользователь писать файл, большинство просто откроет его и попытается, и поймает ошибку в исключении. Возможно, это не правильное решение во всех случаях, но объясняет, почему для этого нет конкретной поддержки.

Ответ 4

os.access делает именно то, что вы хотите.

Используйте реальный uid/gid для проверки доступа к пути. Обратите внимание, что в большинстве операций будет использоваться эффективный uid/gid, поэтому эту процедуру можно использовать в среде suid/sgid, чтобы проверить, имеет ли вызывающий пользователь указанный путь к пути.