Jaki byłby najlepszy sposób w Pythonie na określenie, czy katalog jest zapisywalny dla użytkownika wykonującego skrypt? Ponieważ prawdopodobnie będzie to wymagało użycia modułu os, powinienem wspomnieć, że uruchamiam go w środowisku * nix.
Jaki byłby najlepszy sposób w Pythonie na określenie, czy katalog jest zapisywalny dla użytkownika wykonującego skrypt? Ponieważ prawdopodobnie będzie to wymagało użycia modułu os, powinienem wspomnieć, że uruchamiam go w środowisku * nix.
Odpowiedzi:
Chociaż to, co zasugerował Christophe, jest rozwiązaniem bardziej Pythonowym, moduł os ma funkcję os.access do sprawdzania dostępu:
os.access('/path/to/folder', os.W_OK)
# W_OK służy do pisania, R_OK do czytania itp.
os.access()
jest to, że sprawdza przy użyciu prawdziwego UID i GID, a nie skutecznych . Może to powodować dziwności w środowiskach SUID / SGID. („ale skrypt uruchamia setuid root, dlaczego nie może zapisywać do pliku?”)
os.access(dirpath, os.W_OK | os.X_OK)
zwraca True, nawet jeśli nie mam dostępu do zapisu.
Sugerowanie tego może wydawać się dziwne, ale powszechnym idiomem w Pythonie jest
Łatwiej jest prosić o przebaczenie niż o pozwolenie
Idąc za tym idiomem, można by powiedzieć:
Spróbuj napisać do odpowiedniego katalogu i wyłap błąd, jeśli nie masz do tego uprawnień.
except: pass
- w ten sposób zawsze możesz być optymistą i dobrze o sobie myśleć. / sarkazm wyłączony. Dlaczego miałbym chcieć, na przykład, spróbować zapisać coś w każdym katalogu w moim systemie plików, aby utworzyć listę zapisywalnych lokalizacji?
Moje rozwiązanie z wykorzystaniem tempfile
modułu:
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
Aktualizacja: po ponownym przetestowaniu kodu w systemie Windows widzę, że rzeczywiście występuje problem podczas używania tam pliku tymczasowego, zobacz problem22107: moduł tymczasowego pliku błędnie interpretuje błąd odmowy dostępu w systemie Windows . W przypadku katalogu, którego nie można zapisać, kod zawiesza się na kilka sekund, a na koniec generuje plik IOError: [Errno 17] No usable temporary file name found
. Może to właśnie obserwował użytkownik2171842? Niestety problem nie został na razie rozwiązany, więc aby sobie z tym poradzić, należy również wyłapać błąd:
except (OSError, IOError) as e:
if e.errno == errno.EACCES or e.errno == errno.EEXIST: # 13, 17
Oczywiście w takich przypadkach opóźnienie nadal występuje.
tempfile
. działa tylko wtedy, gdy nie ma OSError
znaczenia, że ma uprawnienia do zapisu / usuwania. w przeciwnym razie tak się nie stanie, return False
ponieważ nie zostanie zwrócony żaden błąd, a skrypt nie będzie kontynuował wykonywania ani kończy pracy. nic nie jest zwracane. po prostu utknął na tej linii. Jednak utworzenie pliku nie tymczasowego, takiego jak odpowiedź khattam, działa zarówno wtedy, gdy zezwolenie jest dozwolone, jak i nie. Wsparcie?
Natknąłem się na ten wątek, szukając przykładów dla kogoś. Pierwszy wynik w Google, gratulacje!
W tym wątku ludzie mówią o sposobie robienia tego w Pythonie, ale nie ma prostych przykładów kodu? Proszę bardzo, dla każdego, kto się potknie:
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")
To próbuje otworzyć uchwyt pliku do zapisu i kończy pracę z błędem, jeśli określony plik nie może zostać zapisany: Jest to o wiele łatwiejsze do odczytania i jest o wiele lepszym sposobem zrobienia tego niż wykonywanie wstępnych kontroli ścieżki pliku lub katalogu ponieważ unika warunków wyścigu; przypadki, w których plik staje się niemożliwy do zapisu między momentem uruchomienia kontroli wstępnej a faktyczną próbą zapisu do pliku.
Jeśli zależy Ci tylko na uprawnieniach do pliku, os.access(path, os.W_OK)
powinieneś zrobić to, o co prosisz. Jeśli natomiast chcemy wiedzieć, czy można zapisywać do katalogu open()
plik testowy na piśmie (nie powinien istnieć wcześniej), złapać i zbadać każdy IOError
, i oczyścić plik testowy później.
Mówiąc bardziej ogólnie, aby uniknąć ataków TOCTOU (tylko problem, jeśli twój skrypt działa z podwyższonymi uprawnieniami - suid lub cgi lub coś podobnego), nie powinieneś naprawdę ufać tym testom z wyprzedzeniem, ale porzuć uprawnienia, zrób open()
i oczekuj the IOError
.
Sprawdź bity trybu:
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)
)
Oto coś, co stworzyłem na podstawie odpowiedzi ChristopheDa:
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")
więcej informacji o dostępie można znaleźć tutaj
Napotkałem tę samą potrzebę, dodając argument za pośrednictwem argparse. Wbudowany type=FileType('w')
nie działałby dla mnie, ponieważ szukałem katalogu. Skończyło się na napisaniu własnej metody rozwiązania mojego problemu. Oto wynik z argparse snippet.
#! /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()
Z tego wynika:
$ 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 ~
Wróciłem i na końcu dodałem print opts.dir i wszystko wydaje się działać zgodnie z oczekiwaniami.
Jeśli chcesz sprawdzić uprawnienia innego użytkownika (tak, zdaję sobie sprawę, że przeczy to pytaniu, ale może się komuś przydać), możesz to zrobić przez pwd
moduł i bity trybu katalogu.
Disclaimer - nie działa na Windows, ponieważ nie korzysta z modelu uprawnień POSIX (a pwd
moduł nie jest tam dostępny), np. - rozwiązanie tylko dla systemów * nix.
Zauważ, że katalog musi mieć ustawione wszystkie 3 bity - odczyt, zapis i eXecute.
Ok, R nie jest absolutną koniecznością, ale bez niego nie możesz wyświetlić listy wpisów w katalogu (więc musisz znać ich nazwy). Z drugiej strony wykonanie jest absolutnie potrzebne - bez niego użytkownik nie może odczytać i-węzłów pliku; więc nawet mając W, bez plików X nie można tworzyć ani modyfikować. Bardziej szczegółowe wyjaśnienie pod tym linkiem.
Wreszcie tryby są dostępne w stat
module, ich opisy znajdują się w inode (7) man .
Przykładowy kod jak sprawdzić:
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