it-roy-ru.com

Каталог

Как лучше всего было бы в Python определить, доступен ли каталог для записи пользователю, выполняющему сценарий? Поскольку это, вероятно, потребует использования модуля os, я должен отметить, что я запускаю его в среде * nix. 

85
illuminatedtiger

Хотя то, что предложил Кристоф, является более Pythonic решением, модуль os имеет функцию os.access для проверки доступа:

os.access('/path/to/folder', os.W_OK) # W_OK для записи, R_OK для чтения и т. д.

144
Max Shawabkeh

Это может показаться странным, но распространенная идиома Python 

Проще просить прощения чем за разрешение

Следуя этой идиоме, можно сказать:

Попробуйте написать в рассматриваемый каталог и поймайте ошибку, если у вас нет разрешения на это.

61
ChristopheD

Мое решение с использованием модуля tempfile:

import tempfile
import errno

def isWritable(path):
    try:
        testfile = tempfile.TemporaryFile(dir = path)
        testfile.close()
    except OSError as e:
        if e.errno == errno.EACCES:  # 13
            return False
        e.filename = path
        raise
    return True
15
zak

Наткнулся на эту тему в поисках примеров для кого-то. Первый результат в Google, поздравляю!

Люди говорят о Pythonic способ сделать это в этой теме, но нет простых примеров кода? Вот, пожалуйста, для всех, кто спотыкается в:

import sys

filepath = 'C:\\path\\to\\your\\file.txt'

try:
    filehandle = open( filepath, 'w' )
except IOError:
    sys.exit( 'Unable to write to file ' + filepath )

filehandle.write("I am writing this text to the file\n")

Это пытается открыть дескриптор файла для записи и завершается с ошибкой, если указанный файл не может быть записан: это гораздо проще для чтения, и это гораздо лучший способ сделать это, чем делать предварительные проверки пути к файлу или каталог так как избегает условий гонки; случаи, когда файл становится недоступным для записи между временем запуска предварительной проверки и фактической попыткой записи в файл. 

10
Rohaq

Если вы заботитесь только о разрешении файлов, os.access(path, os.W_OK) должна выполнить то, что вы просите. Если вы хотите узнать, можете ли вы можете записать в каталог, open() тестовый файл для записи (он не должен существовать заранее), перехватить и проверить любую IOError, а затем очистить тестовый файл.

В более общем плане, чтобы избежать TOCTOU атак (только проблема, если ваш скрипт запускается с повышенными привилегиями - suid или cgi или около того), вам не следует доверять этим преждевременным тестам, а отбрасывать привилегии , выполните функцию open() и ожидайте IOError.

9
sverkerw

Проверьте биты режима: 

def isWritable(name):
  uid = os.geteuid()
  gid = os.getegid()
  s = os.stat(dirname)
  mode = s[stat.ST_MODE]
  return (
     ((s[stat.ST_UID] == uid) and (mode & stat.S_IWUSR)) or
     ((s[stat.ST_GID] == gid) and (mode & stat.S_IWGRP)) or
     (mode & stat.S_IWOTH)
     )
7
Joe Koberg

Вот что я создал на основе ответа ChristopheD:

import os

def isWritable(directory):
    try:
        tmp_prefix = "write_tester";
        count = 0
        filename = os.path.join(directory, tmp_prefix)
        while(os.path.exists(filename)):
            filename = "{}.{}".format(os.path.join(directory, tmp_prefix),count)
            count = count + 1
        f = open(filename,"w")
        f.close()
        os.remove(filename)
        return True
    except Exception as e:
        #print "{}".format(e)
        return False

directory = "c:\\"
if (isWritable(directory)):
    print "directory is writable"
else:
    print "directory is not writable"
4
khattam
 if os.access(path_to_folder, os.W_OK) is not True:
            print("Folder not writable")
 else :
            print("Folder writable")

более подробную информацию о доступе можно найти его здесь

2
Softmixt

Я столкнулся с этой же необходимостью при добавлении аргумента через argparse. Встроенная функция type=FileType('w') не будет работать для меня, так как я искал каталог. Я закончил писать свой собственный метод, чтобы решить мою проблему. Вот результат с argparse сниппетом.

#! /usr/bin/env python
import os
import argparse

def writable_dir(dir):
    if os.access(dir, os.W_OK) and os.path.isdir(dir):
        return os.path.abspath(dir)
    else:
        raise argparse.ArgumentTypeError(dir + " is not writable or does not exist.")

parser = argparse.ArgumentParser()
parser.add_argument("-d","--dir", type=writable_dir(), default='/tmp/',
    help="Directory to use. Default: /tmp")
opts = parser.parse_args()

Это приводит к следующему:

$ python dir-test.py -h
usage: dir-test.py [-h] [-d DIR]

optional arguments:
  -h, --help         show this help message and exit
  -d DIR, --dir DIR  Directory to use. Default: /tmp

$ python dir-test.py -d /not/real
usage: dir-test.py [-h] [-d DIR]
dir-test.py: error: argument -d/--dir: /not/real is not writable or does not exist.

$ python dir-test.py -d ~

Я вернулся и добавил распечатать opts.dir до конца, и все, кажется, работает как хотелось бы.

1
796m9XfYTkmp

Если вам нужно проверить разрешение другого пользователя (да, я понимаю, что это противоречит вопросу, но может кому-то пригодится), вы можете сделать это через модуль pwd и биты режима каталога.

Disclaimer - не работает в Windows, так как не использует модель разрешений POSIX (а модуль pwd там недоступен), например, - решение только для * nix систем.

Обратите внимание, что в каталоге должны быть установлены все 3 бита - Read, Write и eXecute.
Хорошо, R не является обязательным условием, но без него вы не можете перечислить записи в каталоге (поэтому вы должны знать их имена). Выполнение, с другой стороны, абсолютно необходимо - без него пользователь не может прочитать inode файла; таким образом, даже имея W, без X-файлов невозможно создать или изменить. Более подробное объяснение по этой ссылке.

Наконец, режимы доступны в модуле stat, их описания находятся в inode (7) man .

Пример кода как проверить:

import pwd
import stat
import os

def check_user_dir(user, directory):
    dir_stat = os.stat(directory)

    user_id, group_id = pwd.getpwnam(user).pw_uid, pwd.getpwnam(user).pw_gid
    directory_mode = dir_stat[stat.ST_MODE]

    # use directory_mode as mask 
    if user_id == dir_stat[stat.ST_UID] and stat.S_IRWXU & directory_mode == stat.S_IRWXU:     # owner and has RWX
        return True
    Elif group_id == dir_stat[stat.ST_GID] and stat.S_IRWXG & directory_mode == stat.S_IRWXG:  # in group & it has RWX
        return True
    Elif stat.S_IRWXO & directory_mode == stat.S_IRWXO:                                        # everyone has RWX
        return True

    # no permissions
    return False
0
Todor Minakov