2013-01-29 20 views
20

Khi xác định xem tệp có tồn tại hay không, cách sử dụng câu lệnh thử tránh "điều kiện chủng tộc" như thế nào?Làm thế nào để sử dụng câu lệnh thử tránh tình trạng chạy đua?

Tôi đang yêu cầu vì một bản cập nhật cao answer (cập nhật: đã bị xóa) dường như ngụ ý rằng việc sử dụng os.path.exists() tạo cơ hội không tồn tại nếu không.

Các ví dụ đưa ra là:

try: 
    with open(filename): pass 
except IOError: 
    print 'Oh dear.' 

Nhưng tôi không hiểu làm thế nào mà tránh được tình trạng đua so với:

if not os.path.exists(filename): 
    print 'Oh dear.' 

Làm thế nào để gọi os.path.exists(filename) cho phép kẻ tấn công để làm điều gì đó với tệp mà họ chưa thể làm?

Trả lời

24

Các điều kiện chủng tộc là , tất nhiên, giữa chương trình của bạn và một số mã khác hoạt động trên tệp (điều kiện chủng tộc luôn yêu cầu ít nhất hai quy trình hoặc luồng song song, hãy xem this để biết chi tiết). Điều đó có nghĩa sử dụng open() thay vì exists() thực sự có thể giúp chỉ trong hai tình huống:

  1. Bạn kiểm tra cho sự tồn tại của một tập tin được tạo ra hoặc bị xóa bởi một số quá trình nền (tuy nhiên, nếu bạn chạy bên trong một máy chủ web, mà thường có nghĩa là có nhiều bản sao quá trình của bạn chạy song song với quá trình yêu cầu HTTP, do đó, đối với điều kiện cuộc đua ứng dụng web có thể xảy ra ngay cả khi không có chương trình nào khác).
  2. Có thể có một số chương trình độc hại đang chạy đang cố gắng làm hỏng mã của bạn bằng cách hủy tệp ngay khi bạn mong đợi tệp tồn tại.

exists() chỉ thực hiện một lần kiểm tra. Nếu tệp tồn tại, nó có thể bị xóa một micro giây sau exists() trả về True. Nếu tệp vắng mặt, tệp có thể được tạo ngay lập tức.

Tuy nhiên, open() không chỉ kiểm tra sự tồn tại tệp, mà còn mở tệp (và thực hiện hai hành động này một cách nguyên tử, vì vậy không có gì có thể xảy ra giữa séc và phần mở). Thông thường các tập tin không thể bị xóa trong khi chúng được mở bởi ai đó. Điều đó có nghĩa là bên trong with bạn có thể hoàn toàn chắc chắn: tệp thực sự tồn tại ngay bây giờ vì tệp đang mở. Mặc dù nó chỉ đúng trong with và tệp vẫn có thể bị xóa ngay sau khi thoát khỏi khối with, đặt mã cần tệp tồn tại bên trong with đảm bảo rằng mã sẽ không bị lỗi.

9

Dưới đây là một ví dụ về việc sử dụng:

try: 
    with open('filename') as f: 
     do_stuff_that_depends_on_the_existence_of_the_file(f) 
except IOError as e: 
    print 'Trouble opening file' 

Nếu bạn đang mở tập tin với bất kỳ truy cập ở tất cả, sau đó hệ điều hành sẽ đảm bảo rằng các tập tin tồn tại, nếu không nó sẽ thất bại với một lỗi. Nếu quyền truy cập là độc quyền, bất kỳ quá trình tranh chấp nào khác cho tệp sẽ bị bạn chặn hoặc chặn bạn.

try chỉ là một cách để phát hiện lỗi hoặc thành công của hành động mở tệp, vì tệp I/O API bằng Python thường không có mã trả về (ngoại lệ được sử dụng thay thế). Vì vậy, để thực sự trả lời câu hỏi của bạn, nó không phải là try tránh điều kiện chủng tộc, đó là open. Về cơ bản nó giống nhau trong C (dựa trên Python), nhưng không có ngoại lệ. Đọc this để biết thêm thông tin.

Lưu ý rằng bạn có thể muốn thực thi mã phụ thuộc vào quyền truy cập vào tệp bên trong khối thử. Khi bạn đóng tệp, sự tồn tại của nó sẽ không còn được đảm bảo nữa.

Gọi os.path.exists chỉ cung cấp ảnh chụp nhanh tại một thời điểm khi tệp có thể tồn tại hoặc không tồn tại và bạn không biết gì về sự tồn tại của tệp khi trả lại os.path.exists. Mã không hợp lệ hoặc logic không mong muốn có thể xóa hoặc thay đổi tệp khi bạn không mong đợi. Cũng giống như quay đầu để kiểm tra xem con đường có rõ ràng không trước khi lái xe vào đó. Một khi bạn quay đầu lại, bạn không có gì ngoài việc đoán về những gì đang diễn ra mà bạn không còn tìm kiếm nữa. Giữ tập tin mở đảm bảo một trạng thái nhất quán mở rộng, một cái gì đó không thể (cho tốt hay xấu) khi lái xe. :)

Đề xuất kiểm tra xem tệp không tồn tại thay vì sử dụng try/open vẫn không đủ do bản chất chụp nhanh os.path.exists. Thật không may tôi biết không có cách nào để ngăn chặn các tập tin được tạo ra trong một thư mục trong tất cả các trường hợp, vì vậy tôi nghĩ rằng tốt nhất là kiểm tra sự tồn tại tích cực của một tập tin, thay vì sự vắng mặt của nó.

0

Tôi nghĩ rằng những gì bạn đang yêu cầu là điều kiện chủng tộc đặc biệt nơi:

  1. tập tin được mở
  2. bối cảnh được bật và các tập tin bị xóa
  3. bối cảnh được bật trở lại và hoạt động tập tin đang cố gắng trên tệp "đã mở"

Cách bạn "được bảo vệ" trong trường hợp này là đặt tất cả mã xử lý tệp trong khối try, nếu tại bất kỳ thời điểm nào tệp trở thành không thể truy cập/hỏng hoạt động tập tin của bạn sẽ có thể thất bại "gracefully" thông qua khối catch.

Lưu ý tất nhiên hệ điều hành hiện đại này không thể xảy ra dù sao, khi một tập tin được "xóa" các xóa sẽ không diễn ra cho đến khi tất cả các tay nắm mở cửa vào các tập tin được giải quyết (phát hành)

+1

@downvoter - lý luận? Có vấn đề gì không? – Mike

Các vấn đề liên quan