Python'da komut dosyasını çalıştıran kullanıcı için bir dizinin yazılabilir olup olmadığını belirlemenin en iyi yolu nedir? Bu muhtemelen os modülünü kullanmayı içereceğinden, onu bir * nix ortamında çalıştırdığımı söylemeliyim.
Python'da komut dosyasını çalıştıran kullanıcı için bir dizinin yazılabilir olup olmadığını belirlemenin en iyi yolu nedir? Bu muhtemelen os modülünü kullanmayı içereceğinden, onu bir * nix ortamında çalıştırdığımı söylemeliyim.
Yanıtlar:
Christophe'un önerdiği daha Pythonic bir çözüm olsa da, işletim sistemi modülü, erişimi kontrol etmek için os.access işlevine sahiptir:
os.access('/path/to/folder', os.W_OK)
# W_OK yazmak için, R_OK okumak için vb.
os.access()
kullanarak kontrol etmektir . Bu SUID / SGID ortamlarında tuhaflığa neden olabilir. ('ama betik setuid root çalıştırıyor, neden dosyaya yazamıyor?')
os.access(dirpath, os.W_OK | os.X_OK)
Yazma erişimim olmasa bile True döndürüyor.
Bunu önermek tuhaf görünebilir, ancak yaygın bir Python deyimi
Af dilemek izin istemekten daha kolaydır
Bu deyimin ardından şöyle diyebiliriz:
Söz konusu dizine yazmayı deneyin ve izniniz yoksa hatayı yakalayın.
except: pass
- bu şekilde her zaman iyimser olabilir ve kendinizi çok iyi düşünebilirsiniz. / alaycı. Şimdi neden yazılabilir konumların bir listesini oluşturmak için dosya sistemimdeki her dizine bir şeyler yazmaya çalışayım?
tempfile
Modülü kullanan çözümüm :
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
Güncelleme: Kodu Windows'ta tekrar test ettikten sonra, orada geçici dosyayı kullanırken gerçekten bir sorun olduğunu görüyorum, bkz. İssue22107: tempfile modülü, Windows'ta erişim reddedildi hatasını yanlış yorumluyor . Yazılamayan bir dizin olması durumunda, kod birkaç saniye askıda kalır ve sonunda bir IOError: [Errno 17] No usable temporary file name found
. Belki de user2171842'nin gözlemlediği budur? Maalesef sorun şimdilik çözülmedi, bu nedenle bunun üstesinden gelmek için hatanın da yakalanması gerekiyor:
except (OSError, IOError) as e:
if e.errno == errno.EACCES or e.errno == errno.EEXIST: # 13, 17
Bu durumlarda gecikme tabii ki hala mevcuttur.
tempfile
. sadece OSError
yazma / silme iznine sahip olmadığı zaman çalışır . aksi halde return False
hata döndürülmediğinden ve betik çalışmaya veya çıkmaya devam etmeyeceğinden dönmez. hiçbir şey iade edilmez. sadece o çizgide kaldı. ancak, khattam'ın yanıtı gibi geçici olmayan bir dosya oluşturmak hem izin verildiğinde hem de reddedildiğinde işe yarar. Yardım?
Birisi için örnekler ararken bu ileti dizisine rastladım. Google'daki ilk sonuç, tebrikler!
İnsanlar bu yazıda bunu yapmanın Pythonic yolu hakkında konuşuyorlar, ancak basit kod örnekleri yok mu? Tökezleyen herkes için işte buyrun:
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")
Bu, yazma için bir dosya tanıtıcısı açmaya çalışır ve belirtilen dosya yazılamazsa bir hatayla çıkar: Bu, okunması çok daha kolaydır ve dosya yolunda veya dizinde ön kontroller yapmaktan çok daha iyi bir yöntemdir. yarış koşullarından kaçındığı için; ön denetimi çalıştırdığınız zaman ile gerçekten dosyaya yazmaya çalıştığınız zaman arasında dosyanın yazılamaz hale geldiği durumlar.
Yalnızca dosya izinleriyle ilgileniyorsanız, os.access(path, os.W_OK)
istediğinizi yapmalısınız. Bunun yerine dizine yazıp yazamayacağınızı öğrenmek istiyorsanız , yazmak için open()
bir test dosyası (önceden mevcut olmamalıdır), herhangi birini yakalayıp inceleyin IOError
ve daha sonra test dosyasını temizleyin.
Daha genel olarak, TOCTOU saldırılarından kaçınmak için (yalnızca betiğiniz yükseltilmiş ayrıcalıklarla çalışıyorsa bir sorundur - suid veya cgi veya benzeri), bu vaktinden önce yapılan testlere gerçekten güvenmemeli, ayrıcalıkları bırakmalı, yapmalı open()
ve beklemelisiniz IOError
.
Mod bitlerini kontrol edin:
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)
)
İşte ChristopheD'nin cevabına göre oluşturduğum bir şey:
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")
erişim hakkında daha fazla bilgiyi burada bulabilirsiniz
Argparse aracılığıyla bir argüman eklerken de aynı ihtiyaca rastladım. type=FileType('w')
Bir dizin aradığım için yerleşik benim için işe yaramazdı. Sorunumu çözmek için kendi yöntemimi yazdım. İşte argparse snippet'inin sonucu.
#! /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()
Bu, aşağıdakilerle sonuçlanır:
$ 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 ~
Geri döndüm ve sonuna print opts.dir ekledim ve her şey istendiği gibi çalışıyor gibi görünüyor.
Başka bir kullanıcının iznini kontrol etmeniz gerekiyorsa (evet, bunun soruyla çeliştiğini anlıyorum, ancak birisi için kullanışlı olabilir), bunu şu adresten yapabilirsiniz:pwd
modül ve dizinin mod bitleri aracılığıyla yapabilirsiniz.
Sorumluluk Reddi - POSIX izin modelini kullanmadığı için (ve pwd
modül orada bulunmadığından) Windows'ta çalışmaz , örneğin - sadece * nix sistemleri için çözüm.
Bir dizinin 3 bitin de ayarlanması gerektiğini unutmayın - Okuma, Yazma ve eXecute.
Tamam, R mutlak bir zorunluluk değildir, ancak bu olmadan dizindeki girişleri listeleyemezsiniz (bu yüzden isimlerini bilmeniz gerekir). Öte yandan, yürütme kesinlikle gereklidir - kullanıcı dosyanın düğümlerini okuyamaz; bu nedenle W'ye sahip olsanız bile, X dosyaları oluşturulamaz veya değiştirilemez. Bu bağlantıda daha ayrıntılı açıklama.
Son olarak, modlar stat
modülde mevcuttur , açıklamaları inode (7) man içindedir .
Örnek kod nasıl kontrol edilir:
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