Що було б найкращим способом у Python визначити, чи є каталог, що записується для користувача, що виконує сценарій? Оскільки це, ймовірно, передбачає використання модуля os, я повинен зазначити, що я запускаю його в середовищі * nix.
Що було б найкращим способом у Python визначити, чи є каталог, що записується для користувача, що виконує сценарій? Оскільки це, ймовірно, передбачає використання модуля os, я повинен зазначити, що я запускаю його в середовищі * nix.
Відповіді:
Хоча те, що запропонував Крістоф, є більш пітонічним рішенням, модуль os має функцію os.access для перевірки доступу:
os.access('/path/to/folder', os.W_OK)
# W_OK - це для написання, R_OK - для читання тощо.
os.access()
- це перевірка за допомогою реальних UID та GID, а не ефективних . Це може спричинити дивацтво в середовищі SUID / SGID. ("але сценарій запускає встановлений корінь, чому він не може записати у файл?")
os.access(dirpath, os.W_OK | os.X_OK)
повертає True, навіть якщо у мене немає доступу для запису
Це може здатися дивним, але загальна ідіома Python - це
Простіше просити пробачення, ніж дозволу
Слідуючи цій ідіомі, можна сказати:
Спробуйте записатись у відповідний каталог і введіть помилку, якщо у вас немає дозволу на це.
except: pass
- таким чином ви завжди можете бути оптимістичними та думати над собою. / сарказм вимкнено. Тепер чому я хотів би, наприклад, спробувати написати щось у кожен каталог моєї файлової системи, створити список записуваних місць?
Моє рішення за допомогою 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
Оновлення: Після повторного тестування коду в Windows я бачу, що справді існує проблема при використанні tempfile , див. Issue22107: модуль tempfile неправильно тлумачить помилку в доступі, заборонений у Windows . У випадку, коли не записується каталог, код зависає кілька секунд і, нарешті, кидає an IOError: [Errno 17] No usable temporary file name found
. Можливо, це спостерігав користувач2171842? На жаль, проблема наразі не вирішена, щоб вирішити цю проблему, помилка також повинна бути зрозуміла:
except (OSError, IOError) as e:
if e.errno == errno.EACCES or e.errno == errno.EEXIST: # 13, 17
Затримка, безумовно, все ще присутня в цих випадках.
tempfile
. він працює лише тоді, коли немає OSError
сенсу, що він має дозвіл на запис / видалення. в іншому випадку це не буде, return False
тому що помилка не повертається, і сценарій не буде продовжувати виконувати або виходити. нічого не повертається. він просто застряг у цій лінії. однак, створення тимчасового файлу, такого як відповідь khattam, працює як тоді, коли дозвіл дозволено чи відмовлено. допомогти?
Натрапив на цю нитку, шукаючи приклади для когось. Перший результат в Google, привіт!
Люди говорять про пітонічний спосіб зробити це в цій темі, але не прості приклади коду? Ось для всіх, хто натрапляє на:
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")
Це намагається відкрити файл файлових файлів для запису і виходить із помилкою, якщо вказаний файл не може бути записаний на: Це читати набагато простіше, і це набагато кращий спосіб зробити це, аніж робити попередні перевірки на шляху файлу чи каталогу , оскільки це уникає перегонів; випадки, коли файл стає незаписуваним між часом запуску попередньої перевірки та коли ви насправді намагаєтесь записати у файл.
Якщо ви дбаєте лише про файлові тарілки, os.access(path, os.W_OK)
виконайте те, що вам потрібно. Якщо ви замість цього хочете дізнатися, чи можете ви писати в каталог, open()
тестовий файл для написання (він не повинен існувати раніше), виберіть і вивчіть будь-який IOError
, а потім очистіть тестовий файл.
Загалом, щоб уникнути атак TOCTOU (лише проблема, якщо ваш скрипт працює з підвищеними привілеями - suid або cgi тощо), вам не слід довіряти цим тестам заздалегідь, але кидайте приватні особи, робіть open()
і очікуйте то IOError
.
Перевірте біти режиму:
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)
)
Ось що я створив на основі відповіді 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"
if os.access(path_to_folder, os.W_OK) is not True:
print("Folder not writable")
else :
print("Folder writable")
Більше інформації про доступ можна знайти тут
Я зіткнувся з цією ж потребою, додаючи аргумент через 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 ~
Я повернувся назад і додав print opts.dir до кінця, і все, здається, функціонує як потрібно.
Якщо вам потрібно перевірити дозвіл іншого користувача (так, я розумію, що це суперечить питанню, але може бути корисним для когось), ви можете зробити це через pwd
модуль, і біт режиму каталогу.
Відмова від відповідальності - не працює в Windows, оскільки не використовує модель дозволів POSIX (а pwd
модуль там недоступний), наприклад - рішення лише для * nix систем.
Зверніть увагу, що в каталозі повинні бути встановлені всі 3 біти - Read, Write та eXecute.
Гаразд, R не є абсолютним обов'язком, але без нього ви не можете перелічити записи в каталозі (тому ви повинні знати їх назви). Виконання з іншого боку абсолютно необхідне - без цього користувач не може прочитати вставки файлу; тож навіть маючи W, без X-файлів неможливо створити чи змінити. Більш детальне пояснення за цим посиланням.
Нарешті, stat
модулі доступні в модулі, їх описи знаходяться в людині inode (7) .
Приклад коду, як перевірити:
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