名古屋出身ソフトウェアエンジニアのブログ

Windows では読み取り専用属性が付いているファイルは本来消せない

公開:
更新:

Windows を長年使い続けてきて今更知ったことなのですが、Windows ではファイルに読み取り専用 (Read-only) 属性が付いていると削除時に影響を及ぼします。エクスプローラーでは、ファイルに読み取り専用フラグが付いていても確認なしに削除できますが、本来は読み取り専用属性を解除してからでないと消せません1

エクスプローラーは解除を暗黙に行うので、今まで全く気付きませんでした。ちなみに、del コマンドにも、読み取り専用属性を外して削除するためのスイッチ /f が存在します。

エクスプローラーでもうっかり消せなくする

読み取り専用属性と NTFS ACL を組み合わせることで、強固な誤削除防止策を取ることができます。

ファイルへの属性の書き込みを権を拒否することにより、読み取り専用属性を外すことができなくなるので、エクスプローラーのメニューからでは削除ができなくなります(同一ドライブ内での移動は可)。

REM 書き込み不可かつ削除禁止(読み取り専用属性は先に付けておく)
icacls READONLY_FILE.txt /L /deny "Everyone:(WD,AD,WEA,WA,DE)"

ファイルの削除権 DE を拒否するだけで削除ができなくなりそうなものですが、フォルダのコンテンツに対する削除権も含めて拒否しない限り依然削除可能なので、ファイル単位で削除拒否を設定するためには、このような回りくどい方法が必要です2

余談: Python 標準ライブラリ shutil のドキュメント

Python の shutil のドキュメントには、ディレクトリツリーを丸ごと削除する関数について、読み取り専用属性を必要に応じて解除する例が記載されています。

This example shows how to remove a directory tree on Windows where some of the files have their read-only bit set. It uses the onexc callback to clear the readonly bit and reattempt the remove. Any subsequent failure will propagate.

import os, stat
import shutil

def remove_readonly(func, path, _):
  "Clear the readonly bit and reattempt the removal"
  os.chmod(path, stat.S_IWRITE)
  func(path)

shutil.rmtree(directory, onexc=remove_readonly)

https://docs.python.org/ja/3/library/shutil.html#rmtree-example


  1. DeleteFile function (winbase.h) ↩︎

  2. ファイルの DE を拒否しても削除できるのはかなり直観に反する挙動であり、バグではないのかとすら思えます。 ↩︎