Cách tốt nhất trong Python để xác định xem một thư mục có thể ghi được cho người dùng thực thi tập lệnh hay không? Vì điều này có thể sẽ liên quan đến việc sử dụng mô-đun hệ điều hành, tôi nên đề cập rằng tôi đang chạy nó trong môi trường * nix.
Cách tốt nhất trong Python để xác định xem một thư mục có thể ghi được cho người dùng thực thi tập lệnh hay không? Vì điều này có thể sẽ liên quan đến việc sử dụng mô-đun hệ điều hành, tôi nên đề cập rằng tôi đang chạy nó trong môi trường * nix.
Câu trả lời:
Mặc dù những gì Christophe đề xuất là một giải pháp Pythonic hơn, mô-đun os có chức năng os.access để kiểm tra quyền truy cập:
os.access('/path/to/folder', os.W_OK)
# W_OK để viết, R_OK để đọc, v.v.
os.access()
nó là nó kiểm tra bằng cách sử dụng UID thực và GID chứ không phải những cái hiệu quả . Điều này có thể gây ra sự kỳ lạ trong môi trường SUID / SGID. ('nhưng tập lệnh chạy setuid root, tại sao nó không thể ghi vào tệp?')
os.access(dirpath, os.W_OK | os.X_OK)
trả về True ngay cả khi tôi không có quyền ghi.
Có vẻ lạ khi đề xuất điều này, nhưng một thành ngữ Python phổ biến là
Xin tha thứ thì dễ hơn xin phép
Sau thành ngữ đó, người ta có thể nói:
Hãy thử ghi vào thư mục được đề cập và bắt lỗi nếu bạn không có quyền làm như vậy.
except: pass
- theo cách này, bạn có thể luôn lạc quan và nghĩ về bản thân. / mỉa mai tắt. Bây giờ tại sao tôi lại muốn, chẳng hạn như cố gắng ghi một cái gì đó vào mọi thư mục trong hệ thống tệp của tôi, để tạo ra một danh sách các vị trí có thể ghi?
Giải pháp của tôi bằng cách sử dụng tempfile
mô-đun:
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
Cập nhật: Sau khi kiểm tra lại mã trên Windows, tôi thấy rằng thực sự có sự cố khi sử dụng tệp tạm thời ở đó, hãy xem vấn đề22107: mô-đun tempfile hiểu sai lỗi bị từ chối truy cập trên Windows . Trong trường hợp thư mục không thể ghi, mã bị treo trong vài giây và cuối cùng ném một IOError: [Errno 17] No usable temporary file name found
. Có thể đây là những gì người dùng2171842 đã quan sát? Rất tiếc, sự cố hiện vẫn chưa được giải quyết vì vậy để xử lý điều này, lỗi cũng cần được khắc phục:
except (OSError, IOError) as e:
if e.errno == errno.EACCES or e.errno == errno.EEXIST: # 13, 17
Sự chậm trễ tất nhiên vẫn còn trong những trường hợp này.
tempfile
. nó chỉ hoạt động khi không có OSError
nghĩa là nó có quyền ghi / xóa. nếu không, nó sẽ không return False
vì không có lỗi nào được trả lại và tập lệnh sẽ không tiếp tục thực thi hoặc thoát. không có gì được trả lại. nó chỉ bị mắc kẹt ở dòng đó. tuy nhiên, việc tạo tệp không phải tạm thời như câu trả lời của khattam hoạt động cả khi quyền được phép hoặc bị từ chối. Cứu giúp?
Tình cờ tìm thấy chủ đề này để tìm kiếm ví dụ cho ai đó. Kết quả đầu tiên trên Google, xin chúc mừng!
Mọi người nói về cách thức hoạt động của Pythonic trong chủ đề này, nhưng không có ví dụ mã đơn giản nào? Của bạn đây, cho bất kỳ ai khác tình cờ:
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")
Thao tác này cố gắng mở một trình xử lý tệp để ghi và thoát với lỗi nếu tệp được chỉ định không thể được ghi vào: Cách này dễ đọc hơn nhiều và là cách tốt hơn nhiều so với việc kiểm tra trước trên đường dẫn tệp hoặc thư mục , vì nó tránh được các điều kiện về chủng tộc; các trường hợp mà tệp trở nên không thể ghi được giữa thời gian bạn chạy kiểm tra trước và khi bạn thực sự cố gắng ghi vào tệp.
Nếu bạn chỉ quan tâm đến quyền của tệp, os.access(path, os.W_OK)
hãy làm những gì bạn yêu cầu. Thay vào đó, nếu bạn muốn biết liệu bạn có thể ghi vào thư mục, open()
một tệp thử nghiệm để ghi (nó không nên tồn tại trước đó), hãy nắm bắt và kiểm tra bất kỳ IOError
tệp nào và xóa tệp kiểm tra sau đó.
Nói chung, để tránh các cuộc tấn công TOCTOU (chỉ có vấn đề nếu tập lệnh của bạn chạy với các đặc quyền nâng cao - suid hoặc cgi hoặc tương tự), bạn không nên thực sự tin tưởng vào các thử nghiệm trước thời hạn này, nhưng hãy thả priv, thực hiện open()
và mong đợi cái IOError
.
Kiểm tra các bit chế độ:
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)
)
Đây là thứ mà tôi đã tạo dựa trên câu trả lời của 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")
có thể tìm thấy thêm thông tin về quyền truy cập ở đây
Tôi gặp phải nhu cầu tương tự này trong khi thêm một đối số qua argparse. Phần mềm tích hợp type=FileType('w')
sẽ không hoạt động đối với tôi khi tôi đang tìm kiếm một thư mục. Tôi đã viết ra phương pháp của riêng mình để giải quyết vấn đề của tôi. Đây là kết quả với đoạn mã 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()
Điều đó dẫn đến những điều sau:
$ 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 ~
Tôi quay lại và thêm print opts.dir vào cuối và mọi thứ dường như hoạt động như mong muốn.
Nếu bạn cần kiểm tra sự cho phép của người dùng khác (vâng, tôi nhận thấy điều này mâu thuẫn với câu hỏi, nhưng có thể hữu ích cho ai đó), bạn có thể làm điều đó thông qua pwd
mô-đun và các bit chế độ của thư mục.
Tuyên bố từ chối trách nhiệm - không hoạt động trên Windows, vì nó không sử dụng mô hình quyền POSIX (và pwd
mô-đun không có sẵn ở đó), ví dụ - giải pháp chỉ dành cho hệ thống * nix.
Lưu ý rằng một thư mục phải có tất cả 3 bit được thiết lập - Đọc, Ghi và eXecute.
Ok, R không phải là một bắt buộc tuyệt đối, nhưng nếu bạn không thể liệt kê các mục trong thư mục (vì vậy bạn phải biết tên của chúng). Mặt khác, thực thi là hoàn toàn cần thiết - nếu người dùng không thể đọc các inodes của tệp; vì vậy ngay cả khi có W, không có X các tệp không thể được tạo hoặc sửa đổi. Giải thích chi tiết hơn tại liên kết này.
Cuối cùng, các chế độ có sẵn trong stat
mô-đun, mô tả của chúng ở inode (7) man .
Mã mẫu cách kiểm tra:
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